From aea1bd0a5908430d41b6f2d38240f2652ef5651f Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 25 Sep 2018 14:56:43 -0500 Subject: [PATCH 1/8] handle proc-macros as macros instead of functions --- src/librustdoc/clean/inline.rs | 65 ++++++++++---------- src/librustdoc/clean/mod.rs | 34 ++++++++++- src/librustdoc/doctree.rs | 13 ++++ src/librustdoc/html/item_type.rs | 24 +++++++- src/librustdoc/html/render.rs | 21 +++++++ src/librustdoc/html/static/main.js | 5 +- src/librustdoc/html/static/themes/dark.css | 4 ++ src/librustdoc/html/static/themes/light.css | 4 ++ src/librustdoc/passes/mod.rs | 3 + src/librustdoc/visit_ast.rs | 66 ++++++++++++++++----- src/test/rustdoc/proc-macro.rs | 54 +++++++++++++++++ 11 files changed, 243 insertions(+), 50 deletions(-) create mode 100644 src/test/rustdoc/proc-macro.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1ea130cf16ae2..287637ae0da9d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -105,15 +105,14 @@ 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 - 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) - } else { - return None; + Def::Macro(did, mac_kind) => { + match mac_kind { + MacroKind::Bang => record_extern_fqn(cx, did, clean::TypeKind::Macro), + MacroKind::Attr => record_extern_fqn(cx, did, clean::TypeKind::Attr), + MacroKind::Derive => record_extern_fqn(cx, did, clean::TypeKind::Derive), + MacroKind::ProcMacroStub => return None, } + build_macro(cx, did, name) } _ => return None, }; @@ -442,31 +441,35 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { } } -fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> Option { +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 = 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::()); + match cx.cstore.load_macro_untracked(did, cx.sess()) { + LoadedMacro::MacroDef(def) => { + let matchers: hir::HirVec = 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::()); + + clean::MacroItem(clean::Macro { + source, + imported_from: Some(imported_from).clean(cx), + }) + } + LoadedMacro::ProcMacro(ext) => { + clean::ProcMacroItem(clean::ProcMacro { + kind: ext.kind(), + }) + } + } - 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 a982933f6c1a2..244911150043c 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), AssociatedTypeItem(Vec, Option), @@ -588,6 +590,7 @@ impl Clean 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 @@ -3780,6 +3790,28 @@ impl Clean for doctree::Macro { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct ProcMacro { + pub kind: MacroKind, +} + +impl Clean 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, + }), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Stability { pub level: stability::StabilityLevel, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index dd1e1e99957ce..538e61fcb4d32 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, pub foreigns: Vec, pub macros: Vec, + pub proc_macros: Vec, 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,16 @@ pub struct Import { pub whence: Span, } +pub struct ProcMacro { + pub name: Name, + pub id: NodeId, + pub kind: MacroKind, + pub attrs: hir::HirVec, + pub whence: Span, + pub stab: Option, + pub depr: Option, +} + 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 a5131e327e08e..acb8f6a66dfcb 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 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 3e1720f8b8ab2..dc3255d2e528a 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}; @@ -2155,6 +2156,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 +2198,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), @@ -4523,6 +4531,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 +4608,17 @@ 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 +{ + if m.kind == MacroKind::Bang { + write!(w, "
")?;
+        write!(w, "{}!() {{ /* proc-macro */ }}", it.name.as_ref().unwrap())?;
+        write!(w, "
")?; + } + 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 3dbefabace18f..f81391ecefe39 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 12d2208489368..34a1d71beecfc 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 043d7ae23c2e4..8218b1b371ea7 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 24fec62dd573a..d00eb3257d43c 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 0e12fd34eb7d8..dbe25c5ff8a49 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,59 @@ 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 + }; + + om.proc_macros.push(ProcMacro { + name, + id: item.id, + kind, + 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 +461,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/proc-macro.rs b/src/test/rustdoc/proc-macro.rs new file mode 100644 index 0000000000000..cdf2783aec749 --- /dev/null +++ b/src/test/rustdoc/proc-macro.rs @@ -0,0 +1,54 @@ +// 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 or the MIT license +// , 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/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() +} From f05b744b083598f3a34d02ac55d27bb144d99e8a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 25 Sep 2018 16:15:32 -0500 Subject: [PATCH 2/8] disable proc-macro re-export inlining Proc-macros don't emit their attributes or source spans across crates. This means that rustdoc can't actually see the docs of a proc-macro if it wasn't defined in the active crate, and attempting to inline it creates an empty page with no docs or source link. In lieu of attempting to fix that immediately, this commit forces proc-macro re-exports to never inline, which at least creates usable links to complete documentation. --- src/librustdoc/clean/inline.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 287637ae0da9d..4d1b6b8b1a98e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -105,14 +105,15 @@ 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)) } - Def::Macro(did, mac_kind) => { - match mac_kind { - MacroKind::Bang => record_extern_fqn(cx, did, clean::TypeKind::Macro), - MacroKind::Attr => record_extern_fqn(cx, did, clean::TypeKind::Attr), - MacroKind::Derive => record_extern_fqn(cx, did, clean::TypeKind::Derive), - MacroKind::ProcMacroStub => return None, + // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty + Def::Macro(did, MacroKind::Bang) => { + let mac = build_macro(cx, did, name); + if let clean::MacroItem(..) = mac { + record_extern_fqn(cx, did, clean::TypeKind::Macro); + mac + } else { + return None; } - build_macro(cx, did, name) } _ => return None, }; From 8f69a82513d169b8ef57cd885194fd4f9b2d8b65 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 25 Sep 2018 16:30:19 -0500 Subject: [PATCH 3/8] add test for proc-macro re-export --- .../inline_cross/auxiliary/proc_macro.rs | 37 +++++++++++++++++++ src/test/rustdoc/inline_cross/proc_macro.rs | 27 ++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs create mode 100644 src/test/rustdoc/inline_cross/proc_macro.rs 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 0000000000000..6aac070c45bd9 --- /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 or the MIT license +// , 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 0000000000000..a879258f82aee --- /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 or the MIT license +// , 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}; From 869ebc4f9571a58d6af1855791ae15c864ea4bdc Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 26 Sep 2018 09:18:58 -0500 Subject: [PATCH 4/8] add declaration blocks to attribute/derive pages --- src/librustdoc/html/render.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index dc3255d2e528a..107858ae60527 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4611,10 +4611,24 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) -> fmt::Result { - if m.kind == MacroKind::Bang { - write!(w, "
")?;
-        write!(w, "{}!() {{ /* proc-macro */ }}", it.name.as_ref().unwrap())?;
-        write!(w, "
")?; + let name = it.name.as_ref().expect("proc-macros always have names"); + match m.kind { + MacroKind::Bang => { + write!(w, "
")?;
+            write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
+            write!(w, "
")?; + } + MacroKind::Attr => { + write!(w, "
")?;
+            write!(w, "#[{}]", name)?;
+            write!(w, "
")?; + } + MacroKind::Derive => { + write!(w, "
")?;
+            write!(w, "#[derive({})]", name)?;
+            write!(w, "
")?; + } + _ => {} } document(w, cx, it) } From 27429d94150f2d3a61ab113a9373ec2f063150a0 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 26 Sep 2018 11:29:41 -0500 Subject: [PATCH 5/8] add derive macros' helper attributes to doc output --- src/librustdoc/clean/inline.rs | 8 +++++++- src/librustdoc/clean/mod.rs | 2 ++ src/librustdoc/doctree.rs | 1 + src/librustdoc/html/render.rs | 8 ++++++++ src/librustdoc/visit_ast.rs | 16 ++++++++++++++++ 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4d1b6b8b1a98e..a435712ac3d6c 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; @@ -465,8 +465,14 @@ fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> clean::ItemEnum }) } LoadedMacro::ProcMacro(ext) => { + let helpers = match &*ext { + &SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) } + _ => Vec::new(), + }; + clean::ProcMacroItem(clean::ProcMacro { kind: ext.kind(), + helpers, }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 244911150043c..41c4ee982ff79 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3793,6 +3793,7 @@ impl Clean for doctree::Macro { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ProcMacro { pub kind: MacroKind, + pub helpers: Vec, } impl Clean for doctree::ProcMacro { @@ -3807,6 +3808,7 @@ impl Clean for doctree::ProcMacro { def_id: cx.tcx.hir.local_def_id(self.id), inner: ProcMacroItem(ProcMacro { kind: self.kind, + helpers: self.helpers.clean(cx), }), } } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 538e61fcb4d32..4a6a4ee09ea1a 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -271,6 +271,7 @@ pub struct ProcMacro { pub name: Name, pub id: NodeId, pub kind: MacroKind, + pub helpers: Vec, pub attrs: hir::HirVec, pub whence: Span, pub stab: Option, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 107858ae60527..998a48aca09fe 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4626,6 +4626,14 @@ fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &c MacroKind::Derive => { write!(w, "
")?;
             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, "
")?; } _ => {} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index dbe25c5ff8a49..92d8dbed0718a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -197,10 +197,26 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { 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), From 63ac3c7b94df4931e31472599976cb2a9b10a0d1 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 27 Sep 2018 09:04:38 -0500 Subject: [PATCH 6/8] add attributes/derives to "all items" page --- src/librustdoc/html/render.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 998a48aca09fe..8adc45ea965bc 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1596,6 +1596,8 @@ struct AllTypes { statics: FxHashSet, constants: FxHashSet, keywords: FxHashSet, + attributes: FxHashSet, + derives: FxHashSet, } impl AllTypes { @@ -1614,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), } } @@ -1635,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, }; } @@ -1674,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")?; From 967a6b02411f2eecfcc521d4b0129cc6b03d504a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 27 Sep 2018 09:12:13 -0500 Subject: [PATCH 7/8] show "all items" link even if crate doesn't have a version --- src/librustdoc/html/render.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8adc45ea965bc..1c61e73fae03c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4095,11 +4095,12 @@ impl<'a> fmt::Display for Sidebar<'a> { write!(fmt, "
\

Version {}

\ -
-

See all {}'s items

", - version, - it.name.as_ref().unwrap())?; + ", + version)?; } + + write!(fmt, "

See all {}'s items

", + it.name.as_ref().expect("crates always have a name"))?; } write!(fmt, "
")?; From d37f3696b167251a96b8f0e4b33336d023daa2c5 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 27 Sep 2018 10:22:29 -0500 Subject: [PATCH 8/8] check for proc-macros in "all items" --- src/test/rustdoc/proc-macro.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index cdf2783aec749..bfd194701c85d 100644 --- a/src/test/rustdoc/proc-macro.rs +++ b/src/test/rustdoc/proc-macro.rs @@ -23,6 +23,14 @@ use proc_macro::TokenStream; // @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