diff options
| author | kennytm <kennytm@gmail.com> | 2018-09-29 16:46:30 +0800 |
|---|---|---|
| committer | kennytm <kennytm@gmail.com> | 2018-09-29 16:46:30 +0800 |
| commit | def5f84fa64f4a64137dcfc4cc5e3007cc9257e6 (patch) | |
| tree | 08e5f783a646addc58ba008ca8b893fa3bc5c72f | |
| parent | 3861591946a58faaab861d1336ad0ae51e36c0a1 (diff) | |
| parent | d37f3696b167251a96b8f0e4b33336d023daa2c5 (diff) | |
| download | rust-def5f84fa64f4a64137dcfc4cc5e3007cc9257e6.tar.gz rust-def5f84fa64f4a64137dcfc4cc5e3007cc9257e6.zip | |
Rollup merge of #54577 - QuietMisdreavus:docs-for-procs, r=GuillaumeGomez
rustdoc: give proc-macros their own pages related to https://github.com/rust-lang/rust/issues/49553 but i don't think it'll fix it Currently, rustdoc doesn't expose proc-macros all that well. In the source crate, only their definition function is exposed, but when re-exported, they're treated as a macro! This is an awkward situation in all accounts. This PR checks functions to see whether they have any of `#[proc_macro]`, `#[proc_macro_attribute]`, or `#[proc_macro_derive]`, and exposes them as macros instead. In addition, attributes and derives are exposed differently than other macros, getting their own item-type, CSS class, and module heading.  Function-like proc-macros are lumped in with `macro_rules!` macros, but they get a different declaration block (i'm open to tweaking this, it's just what i thought of given how function-proc-macros operate):  Proc-macro attributes and derives get their own pages, with a representative declaration block. Derive macros also show off their helper attributes:   There's one wrinkle which this PR doesn't address, which is why i didn't mark this as fixing the linked issue. Currently, proc-macros don't expose their attributes or source span across crates, so while rustdoc knows they exist, that's about all the information it gets. This leads to an "inlined" macro that has absolutely no docs on it, and no `[src]` link to show you where it was declared. The way i got around it was to keep proc-macro re-export disabled, since we do get enough information across crates to properly link to the source page:  Until we can get a proc-macro's docs (and ideally also its source span) across crates, i believe this is the best way forward.
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 68 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 36 | ||||
| -rw-r--r-- | src/librustdoc/doctree.rs | 14 | ||||
| -rw-r--r-- | src/librustdoc/html/item_type.rs | 24 | ||||
| -rw-r--r-- | src/librustdoc/html/render.rs | 60 | ||||
| -rw-r--r-- | src/librustdoc/html/static/main.js | 5 | ||||
| -rw-r--r-- | src/librustdoc/html/static/themes/dark.css | 4 | ||||
| -rw-r--r-- | src/librustdoc/html/static/themes/light.css | 4 | ||||
| -rw-r--r-- | src/librustdoc/passes/mod.rs | 3 | ||||
| -rw-r--r-- | src/librustdoc/visit_ast.rs | 82 | ||||
| -rw-r--r-- | src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs | 37 | ||||
| -rw-r--r-- | src/test/rustdoc/inline_cross/proc_macro.rs | 27 | ||||
| -rw-r--r-- | src/test/rustdoc/proc-macro.rs | 62 |
13 files changed, 374 insertions, 52 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1ea130cf16a..a435712ac3d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -13,7 +13,7 @@ use std::iter::once; use syntax::ast; -use syntax::ext::base::MacroKind; +use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax_pos::Span; use rustc::hir; @@ -105,12 +105,12 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa record_extern_fqn(cx, did, clean::TypeKind::Const); clean::ConstantItem(build_const(cx, did)) } - // FIXME(misdreavus): if attributes/derives come down here we should probably document them - // separately + // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty Def::Macro(did, MacroKind::Bang) => { - record_extern_fqn(cx, did, clean::TypeKind::Macro); - if let Some(mac) = build_macro(cx, did, name) { - clean::MacroItem(mac) + let mac = build_macro(cx, did, name); + if let clean::MacroItem(..) = mac { + record_extern_fqn(cx, did, clean::TypeKind::Macro); + mac } else { return None; } @@ -442,31 +442,41 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { } } -fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> Option<clean::Macro> { +fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> clean::ItemEnum { let imported_from = cx.tcx.original_crate_name(did.krate); - let def = match cx.cstore.load_macro_untracked(did, cx.sess()) { - LoadedMacro::MacroDef(macro_def) => macro_def, - // FIXME(jseyfried): document proc macro re-exports - LoadedMacro::ProcMacro(..) => return None, - }; - - let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.node { - let tts: Vec<_> = def.stream().into_trees().collect(); - tts.chunks(4).map(|arm| arm[0].span()).collect() - } else { - unreachable!() - }; - - let source = format!("macro_rules! {} {{\n{}}}", - name.clean(cx), - matchers.iter().map(|span| { - format!(" {} => {{ ... }};\n", span.to_src(cx)) - }).collect::<String>()); + match cx.cstore.load_macro_untracked(did, cx.sess()) { + LoadedMacro::MacroDef(def) => { + let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.node { + let tts: Vec<_> = def.stream().into_trees().collect(); + tts.chunks(4).map(|arm| arm[0].span()).collect() + } else { + unreachable!() + }; + + let source = format!("macro_rules! {} {{\n{}}}", + name.clean(cx), + matchers.iter().map(|span| { + format!(" {} => {{ ... }};\n", span.to_src(cx)) + }).collect::<String>()); + + clean::MacroItem(clean::Macro { + source, + imported_from: Some(imported_from).clean(cx), + }) + } + LoadedMacro::ProcMacro(ext) => { + let helpers = match &*ext { + &SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) } + _ => Vec::new(), + }; + + clean::ProcMacroItem(clean::ProcMacro { + kind: ext.kind(), + helpers, + }) + } + } - Some(clean::Macro { - source, - imported_from: Some(imported_from).clean(cx), - }) } /// A trait's generics clause actually contains all of the predicates for all of diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a982933f6c1..41c4ee982ff 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -21,6 +21,7 @@ pub use self::Visibility::{Public, Inherited}; use rustc_target::spec::abi::Abi; use syntax::ast::{self, AttrStyle, Ident}; use syntax::attr; +use syntax::ext::base::MacroKind; use syntax::source_map::{dummy_spanned, Spanned}; use syntax::ptr::P; use syntax::symbol::keywords::{self, Keyword}; @@ -527,6 +528,7 @@ pub enum ItemEnum { /// `type`s from an extern block ForeignTypeItem, MacroItem(Macro), + ProcMacroItem(ProcMacro), PrimitiveItem(PrimitiveType), AssociatedConstItem(Type, Option<String>), AssociatedTypeItem(Vec<GenericBound>, Option<Type>), @@ -588,6 +590,7 @@ impl Clean<Item> for doctree::Module { items.extend(self.traits.iter().map(|x| x.clean(cx))); 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))); // determine if we should display the inner contents or // the outer `mod` item for the source code. @@ -2189,6 +2192,8 @@ pub enum TypeKind { Typedef, Foreign, Macro, + Attr, + Derive, } pub trait GetDefId { @@ -3725,7 +3730,12 @@ pub fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Static(i, _) => (i, TypeKind::Static), Def::Variant(i) => (cx.tcx.parent_def_id(i).expect("cannot get parent def id"), TypeKind::Enum), - Def::Macro(i, _) => (i, TypeKind::Macro), + Def::Macro(i, mac_kind) => match mac_kind { + MacroKind::Bang => (i, TypeKind::Macro), + MacroKind::Attr => (i, TypeKind::Attr), + MacroKind::Derive => (i, TypeKind::Derive), + MacroKind::ProcMacroStub => unreachable!(), + }, Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), Def::SelfTy(_, Some(impl_def_id)) => { return impl_def_id @@ -3781,6 +3791,30 @@ impl Clean<Item> for doctree::Macro { } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct ProcMacro { + pub kind: MacroKind, + pub helpers: Vec<String>, +} + +impl Clean<Item> for doctree::ProcMacro { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), + attrs: self.attrs.clean(cx), + source: self.whence.clean(cx), + visibility: Some(Public), + stability: self.stab.clean(cx), + deprecation: self.depr.clean(cx), + def_id: cx.tcx.hir.local_def_id(self.id), + inner: ProcMacroItem(ProcMacro { + kind: self.kind, + helpers: self.helpers.clean(cx), + }), + } + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Stability { pub level: stability::StabilityLevel, pub feature: String, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index dd1e1e99957..4a6a4ee09ea 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -15,6 +15,7 @@ pub use self::StructType::*; use syntax::ast; use syntax::ast::{Name, NodeId}; use syntax::attr; +use syntax::ext::base::MacroKind; use syntax::ptr::P; use syntax::source_map::Spanned; use syntax_pos::{self, Span}; @@ -46,6 +47,7 @@ pub struct Module { pub impls: Vec<Impl>, pub foreigns: Vec<hir::ForeignMod>, pub macros: Vec<Macro>, + pub proc_macros: Vec<ProcMacro>, pub is_crate: bool, } @@ -75,6 +77,7 @@ impl Module { impls : Vec::new(), foreigns : Vec::new(), macros : Vec::new(), + proc_macros: Vec::new(), is_crate : false, } } @@ -264,6 +267,17 @@ pub struct Import { pub whence: Span, } +pub struct ProcMacro { + pub name: Name, + pub id: NodeId, + pub kind: MacroKind, + pub helpers: Vec<Name>, + pub attrs: hir::HirVec<ast::Attribute>, + pub whence: Span, + pub stab: Option<attr::Stability>, + pub depr: Option<attr::Deprecation>, +} + pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType { match *vdata { hir::VariantData::Struct(..) => Plain, diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index a5131e327e0..acb8f6a66df 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -11,6 +11,7 @@ //! Item types. use std::fmt; +use syntax::ext::base::MacroKind; use clean; /// Item type. Corresponds to `clean::ItemEnum` variants. @@ -19,6 +20,11 @@ use clean; /// discriminants. JavaScript then is used to decode them into the original value. /// Consequently, every change to this type should be synchronized to /// the `itemTypes` mapping table in `static/main.js`. +/// +/// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and +/// module headings. If you are adding to this enum and want to ensure that the sidebar also prints +/// a heading, edit the listing in `html/render.rs`, function `sidebar_module`. This uses an +/// ordering based on a helper function inside `item_module`, in the same file. #[derive(Copy, PartialEq, Clone, Debug)] pub enum ItemType { Module = 0, @@ -44,6 +50,8 @@ pub enum ItemType { ForeignType = 20, Keyword = 21, Existential = 22, + ProcAttribute = 23, + ProcDerive = 24, } @@ -88,6 +96,12 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::AssociatedTypeItem(..) => ItemType::AssociatedType, clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem(..) => ItemType::Keyword, + clean::ProcMacroItem(ref mac) => match mac.kind { + MacroKind::Bang => ItemType::Macro, + MacroKind::Attr => ItemType::ProcAttribute, + MacroKind::Derive => ItemType::ProcDerive, + MacroKind::ProcMacroStub => unreachable!(), + } clean::StrippedItem(..) => unreachable!(), } } @@ -107,7 +121,9 @@ impl From<clean::TypeKind> for ItemType { clean::TypeKind::Variant => ItemType::Variant, clean::TypeKind::Typedef => ItemType::Typedef, clean::TypeKind::Foreign => ItemType::ForeignType, - clean::TypeKind::Macro => ItemType::Macro, + clean::TypeKind::Macro => ItemType::Macro, + clean::TypeKind::Attr => ItemType::ProcAttribute, + clean::TypeKind::Derive => ItemType::ProcDerive, } } } @@ -138,6 +154,8 @@ impl ItemType { ItemType::ForeignType => "foreigntype", ItemType::Keyword => "keyword", ItemType::Existential => "existential", + ItemType::ProcAttribute => "attr", + ItemType::ProcDerive => "derive", } } @@ -166,7 +184,9 @@ impl ItemType { ItemType::Constant | ItemType::AssociatedConst => NameSpace::Value, - ItemType::Macro => NameSpace::Macro, + ItemType::Macro | + ItemType::ProcAttribute | + ItemType::ProcDerive => NameSpace::Macro, ItemType::Keyword => NameSpace::Keyword, } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 3e1720f8b8a..1c61e73fae0 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -56,6 +56,7 @@ use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; use syntax::ast; +use syntax::ext::base::MacroKind; use syntax::source_map::FileName; use syntax::feature_gate::UnstableFeatures; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; @@ -1595,6 +1596,8 @@ struct AllTypes { statics: FxHashSet<ItemEntry>, constants: FxHashSet<ItemEntry>, keywords: FxHashSet<ItemEntry>, + attributes: FxHashSet<ItemEntry>, + derives: FxHashSet<ItemEntry>, } impl AllTypes { @@ -1613,6 +1616,8 @@ impl AllTypes { statics: new_set(100), constants: new_set(100), keywords: new_set(100), + attributes: new_set(100), + derives: new_set(100), } } @@ -1634,6 +1639,8 @@ impl AllTypes { ItemType::Existential => self.existentials.insert(ItemEntry::new(new_url, name)), ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)), 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)), _ => true, }; } @@ -1673,6 +1680,8 @@ impl fmt::Display for AllTypes { print_entries(f, &self.primitives, "Primitives", "primitives")?; print_entries(f, &self.traits, "Traits", "traits")?; print_entries(f, &self.macros, "Macros", "macros")?; + print_entries(f, &self.attributes, "Attribute Macros", "attributes")?; + 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.existentials, "Existentials", "existentials")?; @@ -2155,6 +2164,12 @@ impl<'a> fmt::Display for Item<'a> { clean::EnumItem(..) => write!(fmt, "Enum ")?, clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, clean::MacroItem(..) => write!(fmt, "Macro ")?, + clean::ProcMacroItem(ref mac) => match mac.kind { + MacroKind::Bang => write!(fmt, "Macro ")?, + MacroKind::Attr => write!(fmt, "Attribute Macro ")?, + MacroKind::Derive => write!(fmt, "Derive Macro ")?, + MacroKind::ProcMacroStub => unreachable!(), + } clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?, clean::ConstantItem(..) => write!(fmt, "Constant ")?, @@ -2191,6 +2206,7 @@ impl<'a> fmt::Display for Item<'a> { 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), + clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m), clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p), clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(fmt, self.cx, self.item, i), @@ -4079,11 +4095,12 @@ impl<'a> fmt::Display for Sidebar<'a> { write!(fmt, "<div class='block version'>\ <p>Version {}</p>\ - </div> - <a id='all-types' href='all.html'><p>See all {}'s items</p></a>", - version, - it.name.as_ref().unwrap())?; + </div>", + version)?; } + + write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>", + it.name.as_ref().expect("crates always have a name"))?; } write!(fmt, "<div class=\"sidebar-elems\">")?; @@ -4523,6 +4540,8 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { ItemType::ForeignType => ("foreign-types", "Foreign Types"), ItemType::Keyword => ("keywords", "Keywords"), ItemType::Existential => ("existentials", "Existentials"), + ItemType::ProcAttribute => ("attributes", "Attribute Macros"), + ItemType::ProcDerive => ("derives", "Derive Macros"), } } @@ -4598,6 +4617,39 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, document(w, cx, it) } +fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) + -> fmt::Result +{ + let name = it.name.as_ref().expect("proc-macros always have names"); + match m.kind { + MacroKind::Bang => { + write!(w, "<pre class='rust macro'>")?; + write!(w, "{}!() {{ /* proc-macro */ }}", name)?; + write!(w, "</pre>")?; + } + MacroKind::Attr => { + write!(w, "<pre class='rust attr'>")?; + write!(w, "#[{}]", name)?; + write!(w, "</pre>")?; + } + MacroKind::Derive => { + write!(w, "<pre class='rust derive'>")?; + write!(w, "#[derive({})]", name)?; + if !m.helpers.is_empty() { + writeln!(w, "\n{{")?; + writeln!(w, " // Attributes available to this derive:")?; + for attr in &m.helpers { + writeln!(w, " #[{}]", attr)?; + } + write!(w, "}}")?; + } + write!(w, "</pre>")?; + } + _ => {} + } + document(w, cx, it) +} + fn item_primitive(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, _p: &clean::PrimitiveType) -> fmt::Result { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 0b56692bc2e..6307dda454d 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -39,7 +39,10 @@ "associatedconstant", "union", "foreigntype", - "keyword"]; + "keyword", + "existential", + "attr", + "derive"]; var search_input = document.getElementsByClassName('search-input')[0]; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 12d22084893..34a1d71beec 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -124,6 +124,8 @@ pre { .content .highlighted.tymethod { background-color: #4950ed; } .content .highlighted.type { background-color: #38902c; } .content .highlighted.foreigntype { background-color: #b200d6; } +.content .highlighted.attr, +.content .highlighted.derive, .content .highlighted.macro { background-color: #217d1c; } .content .highlighted.constant, .content .highlighted.static { background-color: #0063cc; } @@ -134,6 +136,8 @@ pre { .content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } .content span.type, .content a.type, .block a.current.type { color: #ff7f00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; } +.content span.attr, .content a.attr, .block a.current.attr, +.content span.derive, .content a.derive, .block a.current.derive, .content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; } .content span.union, .content a.union, .block a.current.union { color: #a6ae37; } .content span.constant, .content a.constant, .block a.current.constant, diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 043d7ae23c2..8218b1b371e 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -124,6 +124,8 @@ pre { .content .highlighted.tymethod { background-color: #c6afb3; } .content .highlighted.type { background-color: #ffc891; } .content .highlighted.foreigntype { background-color: #f5c4ff; } +.content .highlighted.attr, +.content .highlighted.derive, .content .highlighted.macro { background-color: #8ce488; } .content .highlighted.constant, .content .highlighted.static { background-color: #c3e0ff; } @@ -134,6 +136,8 @@ pre { .content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; } .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } +.content span.attr, .content a.attr, .block a.current.attr, +.content span.derive, .content a.derive, .block a.current.derive, .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } .content span.union, .content a.union, .block a.current.union { color: #767b27; } .content span.constant, .content a.constant, .block a.current.constant, diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 24fec62dd57..d00eb3257d4 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -249,6 +249,9 @@ impl<'a> fold::DocFolder for Stripper<'a> { // tymethods/macros have no control over privacy clean::MacroItem(..) | clean::TyMethodItem(..) => {} + // Proc-macros are always public + clean::ProcMacroItem(..) => {} + // Primitives are never stripped clean::PrimitiveItem(..) => {} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0e12fd34eb7..92d8dbed071 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -15,6 +15,7 @@ use std::mem; use syntax::ast; use syntax::attr; +use syntax::ext::base::MacroKind; use syntax::source_map::Spanned; use syntax_pos::{self, Span}; @@ -168,24 +169,75 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { } } - pub fn visit_fn(&mut self, item: &hir::Item, + pub fn visit_fn(&mut self, om: &mut Module, item: &hir::Item, name: ast::Name, fd: &hir::FnDecl, header: hir::FnHeader, gen: &hir::Generics, - body: hir::BodyId) -> Function { + body: hir::BodyId) { debug!("Visiting fn"); - Function { - id: item.id, - vis: item.vis.clone(), - stab: self.stability(item.id), - depr: self.deprecation(item.id), - attrs: item.attrs.clone(), - decl: fd.clone(), - name, - whence: item.span, - generics: gen.clone(), - header, - body, + let macro_kind = item.attrs.iter().filter_map(|a| { + if a.check_name("proc_macro") { + Some(MacroKind::Bang) + } else if a.check_name("proc_macro_derive") { + Some(MacroKind::Derive) + } else if a.check_name("proc_macro_attribute") { + Some(MacroKind::Attr) + } else { + None + } + }).next(); + match macro_kind { + Some(kind) => { + let name = if kind == MacroKind::Derive { + item.attrs.lists("proc_macro_derive") + .filter_map(|mi| mi.name()) + .next() + .expect("proc-macro derives require a name") + } else { + name + }; + + let mut helpers = Vec::new(); + for mi in item.attrs.lists("proc_macro_derive") { + if !mi.check_name("attributes") { + continue; + } + + if let Some(list) = mi.meta_item_list() { + for inner_mi in list { + if let Some(name) = inner_mi.name() { + helpers.push(name); + } + } + } + } + + om.proc_macros.push(ProcMacro { + name, + id: item.id, + kind, + helpers, + attrs: item.attrs.clone(), + whence: item.span, + stab: self.stability(item.id), + depr: self.deprecation(item.id), + }); + } + None => { + om.fns.push(Function { + id: item.id, + vis: item.vis.clone(), + stab: self.stability(item.id), + depr: self.deprecation(item.id), + attrs: item.attrs.clone(), + decl: fd.clone(), + name, + whence: item.span, + generics: gen.clone(), + header, + body, + }); + } } } @@ -425,7 +477,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { hir::ItemKind::Union(ref sd, ref gen) => om.unions.push(self.visit_union_data(item, name, sd, gen)), hir::ItemKind::Fn(ref fd, header, ref gen, body) => - om.fns.push(self.visit_fn(item, name, &**fd, header, gen, body)), + self.visit_fn(om, item, name, &**fd, header, gen, body), hir::ItemKind::Ty(ref ty, ref gen) => { let t = Typedef { ty: ty.clone(), diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs new file mode 100644 index 00000000000..6aac070c45b --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -0,0 +1,37 @@ +// Copyright 2018 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. + +// no-prefer-dynamic + +#![crate_type="proc-macro"] +#![crate_name="some_macros"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +/// a proc-macro that swallows its input and does nothing. +#[proc_macro] +pub fn some_proc_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} + +/// a proc-macro attribute that passes its item through verbatim. +#[proc_macro_attribute] +pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + +/// a derive attribute that adds nothing to its input. +#[proc_macro_derive(SomeDerive)] +pub fn some_derive(_item: TokenStream) -> TokenStream { + TokenStream::new() +} + diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs new file mode 100644 index 00000000000..a879258f82a --- /dev/null +++ b/src/test/rustdoc/inline_cross/proc_macro.rs @@ -0,0 +1,27 @@ +// Copyright 2018 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. + +// ignore-stage1 +// aux-build:proc_macro.rs +// build-aux-docs + +// FIXME: if/when proc-macros start exporting their doc attributes across crates, we can turn on +// cross-crate inlining for them + +extern crate some_macros; + +// @has proc_macro/index.html +// @has - '//a/@href' '../some_macros/macro.some_proc_macro.html' +// @has - '//a/@href' '../some_macros/attr.some_proc_attr.html' +// @has - '//a/@href' '../some_macros/derive.SomeDerive.html' +// @!has proc_macro/macro.some_proc_macro.html +// @!has proc_macro/attr.some_proc_attr.html +// @!has proc_macro/derive.SomeDerive.html +pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive}; diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs new file mode 100644 index 00000000000..bfd194701c8 --- /dev/null +++ b/src/test/rustdoc/proc-macro.rs @@ -0,0 +1,62 @@ +// Copyright 2018 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. + +// ignore-stage1 + +#![crate_type="proc-macro"] +#![crate_name="some_macros"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +// @has some_macros/index.html +// @has - '//h2' 'Macros' +// @has - '//h2' 'Attribute Macros' +// @has - '//h2' 'Derive Macros' +// @!has - '//h2' 'Functions' + +// @has some_macros/all.html +// @has - '//a[@href="macro.some_proc_macro.html"]' 'some_proc_macro' +// @has - '//a[@href="attr.some_proc_attr.html"]' 'some_proc_attr' +// @has - '//a[@href="derive.SomeDerive.html"]' 'SomeDerive' +// @!has - '//a/@href' 'fn.some_proc_macro.html' +// @!has - '//a/@href' 'fn.some_proc_attr.html' +// @!has - '//a/@href' 'fn.some_derive.html' + +// @has some_macros/index.html '//a/@href' 'macro.some_proc_macro.html' +// @!has - '//a/@href' 'fn.some_proc_macro.html' +// @has some_macros/macro.some_proc_macro.html +// @!has some_macros/fn.some_proc_macro.html +/// a proc-macro that swallows its input and does nothing. +#[proc_macro] +pub fn some_proc_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} + +// @has some_macros/index.html '//a/@href' 'attr.some_proc_attr.html' +// @!has - '//a/@href' 'fn.some_proc_attr.html' +// @has some_macros/attr.some_proc_attr.html +// @!has some_macros/fn.some_proc_attr.html +/// a proc-macro attribute that passes its item through verbatim. +#[proc_macro_attribute] +pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + +// @has some_macros/index.html '//a/@href' 'derive.SomeDerive.html' +// @!has - '//a/@href' 'fn.some_derive.html' +// @has some_macros/derive.SomeDerive.html +// @!has some_macros/fn.some_derive.html +/// a derive attribute that adds nothing to its input. +#[proc_macro_derive(SomeDerive)] +pub fn some_derive(_item: TokenStream) -> TokenStream { + TokenStream::new() +} |
