diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d58a88957df22..752918250d802 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -231,14 +231,11 @@ impl Clean for doctree::Module<'_> { let mut items: Vec = vec![]; items.extend(self.extern_crates.iter().flat_map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); - items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); - items.extend(self.items.iter().map(|x| x.clean(cx))); + items.extend(self.items.iter().map(|x| x.clean(cx)).flatten()); 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. @@ -872,6 +869,66 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx } } +fn clean_fn_or_proc_macro( + item: &hir::Item<'_>, + sig: &'a hir::FnSig<'a>, + generics: &'a hir::Generics<'a>, + body_id: hir::BodyId, + name: &mut Symbol, + cx: &DocContext<'_>, +) -> ItemKind { + let macro_kind = item.attrs.iter().find_map(|a| { + if a.has_name(sym::proc_macro) { + Some(MacroKind::Bang) + } else if a.has_name(sym::proc_macro_derive) { + Some(MacroKind::Derive) + } else if a.has_name(sym::proc_macro_attribute) { + Some(MacroKind::Attr) + } else { + None + } + }); + match macro_kind { + Some(kind) => { + if kind == MacroKind::Derive { + *name = item + .attrs + .lists(sym::proc_macro_derive) + .find_map(|mi| mi.ident()) + .expect("proc-macro derives require a name") + .name; + } + + let mut helpers = Vec::new(); + for mi in item.attrs.lists(sym::proc_macro_derive) { + if !mi.has_name(sym::attributes) { + continue; + } + + if let Some(list) = mi.meta_item_list() { + for inner_mi in list { + if let Some(ident) = inner_mi.ident() { + helpers.push(ident.name); + } + } + } + } + ProcMacroItem(ProcMacro { kind, helpers: helpers.clean(cx) }) + } + None => { + let mut func = (sig, generics, body_id).clean(cx); + let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id(); + func.header.constness = + if is_const_fn(cx.tcx, def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; + FunctionItem(func) + } + } +} + impl<'a> Clean for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) { fn clean(&self, cx: &DocContext<'_>) -> Function { let (generics, decl) = @@ -881,34 +938,6 @@ impl<'a> Clean for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::Bo } } -impl Clean for doctree::Function<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Item { - let (generics, decl) = - enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx))); - - let did = cx.tcx.hir().local_def_id(self.id).to_def_id(); - let constness = if is_const_fn(cx.tcx, did) && !is_unstable_const_fn(cx.tcx, did).is_some() - { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - let (all_types, ret_types) = get_all_types(&generics, &decl, cx); - Item::from_def_id_and_parts( - did, - Some(self.name), - FunctionItem(Function { - decl, - generics, - header: hir::FnHeader { constness, ..self.header }, - all_types, - ret_types, - }), - cx, - ) - } -} - impl<'a> Clean for (&'a [hir::Ty<'a>], &'a [Ident]) { fn clean(&self, cx: &DocContext<'_>) -> Arguments { Arguments { @@ -1922,13 +1951,13 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean for (&hir::Item<'_>, Option) { - fn clean(&self, cx: &DocContext<'_>) -> Item { +impl Clean> for (&hir::Item<'_>, Option) { + fn clean(&self, cx: &DocContext<'_>) -> Vec { use hir::ItemKind; let (item, renamed) = self; let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id(); - let name = match renamed { + let mut name = match renamed { Some(ident) => ident.name, None => cx.tcx.hir().name(item.hir_id), }; @@ -1977,10 +2006,15 @@ impl Clean for (&hir::Item<'_>, Option) { fields: variant_data.fields().clean(cx), fields_stripped: false, }), + ItemKind::Impl { .. } => return clean_impl(item, cx), + // proc macros can have a name set by attributes + ItemKind::Fn(ref sig, ref generics, body_id) => { + clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) + } _ => unreachable!("not yet converted"), }; - Item::from_def_id_and_parts(def_id, Some(name), kind, cx) + vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)] } } @@ -2005,57 +2039,53 @@ impl Clean for ty::ImplPolarity { } } -impl Clean> for doctree::Impl<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Vec { - let mut ret = Vec::new(); - let trait_ = self.trait_.clean(cx); - let items = self.items.iter().map(|ii| ii.clean(cx)).collect::>(); - let def_id = cx.tcx.hir().local_def_id(self.id); - - // If this impl block is an implementation of the Deref trait, then we - // need to try inlining the target's inherent impl blocks as well. - if trait_.def_id() == cx.tcx.lang_items().deref_trait() { - build_deref_target_impls(cx, &items, &mut ret); +fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec { + let mut ret = Vec::new(); + let (trait_, items, for_, unsafety, generics) = match &impl_.kind { + hir::ItemKind::Impl { of_trait, items, self_ty, unsafety, generics, .. } => { + (of_trait, items, self_ty, *unsafety, generics) } - - let provided: FxHashSet = trait_ - .def_id() - .map(|did| { - cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect() - }) - .unwrap_or_default(); - - let for_ = self.for_.clean(cx); - let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) { - DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)), - _ => None, + _ => unreachable!(), + }; + let trait_ = trait_.clean(cx); + let items = items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::>(); + let def_id = cx.tcx.hir().local_def_id(impl_.hir_id); + + // If this impl block is an implementation of the Deref trait, then we + // need to try inlining the target's inherent impl blocks as well. + if trait_.def_id() == cx.tcx.lang_items().deref_trait() { + build_deref_target_impls(cx, &items, &mut ret); + } + + let provided: FxHashSet = trait_ + .def_id() + .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()) + .unwrap_or_default(); + + let for_ = for_.clean(cx); + let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) { + DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)), + _ => None, + }); + let make_item = |trait_: Option, for_: Type, items: Vec| { + let kind = ImplItem(Impl { + unsafety, + generics: generics.clean(cx), + provided_trait_methods: provided.clone(), + trait_, + for_, + items, + polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), + synthetic: false, + blanket_impl: None, }); - let make_item = |trait_: Option, for_: Type, items: Vec| Item { - name: None, - attrs: self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: def_id.to_def_id(), - visibility: self.vis.clean(cx), - stability: cx.stability(self.id), - deprecation: cx.deprecation(self.id).clean(cx), - kind: ImplItem(Impl { - unsafety: self.unsafety, - generics: self.generics.clean(cx), - provided_trait_methods: provided.clone(), - trait_, - for_, - items, - polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), - synthetic: false, - blanket_impl: None, - }), - }; - if let Some(type_alias) = type_alias { - ret.push(make_item(trait_.clone(), type_alias, items.clone())); - } - ret.push(make_item(trait_, for_, items)); - ret + Item::from_hir_id_and_parts(impl_.hir_id, None, kind, cx) + }; + if let Some(type_alias) = type_alias { + ret.push(make_item(trait_.clone(), type_alias, items.clone())); } + ret.push(make_item(trait_, for_, items)); + ret } impl Clean> for doctree::ExternCrate<'_> { @@ -2190,11 +2220,12 @@ impl Clean> for doctree::Import<'_> { } } -impl Clean for doctree::ForeignItem<'_> { +impl Clean for (&hir::ForeignItem<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { - let kind = match self.kind { + let (item, renamed) = self; + let kind = match item.kind { hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => { - let abi = cx.tcx.hir().get_foreign_abi(self.id); + let abi = cx.tcx.hir().get_foreign_abi(item.hir_id); let (generics, decl) = enter_impl_trait(cx, || (generics.clean(cx), (&**decl, &names[..]).clean(cx))); let (all_types, ret_types) = get_all_types(&generics, &decl, cx); @@ -2211,15 +2242,13 @@ impl Clean for doctree::ForeignItem<'_> { ret_types, }) } - hir::ForeignItemKind::Static(ref ty, mutbl) => ForeignStaticItem(Static { - type_: ty.clean(cx), - mutability: *mutbl, - expr: String::new(), - }), + hir::ForeignItemKind::Static(ref ty, mutability) => { + ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: String::new() }) + } hir::ForeignItemKind::Type => ForeignTypeItem, }; - Item::from_hir_id_and_parts(self.id, Some(self.name), kind, cx) + Item::from_hir_id_and_parts(item.hir_id, Some(renamed.unwrap_or(item.ident).name), kind, cx) } } @@ -2244,17 +2273,6 @@ impl Clean for doctree::Macro { } } -impl Clean for doctree::ProcMacro { - fn clean(&self, cx: &DocContext<'_>) -> Item { - Item::from_hir_id_and_parts( - self.id, - Some(self.name), - ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }), - cx, - ) - } -} - impl Clean for attr::Deprecation { fn clean(&self, _: &DocContext<'_>) -> Deprecation { Deprecation { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 413f5bdf5214b..b7cc0f1945911 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_driver::abort_on_err; @@ -156,21 +155,6 @@ impl<'tcx> DocContext<'tcx> { def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) } } - - crate fn stability(&self, id: HirId) -> Option { - self.tcx - .hir() - .opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id())) - .cloned() - } - - crate fn deprecation(&self, id: HirId) -> Option { - self.tcx - .hir() - .opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id())) - } } /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors. diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d56328cc2aa08..c6c11164e7df1 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -3,7 +3,6 @@ crate use self::StructType::*; use rustc_ast as ast; -use rustc_span::hygiene::MacroKind; use rustc_span::{self, symbol::Ident, Span, Symbol}; use rustc_hir as hir; @@ -17,16 +16,13 @@ crate struct Module<'hir> { crate where_inner: Span, crate extern_crates: Vec>, crate imports: Vec>, - crate fns: Vec>, crate mods: Vec>, crate id: hir::HirId, // (item, renamed) crate items: Vec<(&'hir hir::Item<'hir>, Option)>, crate traits: Vec>, - crate impls: Vec>, - crate foreigns: Vec>, + crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, crate macros: Vec, - crate proc_macros: Vec, crate is_crate: bool, } @@ -40,14 +36,11 @@ impl Module<'hir> { attrs, extern_crates: Vec::new(), imports: Vec::new(), - fns: Vec::new(), mods: Vec::new(), items: Vec::new(), traits: Vec::new(), - impls: Vec::new(), foreigns: Vec::new(), macros: Vec::new(), - proc_macros: Vec::new(), is_crate: false, } } @@ -69,15 +62,6 @@ crate struct Variant<'hir> { crate def: &'hir hir::VariantData<'hir>, } -crate struct Function<'hir> { - crate decl: &'hir hir::FnDecl<'hir>, - crate id: hir::HirId, - crate name: Symbol, - crate header: hir::FnHeader, - crate generics: &'hir hir::Generics<'hir>, - crate body: hir::BodyId, -} - crate struct Trait<'hir> { crate is_auto: hir::IsAuto, crate unsafety: hir::Unsafety, @@ -89,28 +73,6 @@ crate struct Trait<'hir> { crate id: hir::HirId, } -#[derive(Debug)] -crate struct Impl<'hir> { - crate unsafety: hir::Unsafety, - crate polarity: hir::ImplPolarity, - crate defaultness: hir::Defaultness, - crate constness: hir::Constness, - crate generics: &'hir hir::Generics<'hir>, - crate trait_: &'hir Option>, - crate for_: &'hir hir::Ty<'hir>, - crate items: Vec<&'hir hir::ImplItem<'hir>>, - crate attrs: &'hir [ast::Attribute], - crate span: Span, - crate vis: &'hir hir::Visibility<'hir>, - crate id: hir::HirId, -} - -crate struct ForeignItem<'hir> { - crate id: hir::HirId, - crate name: Symbol, - crate kind: &'hir hir::ForeignItemKind<'hir>, -} - // For Macro we store the DefId instead of the NodeId, since we also create // these imported macro_rules (which only have a DUMMY_NODE_ID). crate struct Macro { @@ -141,13 +103,6 @@ crate struct Import<'hir> { crate span: Span, } -crate struct ProcMacro { - crate name: Symbol, - crate id: hir::HirId, - crate kind: MacroKind, - crate helpers: Vec, -} - crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { match *vdata { hir::VariantData::Struct(..) => Plain, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c55e5f7690c14..624d4d07cc031 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -9,7 +9,6 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Node; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; -use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, Span}; @@ -82,63 +81,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { module } - fn visit_fn( - &mut self, - om: &mut Module<'tcx>, - item: &'tcx hir::Item<'_>, - name: Symbol, - decl: &'tcx hir::FnDecl<'_>, - header: hir::FnHeader, - generics: &'tcx hir::Generics<'_>, - body: hir::BodyId, - ) { - debug!("visiting fn"); - let macro_kind = item.attrs.iter().find_map(|a| { - if a.has_name(sym::proc_macro) { - Some(MacroKind::Bang) - } else if a.has_name(sym::proc_macro_derive) { - Some(MacroKind::Derive) - } else if a.has_name(sym::proc_macro_attribute) { - Some(MacroKind::Attr) - } else { - None - } - }); - match macro_kind { - Some(kind) => { - let name = if kind == MacroKind::Derive { - item.attrs - .lists(sym::proc_macro_derive) - .find_map(|mi| mi.ident()) - .expect("proc-macro derives require a name") - .name - } else { - name - }; - - let mut helpers = Vec::new(); - for mi in item.attrs.lists(sym::proc_macro_derive) { - if !mi.has_name(sym::attributes) { - continue; - } - - if let Some(list) = mi.meta_item_list() { - for inner_mi in list { - if let Some(ident) = inner_mi.ident() { - helpers.push(ident.name); - } - } - } - } - - om.proc_macros.push(ProcMacro { name, id: item.hir_id, kind, helpers }); - } - None => { - om.fns.push(Function { id: item.hir_id, decl, name, generics, header, body }); - } - } - } - fn visit_mod_contents( &mut self, span: Span, @@ -370,10 +312,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Some(ident.name), )); } - hir::ItemKind::Fn(ref sig, ref gen, body) => { - self.visit_fn(om, item, ident.name, &sig.decl, sig.header, gen, body) - } - hir::ItemKind::Enum(..) + hir::ItemKind::Fn(..) + | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::TyAlias(..) @@ -401,37 +341,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.traits.push(t); } - hir::ItemKind::Impl { - unsafety, - polarity, - defaultness, - constness, - defaultness_span: _, - ref generics, - ref of_trait, - self_ty, - ref items, - } => { + hir::ItemKind::Impl { ref of_trait, .. } => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && of_trait.is_none() { - let items = - items.iter().map(|item| self.cx.tcx.hir().impl_item(item.id)).collect(); - let i = Impl { - unsafety, - polarity, - defaultness, - constness, - generics, - trait_: of_trait, - for_: self_ty, - items, - attrs: &item.attrs, - id: item.hir_id, - span: item.span, - vis: &item.vis, - }; - om.impls.push(i); + om.items.push((item, None)); } } } @@ -444,15 +358,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om: &mut Module<'tcx>, ) { // If inlining we only want to include public functions. - if self.inlining && !item.vis.node.is_pub() { - return; + if !self.inlining || item.vis.node.is_pub() { + om.foreigns.push((item, renamed)); } - - om.foreigns.push(ForeignItem { - id: item.hir_id, - name: renamed.unwrap_or(item.ident).name, - kind: &item.kind, - }); } // Convert each `exported_macro` into a doc item. diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 31e7fc48afde5..be98cac94ece7 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -106,6 +106,15 @@ LL | /// [S!] | this link resolves to the struct `S`, which is not in the macro namespace | help: to link to the struct, prefix with `struct@`: `struct@S` +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:78:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `h`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `S::h()` + error: unresolved link to `T::g` --> $DIR/intra-link-errors.rs:86:6 | @@ -121,15 +130,6 @@ error: unresolved link to `T::h` LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` -error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:78:6 - | -LL | /// [type@S::h] - | ^^^^^^^^^ - | | - | this link resolves to the associated function `h`, which is not in the type namespace - | help: to link to the associated function, add parentheses: `S::h()` - error: unresolved link to `m` --> $DIR/intra-link-errors.rs:98:6 | diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index bf437a7cf4674..0b074e9d53e3d 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -36,6 +36,14 @@ warning: unresolved link to `Qux::Z` LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ no item named `Qux` in scope +warning: unresolved link to `Qux:Y` + --> $DIR/intra-links-warning.rs:14:13 + | +LL | /// [Qux:Y] + | ^^^^^ no item named `Qux:Y` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | @@ -90,14 +98,6 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -warning: unresolved link to `Qux:Y` - --> $DIR/intra-links-warning.rs:14:13 - | -LL | /// [Qux:Y] - | ^^^^^ no item named `Qux:Y` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 |