From b4f1dfd2c57985a4cbb74fb34073ba04fd6f5f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Delabrouille?= Date: Fri, 23 Apr 2021 22:15:13 +0200 Subject: [PATCH 1/2] Removed usage of Attributes in FnDecl and ExternalCrate. Relocate part of the fields in Attributes, as functions in AttributesExt. refacto use from_def_id_and_attrs_and_parts instead of an old trick most of josha suggestions + check if def_id is not fake before using it in a query Removed usage of Attributes in FnDecl and ExternalCrate. Relocate part of the Attributes fields as functions in AttributesExt. --- src/librustdoc/clean/inline.rs | 3 +- src/librustdoc/clean/mod.rs | 7 +-- src/librustdoc/clean/types.rs | 50 ++++++++++--------- src/librustdoc/core.rs | 2 +- src/librustdoc/doctest.rs | 11 ++-- src/librustdoc/formats/cache.rs | 8 +-- src/librustdoc/html/render/cache.rs | 9 ++-- src/librustdoc/html/render/context.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- .../passes/collect_intra_doc_links.rs | 19 ++++--- src/librustdoc/passes/strip_hidden.rs | 4 +- 11 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e88a739d04296..0f74639cbc65c 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -124,8 +124,7 @@ crate fn try_inline( let attrs = box merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone); cx.inlined.insert(did); - let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx); - ret.push(clean::Item { attrs, ..what_rustc_thinks }); + ret.push(clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, attrs, cx)); Some(ret) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c0a8c88bdeba0..d1a6f8d0c24fc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -84,9 +84,8 @@ impl, U> Clean> for Option { } impl Clean for CrateNum { - fn clean(&self, cx: &mut DocContext<'_>) -> ExternalCrate { - let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; - ExternalCrate { crate_num: *self, attrs: cx.tcx.get_attrs(root).clean(cx) } + fn clean(&self, _cx: &mut DocContext<'_>) -> ExternalCrate { + ExternalCrate { crate_num: *self } } } @@ -850,7 +849,6 @@ where inputs: (self.0.inputs, self.1).clean(cx), output: self.0.output.clean(cx), c_variadic: self.0.c_variadic, - attrs: Attributes::default(), } } } @@ -862,7 +860,6 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { FnDecl { output: Return(sig.skip_binder().output().clean(cx)), - attrs: Attributes::default(), c_variadic: sig.skip_binder().c_variadic, inputs: Arguments { values: sig diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 607a634c1bced..788b421c7cac9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -73,7 +73,6 @@ crate struct TraitWithExtraInfo { #[derive(Clone, Debug)] crate struct ExternalCrate { crate crate_num: CrateNum, - crate attrs: Attributes, } impl ExternalCrate { @@ -663,12 +662,35 @@ impl<'a> Iterator for ListAttributesIter<'a> { crate trait AttributesExt { /// Finds an attribute as List and returns the list of attributes nested inside. fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; + + fn span(&self) -> Option; + + fn inner_docs(&self) -> bool; + + fn other_attrs(&self) -> Vec; } impl AttributesExt for [ast::Attribute] { fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name } } + + /// Return the span of the first doc-comment, if it exists. + fn span(&self) -> Option { + self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span) + } + + /// Returns whether the first doc-comment is an inner attribute. + /// + //// If there are no doc-comments, return true. + /// FIXME(#78591): Support both inner and outer attributes on the same item. + fn inner_docs(&self) -> bool { + self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner) + } + + fn other_attrs(&self) -> Vec { + self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() + } } crate trait NestedAttributesExt { @@ -778,8 +800,6 @@ crate struct Attributes { crate doc_strings: Vec, crate other_attrs: Vec, crate cfg: Option>, - crate span: Option, - crate inner_docs: bool, } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] @@ -811,6 +831,10 @@ pub struct RenderedLink { } impl Attributes { + crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { + self.other_attrs.lists(name) + } + /// Extracts the content from an attribute `#[doc(cfg(content))]`. crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { use rustc_ast::NestedMetaItem::MetaItem; @@ -895,7 +919,6 @@ impl Attributes { additional_attrs: Option<(&[ast::Attribute], DefId)>, ) -> Attributes { let mut doc_strings: Vec = vec![]; - let mut sp = None; let mut cfg = Cfg::True; let mut doc_line = 0; @@ -940,9 +963,6 @@ impl Attributes { doc_strings.push(frag); - if sp.is_none() { - sp = Some(attr.span); - } None } else { if attr.has_name(sym::doc) { @@ -1001,17 +1021,10 @@ impl Attributes { } } - let inner_docs = attrs - .iter() - .find(|a| a.doc_str().is_some()) - .map_or(true, |a| a.style == AttrStyle::Inner); - Attributes { doc_strings, other_attrs, cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, - span: sp, - inner_docs, } } @@ -1079,7 +1092,6 @@ impl PartialEq for Attributes { fn eq(&self, rhs: &Self) -> bool { self.doc_strings == rhs.doc_strings && self.cfg == rhs.cfg - && self.span == rhs.span && self .other_attrs .iter() @@ -1094,19 +1106,12 @@ impl Hash for Attributes { fn hash(&self, hasher: &mut H) { self.doc_strings.hash(hasher); self.cfg.hash(hasher); - self.span.hash(hasher); for attr in &self.other_attrs { attr.id.hash(hasher); } } } -impl AttributesExt for Attributes { - fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { - self.other_attrs.lists(name) - } -} - #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifier), @@ -1269,7 +1274,6 @@ crate struct FnDecl { crate inputs: Arguments, crate output: FnRetTy, crate c_variadic: bool, - crate attrs: Attributes, } impl FnDecl { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index be7bff1a29c2b..212aac0e5b43c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,7 +32,7 @@ use std::rc::Rc; use crate::clean; use crate::clean::inline::build_external_trait; -use crate::clean::{AttributesExt, TraitWithExtraInfo, MAX_DEF_IDX}; +use crate::clean::{TraitWithExtraInfo, MAX_DEF_IDX}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; use crate::passes::{self, Condition::*, ConditionalPass}; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 6f6ed0eb68413..b51655ea2031b 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -26,7 +26,7 @@ use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; -use crate::clean::Attributes; +use crate::clean::{types::AttributesExt, Attributes}; use crate::config::Options; use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; use crate::lint::init_lints; @@ -1092,8 +1092,9 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { sp: Span, nested: F, ) { - let attrs = self.tcx.hir().attrs(hir_id); - let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs, None); + let ast_attrs = self.tcx.hir().attrs(hir_id); + + let mut attrs = Attributes::from_ast(self.sess.diagnostic(), ast_attrs, None); if let Some(ref cfg) = attrs.cfg { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; @@ -1110,8 +1111,8 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { // anything else, this will combine them for us. if let Some(doc) = attrs.collapsed_doc_value() { // Use the outermost invocation, so that doctest names come from where the docs were written. - let span = attrs - .span + let span = ast_attrs + .span() .map(|span| span.ctxt().outer_expn().expansion_cause().unwrap_or(span)) .unwrap_or(DUMMY_SP); self.collector.set_position(span); diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9a61f963a3ec3..8f8bca64e1497 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -164,10 +164,12 @@ impl Cache { }; let name = e.name(tcx); let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); - self.extern_locations - .insert(n, (name, src_root, extern_location(e, extern_url, &dst, tcx))); - let did = DefId { krate: n, index: CRATE_DEF_INDEX }; + self.extern_locations.insert( + n, + (name, src_root, extern_location(e, extern_url, tcx.get_attrs(did), &dst, tcx)), + ); + self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index f93a0d4fc2d72..d1aa6fba463d9 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -1,15 +1,17 @@ use std::collections::BTreeMap; use std::path::Path; +use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; use serde::ser::{Serialize, SerializeStruct, Serializer}; +use crate::clean; use crate::clean::types::{ - FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate, + AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, TypeKind, + WherePredicate, }; -use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::markdown::short_markdown_summary; @@ -30,6 +32,7 @@ crate enum ExternalLocation { crate fn extern_location( e: &clean::ExternalCrate, extern_url: Option<&str>, + ast_attrs: &[ast::Attribute], dst: &Path, tcx: TyCtxt<'_>, ) -> ExternalLocation { @@ -50,7 +53,7 @@ crate fn extern_location( // Failing that, see if there's an attribute specifying where to find this // external crate - e.attrs + ast_attrs .lists(sym::doc) .filter(|a| a.has_name(sym::html_root_url)) .filter_map(|a| a.value_str()) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 6d45ed69c1232..4c8ba0e7b496e 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -18,7 +18,7 @@ use super::print_item::{full_path, item_path, print_item}; use super::write_shared::write_shared; use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS}; -use crate::clean::{self, AttributesExt}; +use crate::clean; use crate::config::RenderOptions; use crate::docfs::{DocFS, PathError}; use crate::error::Error; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 42cd765c294b1..3d5dc7dbec050 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -421,7 +421,7 @@ impl FromWithTcx for FunctionPointer { impl FromWithTcx for FnDecl { fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self { - let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl; + let clean::FnDecl { inputs, output, c_variadic } = decl; FnDecl { inputs: inputs .values diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index dad6593248dae..7f479b62c908a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2,6 +2,7 @@ //! //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md +use clean::AttributesExt; use rustc_ast as ast; use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -853,7 +854,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } }); - if item.is_mod() && item.attrs.inner_docs { + let inner_docs = match self_id { + Some(did) => self.cx.tcx.get_attrs(did).inner_docs(), + None => false, + }; + + if item.is_mod() && inner_docs { self.mod_ids.push(item.def_id); } @@ -880,7 +886,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } Some(if item.is_mod() { - if !item.attrs.inner_docs { + if !inner_docs { self.mod_ids.push(item.def_id); } @@ -1050,6 +1056,8 @@ impl LinkCollector<'_, '_> { }; let mut path_str = &*path_str; + let inner_docs = self.cx.tcx.get_attrs(item.def_id).inner_docs(); + // In order to correctly resolve intra-doc links we need to // pick a base AST node to work from. If the documentation for // this module came from an inner comment (//!) then we anchor @@ -1061,11 +1069,8 @@ impl LinkCollector<'_, '_> { // we've already pushed this node onto the resolution stack but // for outer comments we explicitly try and resolve against the // parent_node first. - let base_node = if item.is_mod() && item.attrs.inner_docs { - self.mod_ids.last().copied() - } else { - parent_node - }; + let base_node = + if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node }; let mut module_id = if let Some(id) = base_node { id diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index c742d32cb62ea..54c4ed22f1c4b 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,8 +2,8 @@ use rustc_hir::def_id::DefIdSet; use rustc_span::symbol::sym; use std::mem; -use crate::clean::Item; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; +use crate::clean; +use crate::clean::{Item, NestedAttributesExt}; use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; use crate::passes::{ImplStripper, Pass}; From 727f9040aac16dfa5a27687f6f49b7cd5b98a2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Delabrouille?= Date: Sun, 25 Apr 2021 18:17:11 +0200 Subject: [PATCH 2/2] cfg taken out of Attributes, put in Item check item.is_fake() instead of self_id.is_some() Remove empty branching in Attributes::from_ast diverse small refacto after Josha review cfg computation moved in merge_attrs refacto use from_ast twice for coherence take cfg out of Attributes and move it to Item --- src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/blanket_impl.rs | 1 + src/librustdoc/clean/inline.rs | 46 ++++++---- src/librustdoc/clean/mod.rs | 6 +- src/librustdoc/clean/types.rs | 90 +++++++++++-------- src/librustdoc/doctest.rs | 4 +- src/librustdoc/html/render/cache.rs | 3 +- src/librustdoc/html/render/mod.rs | 9 +- src/librustdoc/html/render/print_item.rs | 15 ++-- src/librustdoc/json/conversions.rs | 2 +- .../passes/collect_intra_doc_links.rs | 8 +- src/librustdoc/passes/propagate_doc_cfg.rs | 4 +- 12 files changed, 104 insertions(+), 85 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 010059a89c9b1..92eb6214f79fe 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -126,6 +126,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { synthetic: true, blanket_impl: None, }), + cfg: None, }) } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 50c0fb85d5aa0..3a14a1d23f2d4 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -128,6 +128,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { synthetic: false, blanket_impl: Some(trait_ref.self_ty().clean(self.cx)), }), + cfg: None, }); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0f74639cbc65c..674bf1a5814e1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -1,6 +1,7 @@ //! Support for inlining external documentation into the current AST. use std::iter::once; +use std::sync::Arc; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; @@ -15,7 +16,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use crate::clean::{self, Attributes, GetDefId, ToSource}; +use crate::clean::{self, Attributes, AttributesExt, GetDefId, ToSource}; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -120,11 +121,16 @@ crate fn try_inline( _ => return None, }; - let target_attrs = load_attrs(cx, did); - let attrs = box merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone); - + let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone); cx.inlined.insert(did); - ret.push(clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, attrs, cx)); + ret.push(clean::Item::from_def_id_and_attrs_and_parts( + did, + Some(name), + kind, + box attrs, + cx, + cfg, + )); Some(ret) } @@ -288,22 +294,24 @@ fn merge_attrs( parent_module: Option, old_attrs: Attrs<'_>, new_attrs: Option>, -) -> clean::Attributes { +) -> (clean::Attributes, Option>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. if let Some(inner) = new_attrs { - if let Some(new_id) = parent_module { - let diag = cx.sess().diagnostic(); - Attributes::from_ast(diag, old_attrs, Some((inner, new_id))) - } else { - let mut both = inner.to_vec(); - both.extend_from_slice(old_attrs); - both.clean(cx) - } + let mut both = inner.to_vec(); + both.extend_from_slice(old_attrs); + ( + if let Some(new_id) = parent_module { + Attributes::from_ast(old_attrs, Some((inner, new_id))) + } else { + Attributes::from_ast(&both, None) + }, + both.cfg(cx.sess().diagnostic()), + ) } else { - old_attrs.clean(cx) + (old_attrs.clean(cx), old_attrs.cfg(cx.sess().diagnostic())) } } @@ -414,8 +422,8 @@ crate fn build_impl( debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); - let attrs = box merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); - debug!("merged_attrs={:?}", attrs); + let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); + debug!("merged_attrs={:?}", merged_attrs); ret.push(clean::Item::from_def_id_and_attrs_and_parts( did, @@ -432,8 +440,9 @@ crate fn build_impl( synthetic: false, blanket_impl: None, }), - attrs, + box merged_attrs, cx, + cfg, )); } @@ -479,6 +488,7 @@ fn build_module( }, true, )), + cfg: None, }); } else if let Some(i) = try_inline(cx, did, item.res, item.ident.name, None, visited) { items.extend(i) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d1a6f8d0c24fc..60c5d68b7a0b6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -122,8 +122,8 @@ impl Clean for doctree::Module<'_> { } impl Clean for [ast::Attribute] { - fn clean(&self, cx: &mut DocContext<'_>) -> Attributes { - Attributes::from_ast(cx.sess().diagnostic(), self, None) + fn clean(&self, _cx: &mut DocContext<'_>) -> Attributes { + Attributes::from_ast(self, None) } } @@ -1998,6 +1998,7 @@ fn clean_extern_crate( return items; } } + // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason vec![Item { name: Some(name), @@ -2005,6 +2006,7 @@ fn clean_extern_crate( def_id: crate_def_id, visibility: krate.vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, + cfg: attrs.cfg(cx.sess().diagnostic()), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 788b421c7cac9..5e47144588b3f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -219,11 +219,13 @@ crate struct Item { /// E.g., struct vs enum vs function. crate kind: Box, crate def_id: DefId, + + crate cfg: Option>, } // `Item` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Item, 40); +rustc_data_structures::static_assert_size!(Item, 48); impl fmt::Debug for Item { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -235,6 +237,7 @@ impl fmt::Debug for Item { .field("kind", &self.kind) .field("visibility", &self.visibility) .field("def_id", def_id) + .field("cfg", &self.cfg) .finish() } } @@ -262,6 +265,10 @@ impl Item { if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) } } + crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { + if self.is_fake() { false } else { tcx.get_attrs(self.def_id).inner_docs() } + } + crate fn span(&self, tcx: TyCtxt<'_>) -> Span { let kind = match &*self.kind { ItemKind::StrippedItem(k) => k, @@ -305,12 +312,15 @@ impl Item { kind: ItemKind, cx: &mut DocContext<'_>, ) -> Item { + let ast_attrs = cx.tcx.get_attrs(def_id); + Self::from_def_id_and_attrs_and_parts( def_id, name, kind, - box cx.tcx.get_attrs(def_id).clean(cx), + box ast_attrs.clean(cx), cx, + ast_attrs.cfg(cx.sess().diagnostic()), ) } @@ -320,6 +330,7 @@ impl Item { kind: ItemKind, attrs: Box, cx: &mut DocContext<'_>, + cfg: Option>, ) -> Item { debug!("name={:?}, def_id={:?}", name, def_id); @@ -329,6 +340,7 @@ impl Item { name, attrs, visibility: cx.tcx.visibility(def_id).clean(cx), + cfg, } } @@ -668,6 +680,8 @@ crate trait AttributesExt { fn inner_docs(&self) -> bool; fn other_attrs(&self) -> Vec; + + fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -691,6 +705,41 @@ impl AttributesExt for [ast::Attribute] { fn other_attrs(&self) -> Vec { self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } + + fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option> { + let mut cfg = Cfg::True; + + for attr in self.iter() { + if attr.doc_str().is_none() && attr.has_name(sym::doc) { + if let Some(mi) = attr.meta() { + if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { + // Extracted #[doc(cfg(...))] + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg &= new_cfg, + Err(e) => diagnostic.span_err(e.span, e.msg), + } + } + } + } + } + + for attr in self.lists(sym::target_feature) { + if attr.has_name(sym::enable) { + if let Some(feat) = attr.value_str() { + let meta = attr::mk_name_value_item_str( + Ident::with_dummy_span(sym::target_feature), + feat, + DUMMY_SP, + ); + if let Ok(feat_cfg) = Cfg::parse(&meta) { + cfg &= feat_cfg; + } + } + } + } + + if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } + } } crate trait NestedAttributesExt { @@ -799,7 +848,6 @@ impl<'a> FromIterator<&'a DocFragment> for String { crate struct Attributes { crate doc_strings: Vec, crate other_attrs: Vec, - crate cfg: Option>, } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] @@ -914,12 +962,10 @@ impl Attributes { } crate fn from_ast( - diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute], additional_attrs: Option<(&[ast::Attribute], DefId)>, ) -> Attributes { let mut doc_strings: Vec = vec![]; - let mut cfg = Cfg::True; let mut doc_line = 0; fn update_need_backline(doc_strings: &mut Vec, frag: &DocFragment) { @@ -967,14 +1013,7 @@ impl Attributes { } else { if attr.has_name(sym::doc) { if let Some(mi) = attr.meta() { - if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { - // Extracted #[doc(cfg(...))] - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => diagnostic.span_err(e.span, e.msg), - } - } else if let Some((filename, contents)) = Attributes::extract_include(&mi) - { + if let Some((filename, contents)) = Attributes::extract_include(&mi) { let line = doc_line; doc_line += contents.as_str().lines().count(); let frag = DocFragment { @@ -1004,28 +1043,7 @@ impl Attributes { .filter_map(clean_attr) .collect(); - // treat #[target_feature(enable = "feat")] attributes as if they were - // #[doc(cfg(target_feature = "feat"))] attributes as well - for attr in attrs.lists(sym::target_feature) { - if attr.has_name(sym::enable) { - if let Some(feat) = attr.value_str() { - let meta = attr::mk_name_value_item_str( - Ident::with_dummy_span(sym::target_feature), - feat, - DUMMY_SP, - ); - if let Ok(feat_cfg) = Cfg::parse(&meta) { - cfg &= feat_cfg; - } - } - } - } - - Attributes { - doc_strings, - other_attrs, - cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, - } + Attributes { doc_strings, other_attrs } } /// Finds the `doc` attribute as a NameValue and returns the corresponding @@ -1091,7 +1109,6 @@ impl Attributes { impl PartialEq for Attributes { fn eq(&self, rhs: &Self) -> bool { self.doc_strings == rhs.doc_strings - && self.cfg == rhs.cfg && self .other_attrs .iter() @@ -1105,7 +1122,6 @@ impl Eq for Attributes {} impl Hash for Attributes { fn hash(&self, hasher: &mut H) { self.doc_strings.hash(hasher); - self.cfg.hash(hasher); for attr in &self.other_attrs { attr.id.hash(hasher); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index b51655ea2031b..466d1b65406cd 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1093,9 +1093,9 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { nested: F, ) { let ast_attrs = self.tcx.hir().attrs(hir_id); + let mut attrs = Attributes::from_ast(ast_attrs, None); - let mut attrs = Attributes::from_ast(self.sess.diagnostic(), ast_attrs, None); - if let Some(ref cfg) = attrs.cfg { + if let Some(ref cfg) = ast_attrs.cfg(self.sess.diagnostic()) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index d1aa6fba463d9..f4296a04e5921 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -9,8 +9,7 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; use crate::clean::types::{ - AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, TypeKind, - WherePredicate, + AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate, }; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 67ccf2137bf6e..248bd46da8573 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -608,17 +608,12 @@ fn document_item_info( } fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option { - let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) { + let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) { (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), (cfg, _) => cfg.as_deref().cloned(), }; - debug!( - "Portability {:?} - {:?} = {:?}", - item.attrs.cfg, - parent.and_then(|p| p.attrs.cfg.as_ref()), - cfg - ); + debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg); Some(format!("
{}
", cfg?.render_long_html())) } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f1d79ab097b9f..1bb1db00e8825 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,10 +1,11 @@ +use clean::AttributesExt; + use std::cmp::Ordering; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; -use rustc_middle::dep_graph::DepContext; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; @@ -284,16 +285,14 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl clean::ImportItem(ref import) => { let (stab, stab_tags) = if let Some(import_def_id) = import.source.did { - let import_attrs = Box::new(clean::Attributes::from_ast( - cx.tcx().sess().diagnostic(), - cx.tcx().get_attrs(import_def_id), - None, - )); + let ast_attrs = cx.tcx().get_attrs(import_def_id); + let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None)); // Just need an item with the correct def_id and attrs let import_item = clean::Item { def_id: import_def_id, attrs: import_attrs, + cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()), ..myitem.clone() }; @@ -400,12 +399,12 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> tags += &tag_html("unstable", "", "Experimental"); } - let cfg = match (&item.attrs.cfg, parent.attrs.cfg.as_ref()) { + let cfg = match (&item.cfg, parent.cfg.as_ref()) { (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), (cfg, _) => cfg.as_deref().cloned(), }; - debug!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg); + debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.cfg, cfg); if let Some(ref cfg) = cfg { tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 3d5dc7dbec050..2d8c347c3c167 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -41,7 +41,7 @@ impl JsonRenderer<'_> { .map(rustc_ast_pretty::pprust::attribute_to_string) .collect(); let span = item.span(self.tcx); - let clean::Item { name, attrs: _, kind: _, visibility, def_id } = item; + let clean::Item { name, attrs: _, kind: _, visibility, def_id, cfg: _ } = item; let inner = match *item.kind { clean::StrippedItem(_) => return None, _ => from_clean_item(item, self.tcx), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7f479b62c908a..f1064756fdde7 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2,7 +2,6 @@ //! //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md -use clean::AttributesExt; use rustc_ast as ast; use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -854,10 +853,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } }); - let inner_docs = match self_id { - Some(did) => self.cx.tcx.get_attrs(did).inner_docs(), - None => false, - }; + let inner_docs = item.inner_docs(self.cx.tcx); if item.is_mod() && inner_docs { self.mod_ids.push(item.def_id); @@ -1056,7 +1052,7 @@ impl LinkCollector<'_, '_> { }; let mut path_str = &*path_str; - let inner_docs = self.cx.tcx.get_attrs(item.def_id).inner_docs(); + let inner_docs = item.inner_docs(self.cx.tcx); // In order to correctly resolve intra-doc links we need to // pick a base AST node to work from. If the documentation for diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 2369ff78b1ce0..f5a362bfbe8c6 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -24,7 +24,7 @@ impl DocFolder for CfgPropagator { fn fold_item(&mut self, mut item: Item) -> Option { let old_parent_cfg = self.parent_cfg.clone(); - let new_cfg = match (self.parent_cfg.take(), item.attrs.cfg.take()) { + let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) { (None, None) => None, (Some(rc), None) | (None, Some(rc)) => Some(rc), (Some(mut a), Some(b)) => { @@ -34,7 +34,7 @@ impl DocFolder for CfgPropagator { } }; self.parent_cfg = new_cfg.clone(); - item.attrs.cfg = new_cfg; + item.cfg = new_cfg; let result = self.fold_item_recur(item); self.parent_cfg = old_parent_cfg;