@@ -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 } ;
@@ -760,36 +761,54 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
760
761
}
761
762
}
762
763
764
+ struct AnalyzeAttrState {
765
+ is_exported : bool ,
766
+ may_have_doc_links : bool ,
767
+ is_doc_hidden : bool ,
768
+ }
769
+
763
770
/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
764
771
/// useful in downstream crates. Local-only attributes are an obvious example, but some
765
772
/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
766
773
///
767
774
/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
768
775
///
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
770
777
/// visibility: this is a piece of data that can be computed once per defid, and not once per
771
778
/// attribute. Some attributes would only be usable downstream if they are public.
772
779
#[ 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 ;
779
782
if rustc_feature:: is_builtin_only_local ( attr. name_or_empty ( ) ) {
780
783
// 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
+ }
786
794
} 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
+ }
790
808
} else {
791
- true
809
+ should_encode = true ;
792
810
}
811
+ should_encode
793
812
}
794
813
795
814
fn should_encode_visibility ( def_kind : DefKind ) -> bool {
@@ -1109,24 +1128,24 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
1109
1128
impl < ' a , ' tcx > EncodeContext < ' a , ' tcx > {
1110
1129
fn encode_attrs ( & mut self , def_id : LocalDefId ) {
1111
1130
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) )
1116
1139
. 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) ;
1118
1143
1119
- record_array ! ( self . tables. attributes[ def_id. to_def_id( ) ] <- attrs. clone( ) ) ;
1120
1144
let mut attr_flags = AttrFlags :: empty ( ) ;
1121
- if attrs . any ( |attr| attr . may_have_doc_links ( ) ) {
1145
+ if state . may_have_doc_links {
1122
1146
attr_flags |= AttrFlags :: MAY_HAVE_DOC_LINKS ;
1123
1147
}
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 {
1130
1149
attr_flags |= AttrFlags :: IS_DOC_HIDDEN ;
1131
1150
}
1132
1151
if !attr_flags. is_empty ( ) {
0 commit comments