Support unions in rustdoc
This commit is contained in:
parent
641d8e9e4c
commit
6792bd99fe
@ -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 @@ impl Item {
|
||||
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 @@ impl Clean<Item> for doctree::Module {
|
||||
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 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
|
||||
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 @@ impl Clean<Item> for doctree::Struct {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl 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 @@ pub trait DocFolder : Sized {
|
||||
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 @@ impl<'a> From<&'a clean::Item> for 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 @@ impl ItemType {
|
||||
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 @@ impl DocFolder for Cache {
|
||||
// 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 @@ impl DocFolder for Cache {
|
||||
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 @@ impl DocFolder for Cache {
|
||||
// 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 @@ impl<'a> fmt::Display for Item<'a> {
|
||||
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 @@ impl<'a> fmt::Display for Item<'a> {
|
||||
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 item_module(w: &mut fmt::Formatter, cx: &Context,
|
||||
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 item_module(w: &mut fmt::Formatter, cx: &Context,
|
||||
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 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
||||
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 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
|
||||
Def::ForeignMod(did) |
|
||||
Def::Trait(did) |
|
||||
Def::Struct(did) |
|
||||
Def::Union(did) |
|
||||
Def::Enum(did) |
|
||||
Def::TyAlias(did) |
|
||||
Def::Fn(did) |
|
||||
|
20
src/test/rustdoc/union.rs
Normal file
20
src/test/rustdoc/union.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user