提交 6792bd99 编写于 作者: V Vadim Petrochenkov

Support unions in rustdoc

上级 641d8e9e
......@@ -88,6 +88,11 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
ret.extend(build_impls(cx, tcx, did));
clean::StructItem(build_struct(cx, tcx, did))
}
Def::Union(did) => {
record_extern_fqn(cx, did, clean::TypeUnion);
ret.extend(build_impls(cx, tcx, did));
clean::UnionItem(build_union(cx, tcx, did))
}
Def::TyAlias(did) => {
record_extern_fqn(cx, did, clean::TypeTypedef);
ret.extend(build_impls(cx, tcx, did));
......@@ -214,6 +219,20 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
did: DefId) -> clean::Union {
let t = tcx.lookup_item_type(did);
let predicates = tcx.lookup_predicates(did);
let variant = tcx.lookup_adt_def(did).struct_variant();
clean::Union {
struct_type: doctree::Plain,
generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
fields: variant.fields.clean(cx),
fields_stripped: false,
}
}
fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
did: DefId) -> clean::ItemEnum {
let t = tcx.lookup_item_type(did);
......
......@@ -321,6 +321,7 @@ pub fn is_stripped(&self) -> bool {
pub fn has_stripped_fields(&self) -> Option<bool> {
match self.inner {
StructItem(ref _struct) => Some(_struct.fields_stripped),
UnionItem(ref union) => Some(union.fields_stripped),
VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => {
Some(vstruct.fields_stripped)
},
......@@ -351,6 +352,7 @@ pub enum ItemEnum {
ExternCrateItem(String, Option<String>),
ImportItem(Import),
StructItem(Struct),
UnionItem(Union),
EnumItem(Enum),
FunctionItem(Function),
ModuleItem(Module),
......@@ -414,6 +416,7 @@ fn clean(&self, cx: &DocContext) -> Item {
items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
items.extend(self.structs.iter().map(|x| x.clean(cx)));
items.extend(self.unions.iter().map(|x| x.clean(cx)));
items.extend(self.enums.iter().map(|x| x.clean(cx)));
items.extend(self.fns.iter().map(|x| x.clean(cx)));
items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
......@@ -1464,6 +1467,7 @@ pub enum TypeKind {
TypeConst,
TypeStatic,
TypeStruct,
TypeUnion,
TypeTrait,
TypeVariant,
TypeTypedef,
......@@ -1801,12 +1805,13 @@ fn clean(&self, cx: &DocContext) -> Type {
decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
abi: fty.abi,
}),
ty::TyUnion(..) => unimplemented_unions!(),
ty::TyStruct(def, substs) |
ty::TyUnion(def, substs) |
ty::TyEnum(def, substs) => {
let did = def.did;
let kind = match self.sty {
ty::TyStruct(..) => TypeStruct,
ty::TyUnion(..) => TypeUnion,
_ => TypeEnum,
};
inline::record_extern_fqn(cx, did, kind);
......@@ -1929,6 +1934,14 @@ pub struct Struct {
pub fields_stripped: bool,
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Union {
pub struct_type: doctree::StructType,
pub generics: Generics,
pub fields: Vec<Item>,
pub fields_stripped: bool,
}
impl Clean<Item> for doctree::Struct {
fn clean(&self, cx: &DocContext) -> Item {
Item {
......@@ -1949,6 +1962,26 @@ fn clean(&self, cx: &DocContext) -> Item {
}
}
impl Clean<Item> for doctree::Union {
fn clean(&self, cx: &DocContext) -> Item {
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
deprecation: self.depr.clean(cx),
inner: UnionItem(Union {
struct_type: self.struct_type,
generics: self.generics.clean(cx),
fields: self.fields.clean(cx),
fields_stripped: false,
}),
}
}
}
/// This is a more limited form of the standard Struct, different in that
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
......@@ -2748,6 +2781,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
Def::Enum(i) => (i, TypeEnum),
Def::Trait(i) => (i, TypeTrait),
Def::Struct(i) => (i, TypeStruct),
Def::Union(i) => (i, TypeUnion),
Def::Mod(i) => (i, TypeModule),
Def::Static(i, _) => (i, TypeStatic),
Def::Variant(i, _) => (i, TypeEnum),
......
......@@ -30,6 +30,7 @@ pub struct Module {
pub extern_crates: Vec<ExternCrate>,
pub imports: Vec<Import>,
pub structs: Vec<Struct>,
pub unions: Vec<Union>,
pub enums: Vec<Enum>,
pub fns: Vec<Function>,
pub mods: Vec<Module>,
......@@ -62,6 +63,7 @@ pub fn new(name: Option<Name>) -> Module {
extern_crates: Vec::new(),
imports : Vec::new(),
structs : Vec::new(),
unions : Vec::new(),
enums : Vec::new(),
fns : Vec::new(),
mods : Vec::new(),
......@@ -108,6 +110,19 @@ pub struct Struct {
pub whence: Span,
}
pub struct Union {
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub depr: Option<attr::Deprecation>,
pub id: NodeId,
pub struct_type: StructType,
pub name: Name,
pub generics: hir::Generics,
pub attrs: hir::HirVec<ast::Attribute>,
pub fields: hir::HirVec<hir::StructField>,
pub whence: Span,
}
pub struct Enum {
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
......
......@@ -49,6 +49,13 @@ fn fold_inner_recur(&mut self, inner: ItemEnum) -> ItemEnum {
i.fields.iter().any(|f| f.is_stripped());
StructItem(i)
},
UnionItem(mut i) => {
let num_fields = i.fields.len();
i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
i.fields_stripped |= num_fields != i.fields.len() ||
i.fields.iter().any(|f| f.is_stripped());
UnionItem(i)
},
EnumItem(mut i) => {
let num_variants = i.variants.len();
i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
......
......@@ -40,6 +40,7 @@ pub enum ItemType {
AssociatedType = 16,
Constant = 17,
AssociatedConst = 18,
Union = 19,
}
......@@ -62,6 +63,7 @@ fn from(item: &'a clean::Item) -> ItemType {
clean::ExternCrateItem(..) => ItemType::ExternCrate,
clean::ImportItem(..) => ItemType::Import,
clean::StructItem(..) => ItemType::Struct,
clean::UnionItem(..) => ItemType::Union,
clean::EnumItem(..) => ItemType::Enum,
clean::FunctionItem(..) => ItemType::Function,
clean::TypedefItem(..) => ItemType::Typedef,
......@@ -89,6 +91,7 @@ impl From<clean::TypeKind> for ItemType {
fn from(kind: clean::TypeKind) -> ItemType {
match kind {
clean::TypeStruct => ItemType::Struct,
clean::TypeUnion => ItemType::Union,
clean::TypeEnum => ItemType::Enum,
clean::TypeFunction => ItemType::Function,
clean::TypeTrait => ItemType::Trait,
......@@ -108,6 +111,7 @@ pub fn css_class(&self) -> &'static str {
ItemType::ExternCrate => "externcrate",
ItemType::Import => "import",
ItemType::Struct => "struct",
ItemType::Union => "union",
ItemType::Enum => "enum",
ItemType::Function => "fn",
ItemType::Typedef => "type",
......
......@@ -1053,6 +1053,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
// information if present.
Some(&(ref fqp, ItemType::Trait)) |
Some(&(ref fqp, ItemType::Struct)) |
Some(&(ref fqp, ItemType::Union)) |
Some(&(ref fqp, ItemType::Enum)) =>
Some(&fqp[..fqp.len() - 1]),
Some(..) => Some(&*self.stack),
......@@ -1106,7 +1107,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
clean::TypedefItem(..) | clean::TraitItem(..) |
clean::FunctionItem(..) | clean::ModuleItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
clean::ConstantItem(..) | clean::StaticItem(..)
clean::ConstantItem(..) | clean::StaticItem(..) |
clean::UnionItem(..)
if !self.stripped_mod => {
// Reexported items mean that the same id can show up twice
// in the rustdoc ast that we're looking at. We know,
......@@ -1141,7 +1143,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
// Maintain the parent stack
let orig_parent_is_trait_impl = self.parent_is_trait_impl;
let parent_pushed = match item.inner {
clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
clean::TraitItem(..) | clean::EnumItem(..) |
clean::StructItem(..) | clean::UnionItem(..) => {
self.parent_stack.push(item.def_id);
self.parent_is_trait_impl = false;
true
......@@ -1557,6 +1560,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
clean::FunctionItem(..) => write!(fmt, "Function ")?,
clean::TraitItem(..) => write!(fmt, "Trait ")?,
clean::StructItem(..) => write!(fmt, "Struct ")?,
clean::UnionItem(..) => write!(fmt, "Union ")?,
clean::EnumItem(..) => write!(fmt, "Enum ")?,
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
_ => {}
......@@ -1613,6 +1617,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
item_function(fmt, self.cx, self.item, f),
clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s),
clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s),
clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e),
clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t),
clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m),
......@@ -1715,7 +1720,8 @@ fn reorder(ty: ItemType) -> u8 {
ItemType::Trait => 9,
ItemType::Function => 10,
ItemType::Typedef => 12,
_ => 13 + ty as u8,
ItemType::Union => 13,
_ => 14 + ty as u8,
}
}
......@@ -1759,6 +1765,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
ItemType::Import => ("reexports", "Reexports"),
ItemType::Module => ("modules", "Modules"),
ItemType::Struct => ("structs", "Structs"),
ItemType::Union => ("unions", "Unions"),
ItemType::Enum => ("enums", "Enums"),
ItemType::Function => ("functions", "Functions"),
ItemType::Typedef => ("types", "Type Definitions"),
......@@ -2312,6 +2319,40 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
s: &clean::Union) -> fmt::Result {
write!(w, "<pre class='rust union'>")?;
render_attributes(w, it)?;
render_union(w,
it,
Some(&s.generics),
&s.fields,
"",
true)?;
write!(w, "</pre>")?;
document(w, cx, it)?;
let mut fields = s.fields.iter().filter_map(|f| {
match f.inner {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
}
}).peekable();
if fields.peek().is_some() {
write!(w, "<h2 class='fields'>Fields</h2>")?;
for (field, ty) in fields {
write!(w, "<span id='{shortty}.{name}' class='{shortty}'><code>{name}: {ty}</code>
</span><span class='stab {stab}'></span>",
shortty = ItemType::StructField,
stab = field.stability_class(),
name = field.name.as_ref().unwrap(),
ty = ty)?;
document(w, cx, field)?;
}
}
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
e: &clean::Enum) -> fmt::Result {
write!(w, "<pre class='rust enum'>")?;
......@@ -2514,6 +2555,40 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
Ok(())
}
fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
g: Option<&clean::Generics>,
fields: &[clean::Item],
tab: &str,
structhead: bool) -> fmt::Result {
write!(w, "{}{}{}",
VisSpace(&it.visibility),
if structhead {"union "} else {""},
it.name.as_ref().unwrap())?;
if let Some(g) = g {
write!(w, "{}", g)?
}
if let Some(g) = g {
write!(w, "{}", WhereClause(g))?
}
write!(w, " {{\n{}", tab)?;
for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner {
write!(w, " {}{}: {},\n{}",
VisSpace(&field.visibility),
field.name.as_ref().unwrap(),
*ty,
tab)?;
}
}
if it.has_stripped_fields().unwrap() {
write!(w, " // some fields omitted\n{}", tab)?;
}
write!(w, "}}")?;
Ok(())
}
#[derive(Copy, Clone)]
enum AssocItemLink<'a> {
Anchor(Option<&'a str>),
......
......@@ -34,7 +34,8 @@
"primitive",
"associatedtype",
"constant",
"associatedconstant"];
"associatedconstant",
"union"];
// used for special search precedence
var TY_PRIMITIVE = itemTypes.indexOf("primitive");
......
......@@ -113,7 +113,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
clean::TraitItem(..) | clean::FunctionItem(..) |
clean::VariantItem(..) | clean::MethodItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
clean::ConstantItem(..) => {
clean::ConstantItem(..) | clean::UnionItem(..) => {
if i.def_id.is_local() {
if !self.access_levels.is_exported(i.def_id) {
return None;
......
......@@ -108,6 +108,25 @@ pub fn visit_variant_data(&mut self, item: &hir::Item,
}
}
pub fn visit_union_data(&mut self, item: &hir::Item,
name: ast::Name, sd: &hir::VariantData,
generics: &hir::Generics) -> Union {
debug!("Visiting union");
let struct_type = struct_type_from_def(&*sd);
Union {
id: item.id,
struct_type: struct_type,
name: name,
vis: item.vis.clone(),
stab: self.stability(item.id),
depr: self.deprecation(item.id),
attrs: item.attrs.clone(),
generics: generics.clone(),
fields: sd.fields().iter().cloned().collect(),
whence: item.span
}
}
pub fn visit_enum_def(&mut self, it: &hir::Item,
name: ast::Name, def: &hir::EnumDef,
params: &hir::Generics) -> Enum {
......@@ -258,6 +277,7 @@ fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool {
match def {
Def::Trait(did) |
Def::Struct(did) |
Def::Union(did) |
Def::Enum(did) |
Def::TyAlias(did) if !self_is_hidden => {
self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public);
......@@ -365,8 +385,8 @@ pub fn visit_item(&mut self, item: &hir::Item,
om.enums.push(self.visit_enum_def(item, name, ed, gen)),
hir::ItemStruct(ref sd, ref gen) =>
om.structs.push(self.visit_variant_data(item, name, sd, gen)),
hir::ItemUnion(..) =>
unimplemented_unions!(),
hir::ItemUnion(ref sd, ref gen) =>
om.unions.push(self.visit_union_data(item, name, sd, gen)),
hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
constness, abi, gen)),
......
......@@ -73,6 +73,7 @@ pub fn visit_mod(&mut self, did: DefId) {
Def::ForeignMod(did) |
Def::Trait(did) |
Def::Struct(did) |
Def::Union(did) |
Def::Enum(did) |
Def::TyAlias(did) |
Def::Fn(did) |
......
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
// @has union/union.U.html
pub union U {
// @has - //pre "pub a: u8"
pub a: u8,
// @has - //pre "// some fields omitted"
// @!has - //pre "b: u16"
b: u16,
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册