Skip to content

Commit def5f84

Browse files
committed
Rollup merge of #54577 - QuietMisdreavus:docs-for-procs, r=GuillaumeGomez
rustdoc: give proc-macros their own pages related to #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. ![image](https://user-images.githubusercontent.com/5217170/46044803-6df8da00-c0e1-11e8-8c3b-25d2c3beb55c.png) 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): ![image](https://user-images.githubusercontent.com/5217170/46044828-84069a80-c0e1-11e8-9cc4-127e5477c395.png) Proc-macro attributes and derives get their own pages, with a representative declaration block. Derive macros also show off their helper attributes: ![image](https://user-images.githubusercontent.com/5217170/46094583-ef9f4500-c17f-11e8-8f71-fa0a7895c9f6.png) ![image](https://user-images.githubusercontent.com/5217170/46101529-cab3cd80-c191-11e8-857a-946897750da1.png) 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: ![image](https://user-images.githubusercontent.com/5217170/46045074-2cb4fa00-c0e2-11e8-81bc-33a8205fbd03.png) 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.
2 parents 3861591 + d37f369 commit def5f84

File tree

13 files changed

+346
-24
lines changed

13 files changed

+346
-24
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use std::iter::once;
1414

1515
use syntax::ast;
16-
use syntax::ext::base::MacroKind;
16+
use syntax::ext::base::{MacroKind, SyntaxExtension};
1717
use syntax_pos::Span;
1818

1919
use rustc::hir;
@@ -105,12 +105,12 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa
105105
record_extern_fqn(cx, did, clean::TypeKind::Const);
106106
clean::ConstantItem(build_const(cx, did))
107107
}
108-
// FIXME(misdreavus): if attributes/derives come down here we should probably document them
109-
// separately
108+
// FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty
110109
Def::Macro(did, MacroKind::Bang) => {
110+
let mac = build_macro(cx, did, name);
111+
if let clean::MacroItem(..) = mac {
111112
record_extern_fqn(cx, did, clean::TypeKind::Macro);
112-
if let Some(mac) = build_macro(cx, did, name) {
113-
clean::MacroItem(mac)
113+
mac
114114
} else {
115115
return None;
116116
}
@@ -442,14 +442,10 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static {
442442
}
443443
}
444444

445-
fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> Option<clean::Macro> {
445+
fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> clean::ItemEnum {
446446
let imported_from = cx.tcx.original_crate_name(did.krate);
447-
let def = match cx.cstore.load_macro_untracked(did, cx.sess()) {
448-
LoadedMacro::MacroDef(macro_def) => macro_def,
449-
// FIXME(jseyfried): document proc macro re-exports
450-
LoadedMacro::ProcMacro(..) => return None,
451-
};
452-
447+
match cx.cstore.load_macro_untracked(did, cx.sess()) {
448+
LoadedMacro::MacroDef(def) => {
453449
let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.node {
454450
let tts: Vec<_> = def.stream().into_trees().collect();
455451
tts.chunks(4).map(|arm| arm[0].span()).collect()
@@ -463,11 +459,25 @@ fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> Option<clean::Ma
463459
format!(" {} => {{ ... }};\n", span.to_src(cx))
464460
}).collect::<String>());
465461

466-
Some(clean::Macro {
462+
clean::MacroItem(clean::Macro {
467463
source,
468464
imported_from: Some(imported_from).clean(cx),
469465
})
470466
}
467+
LoadedMacro::ProcMacro(ext) => {
468+
let helpers = match &*ext {
469+
&SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) }
470+
_ => Vec::new(),
471+
};
472+
473+
clean::ProcMacroItem(clean::ProcMacro {
474+
kind: ext.kind(),
475+
helpers,
476+
})
477+
}
478+
}
479+
480+
}
471481

472482
/// A trait's generics clause actually contains all of the predicates for all of
473483
/// its associated types as well. We specifically move these clauses to the

src/librustdoc/clean/mod.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub use self::Visibility::{Public, Inherited};
2121
use rustc_target::spec::abi::Abi;
2222
use syntax::ast::{self, AttrStyle, Ident};
2323
use syntax::attr;
24+
use syntax::ext::base::MacroKind;
2425
use syntax::source_map::{dummy_spanned, Spanned};
2526
use syntax::ptr::P;
2627
use syntax::symbol::keywords::{self, Keyword};
@@ -527,6 +528,7 @@ pub enum ItemEnum {
527528
/// `type`s from an extern block
528529
ForeignTypeItem,
529530
MacroItem(Macro),
531+
ProcMacroItem(ProcMacro),
530532
PrimitiveItem(PrimitiveType),
531533
AssociatedConstItem(Type, Option<String>),
532534
AssociatedTypeItem(Vec<GenericBound>, Option<Type>),
@@ -588,6 +590,7 @@ impl Clean<Item> for doctree::Module {
588590
items.extend(self.traits.iter().map(|x| x.clean(cx)));
589591
items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
590592
items.extend(self.macros.iter().map(|x| x.clean(cx)));
593+
items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
591594

592595
// determine if we should display the inner contents or
593596
// the outer `mod` item for the source code.
@@ -2189,6 +2192,8 @@ pub enum TypeKind {
21892192
Typedef,
21902193
Foreign,
21912194
Macro,
2195+
Attr,
2196+
Derive,
21922197
}
21932198

21942199
pub trait GetDefId {
@@ -3725,7 +3730,12 @@ pub fn register_def(cx: &DocContext, def: Def) -> DefId {
37253730
Def::Static(i, _) => (i, TypeKind::Static),
37263731
Def::Variant(i) => (cx.tcx.parent_def_id(i).expect("cannot get parent def id"),
37273732
TypeKind::Enum),
3728-
Def::Macro(i, _) => (i, TypeKind::Macro),
3733+
Def::Macro(i, mac_kind) => match mac_kind {
3734+
MacroKind::Bang => (i, TypeKind::Macro),
3735+
MacroKind::Attr => (i, TypeKind::Attr),
3736+
MacroKind::Derive => (i, TypeKind::Derive),
3737+
MacroKind::ProcMacroStub => unreachable!(),
3738+
},
37293739
Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
37303740
Def::SelfTy(_, Some(impl_def_id)) => {
37313741
return impl_def_id
@@ -3780,6 +3790,30 @@ impl Clean<Item> for doctree::Macro {
37803790
}
37813791
}
37823792

3793+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3794+
pub struct ProcMacro {
3795+
pub kind: MacroKind,
3796+
pub helpers: Vec<String>,
3797+
}
3798+
3799+
impl Clean<Item> for doctree::ProcMacro {
3800+
fn clean(&self, cx: &DocContext) -> Item {
3801+
Item {
3802+
name: Some(self.name.clean(cx)),
3803+
attrs: self.attrs.clean(cx),
3804+
source: self.whence.clean(cx),
3805+
visibility: Some(Public),
3806+
stability: self.stab.clean(cx),
3807+
deprecation: self.depr.clean(cx),
3808+
def_id: cx.tcx.hir.local_def_id(self.id),
3809+
inner: ProcMacroItem(ProcMacro {
3810+
kind: self.kind,
3811+
helpers: self.helpers.clean(cx),
3812+
}),
3813+
}
3814+
}
3815+
}
3816+
37833817
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
37843818
pub struct Stability {
37853819
pub level: stability::StabilityLevel,

src/librustdoc/doctree.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub use self::StructType::*;
1515
use syntax::ast;
1616
use syntax::ast::{Name, NodeId};
1717
use syntax::attr;
18+
use syntax::ext::base::MacroKind;
1819
use syntax::ptr::P;
1920
use syntax::source_map::Spanned;
2021
use syntax_pos::{self, Span};
@@ -46,6 +47,7 @@ pub struct Module {
4647
pub impls: Vec<Impl>,
4748
pub foreigns: Vec<hir::ForeignMod>,
4849
pub macros: Vec<Macro>,
50+
pub proc_macros: Vec<ProcMacro>,
4951
pub is_crate: bool,
5052
}
5153

@@ -75,6 +77,7 @@ impl Module {
7577
impls : Vec::new(),
7678
foreigns : Vec::new(),
7779
macros : Vec::new(),
80+
proc_macros: Vec::new(),
7881
is_crate : false,
7982
}
8083
}
@@ -264,6 +267,17 @@ pub struct Import {
264267
pub whence: Span,
265268
}
266269

270+
pub struct ProcMacro {
271+
pub name: Name,
272+
pub id: NodeId,
273+
pub kind: MacroKind,
274+
pub helpers: Vec<Name>,
275+
pub attrs: hir::HirVec<ast::Attribute>,
276+
pub whence: Span,
277+
pub stab: Option<attr::Stability>,
278+
pub depr: Option<attr::Deprecation>,
279+
}
280+
267281
pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType {
268282
match *vdata {
269283
hir::VariantData::Struct(..) => Plain,

src/librustdoc/html/item_type.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//! Item types.
1212
1313
use std::fmt;
14+
use syntax::ext::base::MacroKind;
1415
use clean;
1516

1617
/// Item type. Corresponds to `clean::ItemEnum` variants.
@@ -19,6 +20,11 @@ use clean;
1920
/// discriminants. JavaScript then is used to decode them into the original value.
2021
/// Consequently, every change to this type should be synchronized to
2122
/// the `itemTypes` mapping table in `static/main.js`.
23+
///
24+
/// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and
25+
/// module headings. If you are adding to this enum and want to ensure that the sidebar also prints
26+
/// a heading, edit the listing in `html/render.rs`, function `sidebar_module`. This uses an
27+
/// ordering based on a helper function inside `item_module`, in the same file.
2228
#[derive(Copy, PartialEq, Clone, Debug)]
2329
pub enum ItemType {
2430
Module = 0,
@@ -44,6 +50,8 @@ pub enum ItemType {
4450
ForeignType = 20,
4551
Keyword = 21,
4652
Existential = 22,
53+
ProcAttribute = 23,
54+
ProcDerive = 24,
4755
}
4856

4957

@@ -88,6 +96,12 @@ impl<'a> From<&'a clean::Item> for ItemType {
8896
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
8997
clean::ForeignTypeItem => ItemType::ForeignType,
9098
clean::KeywordItem(..) => ItemType::Keyword,
99+
clean::ProcMacroItem(ref mac) => match mac.kind {
100+
MacroKind::Bang => ItemType::Macro,
101+
MacroKind::Attr => ItemType::ProcAttribute,
102+
MacroKind::Derive => ItemType::ProcDerive,
103+
MacroKind::ProcMacroStub => unreachable!(),
104+
}
91105
clean::StrippedItem(..) => unreachable!(),
92106
}
93107
}
@@ -108,6 +122,8 @@ impl From<clean::TypeKind> for ItemType {
108122
clean::TypeKind::Typedef => ItemType::Typedef,
109123
clean::TypeKind::Foreign => ItemType::ForeignType,
110124
clean::TypeKind::Macro => ItemType::Macro,
125+
clean::TypeKind::Attr => ItemType::ProcAttribute,
126+
clean::TypeKind::Derive => ItemType::ProcDerive,
111127
}
112128
}
113129
}
@@ -138,6 +154,8 @@ impl ItemType {
138154
ItemType::ForeignType => "foreigntype",
139155
ItemType::Keyword => "keyword",
140156
ItemType::Existential => "existential",
157+
ItemType::ProcAttribute => "attr",
158+
ItemType::ProcDerive => "derive",
141159
}
142160
}
143161

@@ -166,7 +184,9 @@ impl ItemType {
166184
ItemType::Constant |
167185
ItemType::AssociatedConst => NameSpace::Value,
168186

169-
ItemType::Macro => NameSpace::Macro,
187+
ItemType::Macro |
188+
ItemType::ProcAttribute |
189+
ItemType::ProcDerive => NameSpace::Macro,
170190

171191
ItemType::Keyword => NameSpace::Keyword,
172192
}

src/librustdoc/html/render.rs

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use externalfiles::ExternalHtml;
5656

5757
use serialize::json::{ToJson, Json, as_json};
5858
use syntax::ast;
59+
use syntax::ext::base::MacroKind;
5960
use syntax::source_map::FileName;
6061
use syntax::feature_gate::UnstableFeatures;
6162
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
@@ -1595,6 +1596,8 @@ struct AllTypes {
15951596
statics: FxHashSet<ItemEntry>,
15961597
constants: FxHashSet<ItemEntry>,
15971598
keywords: FxHashSet<ItemEntry>,
1599+
attributes: FxHashSet<ItemEntry>,
1600+
derives: FxHashSet<ItemEntry>,
15981601
}
15991602

16001603
impl AllTypes {
@@ -1613,6 +1616,8 @@ impl AllTypes {
16131616
statics: new_set(100),
16141617
constants: new_set(100),
16151618
keywords: new_set(100),
1619+
attributes: new_set(100),
1620+
derives: new_set(100),
16161621
}
16171622
}
16181623

@@ -1634,6 +1639,8 @@ impl AllTypes {
16341639
ItemType::Existential => self.existentials.insert(ItemEntry::new(new_url, name)),
16351640
ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
16361641
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
1642+
ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
1643+
ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
16371644
_ => true,
16381645
};
16391646
}
@@ -1673,6 +1680,8 @@ impl fmt::Display for AllTypes {
16731680
print_entries(f, &self.primitives, "Primitives", "primitives")?;
16741681
print_entries(f, &self.traits, "Traits", "traits")?;
16751682
print_entries(f, &self.macros, "Macros", "macros")?;
1683+
print_entries(f, &self.attributes, "Attribute Macros", "attributes")?;
1684+
print_entries(f, &self.derives, "Derive Macros", "derives")?;
16761685
print_entries(f, &self.functions, "Functions", "functions")?;
16771686
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
16781687
print_entries(f, &self.existentials, "Existentials", "existentials")?;
@@ -2155,6 +2164,12 @@ impl<'a> fmt::Display for Item<'a> {
21552164
clean::EnumItem(..) => write!(fmt, "Enum ")?,
21562165
clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
21572166
clean::MacroItem(..) => write!(fmt, "Macro ")?,
2167+
clean::ProcMacroItem(ref mac) => match mac.kind {
2168+
MacroKind::Bang => write!(fmt, "Macro ")?,
2169+
MacroKind::Attr => write!(fmt, "Attribute Macro ")?,
2170+
MacroKind::Derive => write!(fmt, "Derive Macro ")?,
2171+
MacroKind::ProcMacroStub => unreachable!(),
2172+
}
21582173
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
21592174
clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
21602175
clean::ConstantItem(..) => write!(fmt, "Constant ")?,
@@ -2191,6 +2206,7 @@ impl<'a> fmt::Display for Item<'a> {
21912206
clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e),
21922207
clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t),
21932208
clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m),
2209+
clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m),
21942210
clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p),
21952211
clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
21962212
item_static(fmt, self.cx, self.item, i),
@@ -4079,11 +4095,12 @@ impl<'a> fmt::Display for Sidebar<'a> {
40794095
write!(fmt,
40804096
"<div class='block version'>\
40814097
<p>Version {}</p>\
4082-
</div>
4083-
<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
4084-
version,
4085-
it.name.as_ref().unwrap())?;
4098+
</div>",
4099+
version)?;
40864100
}
4101+
4102+
write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
4103+
it.name.as_ref().expect("crates always have a name"))?;
40874104
}
40884105

40894106
write!(fmt, "<div class=\"sidebar-elems\">")?;
@@ -4523,6 +4540,8 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
45234540
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
45244541
ItemType::Keyword => ("keywords", "Keywords"),
45254542
ItemType::Existential => ("existentials", "Existentials"),
4543+
ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
4544+
ItemType::ProcDerive => ("derives", "Derive Macros"),
45264545
}
45274546
}
45284547

@@ -4598,6 +4617,39 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
45984617
document(w, cx, it)
45994618
}
46004619

4620+
fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &clean::ProcMacro)
4621+
-> fmt::Result
4622+
{
4623+
let name = it.name.as_ref().expect("proc-macros always have names");
4624+
match m.kind {
4625+
MacroKind::Bang => {
4626+
write!(w, "<pre class='rust macro'>")?;
4627+
write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
4628+
write!(w, "</pre>")?;
4629+
}
4630+
MacroKind::Attr => {
4631+
write!(w, "<pre class='rust attr'>")?;
4632+
write!(w, "#[{}]", name)?;
4633+
write!(w, "</pre>")?;
4634+
}
4635+
MacroKind::Derive => {
4636+
write!(w, "<pre class='rust derive'>")?;
4637+
write!(w, "#[derive({})]", name)?;
4638+
if !m.helpers.is_empty() {
4639+
writeln!(w, "\n{{")?;
4640+
writeln!(w, " // Attributes available to this derive:")?;
4641+
for attr in &m.helpers {
4642+
writeln!(w, " #[{}]", attr)?;
4643+
}
4644+
write!(w, "}}")?;
4645+
}
4646+
write!(w, "</pre>")?;
4647+
}
4648+
_ => {}
4649+
}
4650+
document(w, cx, it)
4651+
}
4652+
46014653
fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
46024654
it: &clean::Item,
46034655
_p: &clean::PrimitiveType) -> fmt::Result {

0 commit comments

Comments
 (0)