Add trait alias support in rustdoc

This commit is contained in:
Guillaume Gomez 2019-02-05 14:27:09 +01:00
parent 618f5a08a1
commit 74e97f3381
7 changed files with 149 additions and 46 deletions

View File

@ -517,6 +517,7 @@ pub enum ItemEnum {
StaticItem(Static),
ConstantItem(Constant),
TraitItem(Trait),
TraitAliasItem(TraitAlias),
ImplItem(Impl),
/// A method signature only. Used for required methods in traits (ie,
/// non-default-methods).
@ -554,6 +555,7 @@ impl ItemEnum {
ItemEnum::TyMethodItem(ref i) => &i.generics,
ItemEnum::MethodItem(ref i) => &i.generics,
ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
ItemEnum::TraitAliasItem(ref ta) => &ta.generics,
_ => return None,
})
}
@ -603,6 +605,7 @@ impl Clean<Item> for doctree::Module {
items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
items.extend(self.macros.iter().map(|x| x.clean(cx)));
items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
items.extend(self.trait_aliases.iter().map(|x| x.clean(cx)));
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
@ -1885,13 +1888,41 @@ impl Clean<Item> for doctree::Trait {
items: self.items.clean(cx),
generics: self.generics.clean(cx),
bounds: self.bounds.clean(cx),
is_spotlight: is_spotlight,
is_spotlight,
is_auto: self.is_auto.clean(cx),
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct TraitAlias {
pub generics: Generics,
pub bounds: Vec<GenericBound>,
pub is_spotlight: bool,
}
impl Clean<Item> for doctree::TraitAlias {
fn clean(&self, cx: &DocContext) -> Item {
let attrs = self.attrs.clean(cx);
let is_spotlight = attrs.has_doc_flag("spotlight");
Item {
name: Some(self.name.clean(cx)),
attrs,
source: self.whence.clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
deprecation: self.depr.clean(cx),
inner: TraitAliasItem(TraitAlias {
generics: self.generics.clean(cx),
bounds: self.bounds.clean(cx),
is_spotlight,
}),
}
}
}
impl Clean<bool> for hir::IsAuto {
fn clean(&self, _: &DocContext) -> bool {
match *self {
@ -2223,6 +2254,7 @@ pub enum TypeKind {
Macro,
Attr,
Derive,
TraitAlias,
}
pub trait GetDefId {
@ -3819,10 +3851,9 @@ pub fn register_def(cx: &DocContext, def: Def) -> DefId {
MacroKind::Derive => (i, TypeKind::Derive),
MacroKind::ProcMacroStub => unreachable!(),
},
Def::TraitAlias(i) => (i, TypeKind::TraitAlias),
Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
Def::SelfTy(_, Some(impl_def_id)) => {
return impl_def_id
}
Def::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
_ => return def.def_id()
};
if did.is_local() { return did }

View File

@ -38,6 +38,7 @@ pub struct Module {
pub foreigns: Vec<hir::ForeignMod>,
pub macros: Vec<Macro>,
pub proc_macros: Vec<ProcMacro>,
pub trait_aliases: Vec<TraitAlias>,
pub is_crate: bool,
}
@ -53,21 +54,22 @@ impl Module {
where_inner: syntax_pos::DUMMY_SP,
attrs : hir::HirVec::new(),
extern_crates: Vec::new(),
imports : Vec::new(),
structs : Vec::new(),
unions : Vec::new(),
enums : Vec::new(),
fns : Vec::new(),
mods : Vec::new(),
typedefs : Vec::new(),
existentials: Vec::new(),
statics : Vec::new(),
constants : Vec::new(),
traits : Vec::new(),
impls : Vec::new(),
foreigns : Vec::new(),
macros : Vec::new(),
proc_macros: Vec::new(),
imports : Vec::new(),
structs : Vec::new(),
unions : Vec::new(),
enums : Vec::new(),
fns : Vec::new(),
mods : Vec::new(),
typedefs : Vec::new(),
existentials: Vec::new(),
statics : Vec::new(),
constants : Vec::new(),
traits : Vec::new(),
impls : Vec::new(),
foreigns : Vec::new(),
macros : Vec::new(),
proc_macros: Vec::new(),
trait_aliases: Vec::new(),
is_crate : false,
}
}
@ -208,6 +210,18 @@ pub struct Trait {
pub depr: Option<attr::Deprecation>,
}
pub struct TraitAlias {
pub name: Name,
pub generics: hir::Generics,
pub bounds: hir::HirVec<hir::GenericBound>,
pub attrs: hir::HirVec<ast::Attribute>,
pub id: ast::NodeId,
pub whence: Span,
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub depr: Option<attr::Deprecation>,
}
#[derive(Debug)]
pub struct Impl {
pub unsafety: hir::Unsafety,

View File

@ -42,6 +42,7 @@ pub enum ItemType {
Existential = 22,
ProcAttribute = 23,
ProcDerive = 24,
TraitAlias = 25,
}
@ -86,6 +87,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::KeywordItem(..) => ItemType::Keyword,
clean::TraitAliasItem(..) => ItemType::TraitAlias,
clean::ProcMacroItem(ref mac) => match mac.kind {
MacroKind::Bang => ItemType::Macro,
MacroKind::Attr => ItemType::ProcAttribute,
@ -100,20 +102,21 @@ impl<'a> From<&'a clean::Item> for ItemType {
impl From<clean::TypeKind> for ItemType {
fn from(kind: clean::TypeKind) -> ItemType {
match kind {
clean::TypeKind::Struct => ItemType::Struct,
clean::TypeKind::Union => ItemType::Union,
clean::TypeKind::Enum => ItemType::Enum,
clean::TypeKind::Function => ItemType::Function,
clean::TypeKind::Trait => ItemType::Trait,
clean::TypeKind::Module => ItemType::Module,
clean::TypeKind::Static => ItemType::Static,
clean::TypeKind::Const => ItemType::Constant,
clean::TypeKind::Variant => ItemType::Variant,
clean::TypeKind::Typedef => ItemType::Typedef,
clean::TypeKind::Foreign => ItemType::ForeignType,
clean::TypeKind::Macro => ItemType::Macro,
clean::TypeKind::Attr => ItemType::ProcAttribute,
clean::TypeKind::Derive => ItemType::ProcDerive,
clean::TypeKind::Struct => ItemType::Struct,
clean::TypeKind::Union => ItemType::Union,
clean::TypeKind::Enum => ItemType::Enum,
clean::TypeKind::Function => ItemType::Function,
clean::TypeKind::Trait => ItemType::Trait,
clean::TypeKind::Module => ItemType::Module,
clean::TypeKind::Static => ItemType::Static,
clean::TypeKind::Const => ItemType::Constant,
clean::TypeKind::Variant => ItemType::Variant,
clean::TypeKind::Typedef => ItemType::Typedef,
clean::TypeKind::Foreign => ItemType::ForeignType,
clean::TypeKind::Macro => ItemType::Macro,
clean::TypeKind::Attr => ItemType::ProcAttribute,
clean::TypeKind::Derive => ItemType::ProcDerive,
clean::TypeKind::TraitAlias => ItemType::TraitAlias,
}
}
}
@ -146,6 +149,7 @@ impl ItemType {
ItemType::Existential => "existential",
ItemType::ProcAttribute => "attr",
ItemType::ProcDerive => "derive",
ItemType::TraitAlias => "traitalias",
}
}
@ -160,6 +164,7 @@ impl ItemType {
ItemType::Primitive |
ItemType::AssociatedType |
ItemType::Existential |
ItemType::TraitAlias |
ItemType::ForeignType => NameSpace::Type,
ItemType::ExternCrate |

View File

@ -1836,6 +1836,7 @@ struct AllTypes {
keywords: FxHashSet<ItemEntry>,
attributes: FxHashSet<ItemEntry>,
derives: FxHashSet<ItemEntry>,
trait_aliases: FxHashSet<ItemEntry>,
}
impl AllTypes {
@ -1856,6 +1857,7 @@ impl AllTypes {
keywords: new_set(100),
attributes: new_set(100),
derives: new_set(100),
trait_aliases: new_set(100),
}
}
@ -1879,6 +1881,7 @@ impl AllTypes {
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
_ => true,
};
}
@ -1922,6 +1925,7 @@ impl fmt::Display for AllTypes {
print_entries(f, &self.derives, "Derive Macros", "derives")?;
print_entries(f, &self.functions, "Functions", "functions")?;
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-alias")?;
print_entries(f, &self.existentials, "Existentials", "existentials")?;
print_entries(f, &self.statics, "Statics", "statics")?;
print_entries(f, &self.constants, "Constants", "constants")
@ -2419,6 +2423,7 @@ impl<'a> fmt::Display for Item<'a> {
clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
clean::KeywordItem(..) => write!(fmt, "Keyword ")?,
clean::ExistentialItem(..) => write!(fmt, "Existential Type ")?,
clean::TraitAliasItem(..) => write!(fmt, "Trait Alias ")?,
_ => {
// We don't generate pages for any other type.
unreachable!();
@ -2457,6 +2462,7 @@ impl<'a> fmt::Display for Item<'a> {
clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k),
clean::ExistentialItem(ref e, _) => item_existential(fmt, self.cx, self.item, e),
clean::TraitAliasItem(ref ta) => item_trait_alias(fmt, self.cx, self.item, ta),
_ => {
// We don't generate pages for any other type.
unreachable!();
@ -3014,23 +3020,17 @@ fn render_impls(cx: &Context, w: &mut fmt::Formatter,
Ok(())
}
fn bounds(t_bounds: &[clean::GenericBound]) -> String {
fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
let mut bounds = String::new();
let mut bounds_plain = String::new();
if !t_bounds.is_empty() {
if !bounds.is_empty() {
bounds.push(' ');
bounds_plain.push(' ');
if !trait_alias {
bounds.push_str(": ");
}
bounds.push_str(": ");
bounds_plain.push_str(": ");
for (i, p) in t_bounds.iter().enumerate() {
if i > 0 {
bounds.push_str(" + ");
bounds_plain.push_str(" + ");
}
bounds.push_str(&(*p).to_string());
bounds_plain.push_str(&format!("{:#}", *p));
}
}
bounds
@ -3050,7 +3050,7 @@ fn item_trait(
it: &clean::Item,
t: &clean::Trait,
) -> fmt::Result {
let bounds = bounds(&t.bounds);
let bounds = bounds(&t.bounds, false);
let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
@ -4280,7 +4280,26 @@ fn item_existential(
it.name.as_ref().unwrap(),
t.generics,
where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
bounds = bounds(&t.bounds))?;
bounds = bounds(&t.bounds, false))?;
document(w, cx, it)?;
// Render any items associated directly to this alias, as otherwise they
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_trait_alias(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
t: &clean::TraitAlias) -> fmt::Result {
write!(w, "<pre class='rust trait-alias'>")?;
render_attributes(w, it)?;
write!(w, "trait {}{}{} = {};</pre>",
it.name.as_ref().unwrap(),
t.generics,
WhereClause { gens: &t.generics, indent: 0, end_newline: true },
bounds(&t.bounds, true))?;
document(w, cx, it)?;
@ -4844,6 +4863,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
ItemType::Existential => ("existentials", "Existentials"),
ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
ItemType::ProcDerive => ("derives", "Derive Macros"),
ItemType::TraitAlias => ("trait-alias", "Trait aliases"),
}
}

View File

@ -224,6 +224,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
| clean::ConstantItem(..)
| clean::UnionItem(..)
| clean::AssociatedConstItem(..)
| clean::TraitAliasItem(..)
| clean::ForeignTypeItem => {
if i.def_id.is_local() {
if !self.access_levels.is_exported(i.def_id) {

View File

@ -547,8 +547,19 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
};
om.traits.push(t);
},
hir::ItemKind::TraitAlias(..) => {
unimplemented!("trait objects are not yet implemented")
hir::ItemKind::TraitAlias(ref gen, ref b) => {
let t = TraitAlias {
name: ident.name,
generics: gen.clone(),
bounds: b.iter().cloned().collect(),
id: item.id,
attrs: item.attrs.clone(),
whence: item.span,
vis: item.vis.clone(),
stab: self.stability(item.id),
depr: self.deprecation(item.id),
};
om.trait_aliases.push(t);
},
hir::ItemKind::Impl(unsafety,

View File

@ -0,0 +1,21 @@
#![feature(trait_alias)]
#![crate_name = "foo"]
use std::fmt::Debug;
// @has foo/all.html '//a[@href="traitalias.CopyAlias.html"]' 'CopyAlias'
// @has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
// @has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo'
// @has foo/index.html '//h2[@id="trait-alias"]' 'Trait aliases'
// @has foo/index.html '//a[@class="traitalias"]' 'CopyAlias'
// @has foo/index.html '//a[@class="traitalias"]' 'Alias2'
// @has foo/index.html '//a[@class="traitalias"]' 'Foo'
// @has foo/traitalias.CopyAlias.html '//section[@id="main"]/pre' 'trait CopyAlias = Copy;'
pub trait CopyAlias = Copy;
// @has foo/traitalias.Alias2.html '//section[@id="main"]/pre' 'trait Alias2 = Copy + Debug;'
pub trait Alias2 = Copy + Debug;
// @has foo/traitalias.Foo.html '//section[@id="main"]/pre' 'trait Foo<T> = Into<T> + Debug;'
pub trait Foo<T> = Into<T> + Debug;