@@ -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 } ;
@@ -759,36 +760,54 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
759760 }
760761}
761762
763+ struct AnalyzeAttrState {
764+ is_exported : bool ,
765+ may_have_doc_links : bool ,
766+ is_doc_hidden : bool ,
767+ }
768+
762769/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
763770/// useful in downstream crates. Local-only attributes are an obvious example, but some
764771/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
765772///
766773/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
767774///
768- /// Note: the `is_def_id_public ` parameter is used to cache whether the given `DefId` has a public
775+ /// Note: the `is_exported ` parameter is used to cache whether the given `DefId` has a public
769776/// visibility: this is a piece of data that can be computed once per defid, and not once per
770777/// attribute. Some attributes would only be usable downstream if they are public.
771778#[ inline]
772- fn should_encode_attr (
773- tcx : TyCtxt < ' _ > ,
774- attr : & Attribute ,
775- def_id : LocalDefId ,
776- is_def_id_public : & mut Option < bool > ,
777- ) -> bool {
779+ fn analyze_attr ( attr : & Attribute , state : & mut AnalyzeAttrState ) -> bool {
780+ let mut should_encode = false ;
778781 if rustc_feature:: is_builtin_only_local ( attr. name_or_empty ( ) ) {
779782 // Attributes marked local-only don't need to be encoded for downstream crates.
780- false
781- } else if attr. doc_str ( ) . is_some ( ) {
782- // We keep all public doc comments because they might be "imported" into downstream crates
783- // if they use `#[doc(inline)]` to copy an item's documentation into their own.
784- * is_def_id_public. get_or_insert_with ( || tcx. effective_visibilities ( ( ) ) . is_exported ( def_id) )
783+ } else if let Some ( s) = attr. doc_str ( ) {
784+ // We keep all doc comments reachable to rustdoc because they might be "imported" into
785+ // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into
786+ // their own.
787+ if state. is_exported {
788+ should_encode = true ;
789+ if comments:: may_have_doc_links ( s. as_str ( ) ) {
790+ state. may_have_doc_links = true ;
791+ }
792+ }
785793 } else if attr. has_name ( sym:: doc) {
786- // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
787- // remove it. It won't be inlinable in downstream crates.
788- attr. meta_item_list ( ) . map ( |l| l. iter ( ) . any ( |l| !l. has_name ( sym:: inline) ) ) . unwrap_or ( false )
794+ // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in
795+ // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates.
796+ if let Some ( item_list) = attr. meta_item_list ( ) {
797+ for item in item_list {
798+ if !item. has_name ( sym:: inline) {
799+ should_encode = true ;
800+ if item. has_name ( sym:: hidden) {
801+ state. is_doc_hidden = true ;
802+ break ;
803+ }
804+ }
805+ }
806+ }
789807 } else {
790- true
808+ should_encode = true ;
791809 }
810+ should_encode
792811}
793812
794813fn should_encode_visibility ( def_kind : DefKind ) -> bool {
@@ -1108,24 +1127,24 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
11081127impl < ' a , ' tcx > EncodeContext < ' a , ' tcx > {
11091128 fn encode_attrs ( & mut self , def_id : LocalDefId ) {
11101129 let tcx = self . tcx ;
1111- let mut is_public: Option < bool > = None ;
1112-
1113- let hir_attrs = tcx. hir ( ) . attrs ( tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ) ;
1114- let mut attrs = hir_attrs
1130+ let mut state = AnalyzeAttrState {
1131+ is_exported : tcx. effective_visibilities ( ( ) ) . is_exported ( def_id) ,
1132+ may_have_doc_links : false ,
1133+ is_doc_hidden : false ,
1134+ } ;
1135+ let attr_iter = tcx
1136+ . hir ( )
1137+ . attrs ( tcx. hir ( ) . local_def_id_to_hir_id ( def_id) )
11151138 . iter ( )
1116- . filter ( move |attr| should_encode_attr ( tcx, attr, def_id, & mut is_public) ) ;
1139+ . filter ( |attr| analyze_attr ( attr, & mut state) ) ;
1140+
1141+ record_array ! ( self . tables. attributes[ def_id. to_def_id( ) ] <- attr_iter) ;
11171142
1118- record_array ! ( self . tables. attributes[ def_id. to_def_id( ) ] <- attrs. clone( ) ) ;
11191143 let mut attr_flags = AttrFlags :: empty ( ) ;
1120- if attrs . any ( |attr| attr . may_have_doc_links ( ) ) {
1144+ if state . may_have_doc_links {
11211145 attr_flags |= AttrFlags :: MAY_HAVE_DOC_LINKS ;
11221146 }
1123- if hir_attrs
1124- . iter ( )
1125- . filter ( |attr| attr. has_name ( sym:: doc) )
1126- . filter_map ( |attr| attr. meta_item_list ( ) )
1127- . any ( |items| items. iter ( ) . any ( |item| item. has_name ( sym:: hidden) ) )
1128- {
1147+ if state. is_doc_hidden {
11291148 attr_flags |= AttrFlags :: IS_DOC_HIDDEN ;
11301149 }
11311150 if !attr_flags. is_empty ( ) {
0 commit comments