@@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
3
3
use crate :: rmeta:: table:: TableBuilder ;
4
4
use crate :: rmeta:: * ;
5
5
6
+ use rustc_ast:: util:: comments;
6
7
use rustc_ast:: Attribute ;
7
8
use rustc_data_structures:: fingerprint:: Fingerprint ;
8
9
use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
@@ -759,36 +760,54 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
759
760
}
760
761
}
761
762
763
+ struct AnalyzeAttrState {
764
+ is_exported : bool ,
765
+ may_have_doc_links : bool ,
766
+ is_doc_hidden : bool ,
767
+ }
768
+
762
769
/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
763
770
/// useful in downstream crates. Local-only attributes are an obvious example, but some
764
771
/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
765
772
///
766
773
/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
767
774
///
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
769
776
/// visibility: this is a piece of data that can be computed once per defid, and not once per
770
777
/// attribute. Some attributes would only be usable downstream if they are public.
771
778
#[ 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 ;
778
781
if rustc_feature:: is_builtin_only_local ( attr. name_or_empty ( ) ) {
779
782
// 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
+ }
785
793
} 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
+ }
789
807
} else {
790
- true
808
+ should_encode = true ;
791
809
}
810
+ should_encode
792
811
}
793
812
794
813
fn should_encode_visibility ( def_kind : DefKind ) -> bool {
@@ -1108,24 +1127,24 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
1108
1127
impl < ' a , ' tcx > EncodeContext < ' a , ' tcx > {
1109
1128
fn encode_attrs ( & mut self , def_id : LocalDefId ) {
1110
1129
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) )
1115
1138
. 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) ;
1117
1142
1118
- record_array ! ( self . tables. attributes[ def_id. to_def_id( ) ] <- attrs. clone( ) ) ;
1119
1143
let mut attr_flags = AttrFlags :: empty ( ) ;
1120
- if attrs . any ( |attr| attr . may_have_doc_links ( ) ) {
1144
+ if state . may_have_doc_links {
1121
1145
attr_flags |= AttrFlags :: MAY_HAVE_DOC_LINKS ;
1122
1146
}
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 {
1129
1148
attr_flags |= AttrFlags :: IS_DOC_HIDDEN ;
1130
1149
}
1131
1150
if !attr_flags. is_empty ( ) {
0 commit comments