@@ -17,8 +17,8 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
17
17
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
18
18
use rustc_data_structures:: thin_vec:: ThinVec ;
19
19
use rustc_hir as hir;
20
- use rustc_hir:: def:: { CtorKind , Res } ;
21
- use rustc_hir:: def_id:: { CrateNum , DefId , DefIndex } ;
20
+ use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
21
+ use rustc_hir:: def_id:: { CrateNum , DefId , DefIndex , CRATE_DEF_INDEX } ;
22
22
use rustc_hir:: lang_items:: LangItem ;
23
23
use rustc_hir:: { BodyId , Mutability } ;
24
24
use rustc_index:: vec:: IndexVec ;
@@ -74,7 +74,6 @@ crate struct TraitWithExtraInfo {
74
74
crate struct ExternalCrate {
75
75
crate crate_num : CrateNum ,
76
76
crate attrs : Attributes ,
77
- crate primitives : ThinVec < ( DefId , PrimitiveType ) > ,
78
77
crate keywords : ThinVec < ( DefId , Symbol ) > ,
79
78
}
80
79
@@ -88,6 +87,75 @@ impl ExternalCrate {
88
87
crate fn name ( & self , tcx : TyCtxt < ' _ > ) -> Symbol {
89
88
tcx. crate_name ( self . crate_num )
90
89
}
90
+
91
+ crate fn primitives ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , PrimitiveType ) > {
92
+ let root = DefId { krate : self . crate_num , index : CRATE_DEF_INDEX } ;
93
+
94
+ // Collect all inner modules which are tagged as implementations of
95
+ // primitives.
96
+ //
97
+ // Note that this loop only searches the top-level items of the crate,
98
+ // and this is intentional. If we were to search the entire crate for an
99
+ // item tagged with `#[doc(primitive)]` then we would also have to
100
+ // search the entirety of external modules for items tagged
101
+ // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
102
+ // all that metadata unconditionally).
103
+ //
104
+ // In order to keep the metadata load under control, the
105
+ // `#[doc(primitive)]` feature is explicitly designed to only allow the
106
+ // primitive tags to show up as the top level items in a crate.
107
+ //
108
+ // Also note that this does not attempt to deal with modules tagged
109
+ // duplicately for the same primitive. This is handled later on when
110
+ // rendering by delegating everything to a hash map.
111
+ let as_primitive = |res : Res | {
112
+ if let Res :: Def ( DefKind :: Mod , def_id) = res {
113
+ let attrs = tcx. get_attrs ( def_id) ;
114
+ let mut prim = None ;
115
+ for attr in attrs. lists ( sym:: doc) {
116
+ if let Some ( v) = attr. value_str ( ) {
117
+ if attr. has_name ( sym:: primitive) {
118
+ prim = PrimitiveType :: from_symbol ( v) ;
119
+ if prim. is_some ( ) {
120
+ break ;
121
+ }
122
+ // FIXME: should warn on unknown primitives?
123
+ }
124
+ }
125
+ }
126
+ return prim. map ( |p| ( def_id, p) ) ;
127
+ }
128
+ None
129
+ } ;
130
+
131
+ if root. is_local ( ) {
132
+ tcx. hir ( )
133
+ . krate ( )
134
+ . item
135
+ . item_ids
136
+ . iter ( )
137
+ . filter_map ( |& id| {
138
+ let item = tcx. hir ( ) . item ( id) ;
139
+ match item. kind {
140
+ hir:: ItemKind :: Mod ( _) => {
141
+ as_primitive ( Res :: Def ( DefKind :: Mod , id. def_id . to_def_id ( ) ) )
142
+ }
143
+ hir:: ItemKind :: Use ( ref path, hir:: UseKind :: Single )
144
+ if item. vis . node . is_pub ( ) =>
145
+ {
146
+ as_primitive ( path. res ) . map ( |( _, prim) | {
147
+ // Pretend the primitive is local.
148
+ ( id. def_id . to_def_id ( ) , prim)
149
+ } )
150
+ }
151
+ _ => None ,
152
+ }
153
+ } )
154
+ . collect ( )
155
+ } else {
156
+ tcx. item_children ( root) . iter ( ) . map ( |item| item. res ) . filter_map ( as_primitive) . collect ( )
157
+ }
158
+ }
91
159
}
92
160
93
161
/// Anything with a source location and set of attributes and, optionally, a
0 commit comments