@@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
33use crate :: rmeta:: table:: TableBuilder ;
44use crate :: rmeta:: * ;
55
6+ use rustc_ast:: util:: comments;
67use rustc_ast:: Attribute ;
78use rustc_data_structures:: fingerprint:: Fingerprint ;
89use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
@@ -760,36 +761,54 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
760761 }
761762}
762763
764+ struct AnalyzeAttrState {
765+ is_exported : bool ,
766+ may_have_doc_links : bool ,
767+ is_doc_hidden : bool ,
768+ }
769+
763770/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
764771/// useful in downstream crates. Local-only attributes are an obvious example, but some
765772/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
766773///
767774/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
768775///
769- /// Note: the `is_def_id_public ` parameter is used to cache whether the given `DefId` has a public
776+ /// Note: the `is_exported ` parameter is used to cache whether the given `DefId` has a public
770777/// visibility: this is a piece of data that can be computed once per defid, and not once per
771778/// attribute. Some attributes would only be usable downstream if they are public.
772779#[ inline]
773- fn should_encode_attr (
774- tcx : TyCtxt < ' _ > ,
775- attr : & Attribute ,
776- def_id : LocalDefId ,
777- is_def_id_public : & mut Option < bool > ,
778- ) -> bool {
780+ fn analyze_attr ( attr : & Attribute , state : & mut AnalyzeAttrState ) -> bool {
781+ let mut should_encode = false ;
779782 if rustc_feature:: is_builtin_only_local ( attr. name_or_empty ( ) ) {
780783 // Attributes marked local-only don't need to be encoded for downstream crates.
781- false
782- } else if attr. doc_str ( ) . is_some ( ) {
783- // We keep all public doc comments because they might be "imported" into downstream crates
784- // if they use `#[doc(inline)]` to copy an item's documentation into their own.
785- * is_def_id_public. get_or_insert_with ( || tcx. effective_visibilities ( ( ) ) . is_exported ( def_id) )
784+ } else if let Some ( s) = attr. doc_str ( ) {
785+ // We keep all doc comments reachable to rustdoc because they might be "imported" into
786+ // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into
787+ // their own.
788+ if state. is_exported {
789+ should_encode = true ;
790+ if comments:: may_have_doc_links ( s. as_str ( ) ) {
791+ state. may_have_doc_links = true ;
792+ }
793+ }
786794 } else if attr. has_name ( sym:: doc) {
787- // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
788- // remove it. It won't be inlinable in downstream crates.
789- attr. meta_item_list ( ) . map ( |l| l. iter ( ) . any ( |l| !l. has_name ( sym:: inline) ) ) . unwrap_or ( false )
795+ // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in
796+ // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates.
797+ if let Some ( item_list) = attr. meta_item_list ( ) {
798+ for item in item_list {
799+ if !item. has_name ( sym:: inline) {
800+ should_encode = true ;
801+ if item. has_name ( sym:: hidden) {
802+ state. is_doc_hidden = true ;
803+ break ;
804+ }
805+ }
806+ }
807+ }
790808 } else {
791- true
809+ should_encode = true ;
792810 }
811+ should_encode
793812}
794813
795814fn should_encode_visibility ( def_kind : DefKind ) -> bool {
@@ -1109,24 +1128,24 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
11091128impl < ' a , ' tcx > EncodeContext < ' a , ' tcx > {
11101129 fn encode_attrs ( & mut self , def_id : LocalDefId ) {
11111130 let tcx = self . tcx ;
1112- let mut is_public: Option < bool > = None ;
1113-
1114- let hir_attrs = tcx. hir ( ) . attrs ( tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ) ;
1115- let mut attrs = hir_attrs
1131+ let mut state = AnalyzeAttrState {
1132+ is_exported : tcx. effective_visibilities ( ( ) ) . is_exported ( def_id) ,
1133+ may_have_doc_links : false ,
1134+ is_doc_hidden : false ,
1135+ } ;
1136+ let attr_iter = tcx
1137+ . hir ( )
1138+ . attrs ( tcx. hir ( ) . local_def_id_to_hir_id ( def_id) )
11161139 . iter ( )
1117- . filter ( move |attr| should_encode_attr ( tcx, attr, def_id, & mut is_public) ) ;
1140+ . filter ( |attr| analyze_attr ( attr, & mut state) ) ;
1141+
1142+ record_array ! ( self . tables. attributes[ def_id. to_def_id( ) ] <- attr_iter) ;
11181143
1119- record_array ! ( self . tables. attributes[ def_id. to_def_id( ) ] <- attrs. clone( ) ) ;
11201144 let mut attr_flags = AttrFlags :: empty ( ) ;
1121- if attrs . any ( |attr| attr . may_have_doc_links ( ) ) {
1145+ if state . may_have_doc_links {
11221146 attr_flags |= AttrFlags :: MAY_HAVE_DOC_LINKS ;
11231147 }
1124- if hir_attrs
1125- . iter ( )
1126- . filter ( |attr| attr. has_name ( sym:: doc) )
1127- . filter_map ( |attr| attr. meta_item_list ( ) )
1128- . any ( |items| items. iter ( ) . any ( |item| item. has_name ( sym:: hidden) ) )
1129- {
1148+ if state. is_doc_hidden {
11301149 attr_flags |= AttrFlags :: IS_DOC_HIDDEN ;
11311150 }
11321151 if !attr_flags. is_empty ( ) {
0 commit comments