@@ -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 ;
@@ -72,11 +72,138 @@ crate struct TraitWithExtraInfo {
72
72
73
73
#[ derive( Clone , Debug ) ]
74
74
crate struct ExternalCrate {
75
- crate name : Symbol ,
76
- crate src : FileName ,
75
+ crate crate_num : CrateNum ,
77
76
crate attrs : Attributes ,
78
- crate primitives : ThinVec < ( DefId , PrimitiveType ) > ,
79
- crate keywords : ThinVec < ( DefId , Symbol ) > ,
77
+ }
78
+
79
+ impl ExternalCrate {
80
+ #[ inline]
81
+ fn def_id ( & self ) -> DefId {
82
+ DefId { krate : self . crate_num , index : CRATE_DEF_INDEX }
83
+ }
84
+
85
+ crate fn src ( & self , tcx : TyCtxt < ' _ > ) -> FileName {
86
+ let krate_span = tcx. def_span ( self . def_id ( ) ) ;
87
+ tcx. sess . source_map ( ) . span_to_filename ( krate_span)
88
+ }
89
+
90
+ crate fn name ( & self , tcx : TyCtxt < ' _ > ) -> Symbol {
91
+ tcx. crate_name ( self . crate_num )
92
+ }
93
+
94
+ crate fn keywords ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , Symbol ) > {
95
+ let root = self . def_id ( ) ;
96
+
97
+ let as_keyword = |res : Res | {
98
+ if let Res :: Def ( DefKind :: Mod , def_id) = res {
99
+ let attrs = tcx. get_attrs ( def_id) ;
100
+ let mut keyword = None ;
101
+ for attr in attrs. lists ( sym:: doc) {
102
+ if attr. has_name ( sym:: keyword) {
103
+ if let Some ( v) = attr. value_str ( ) {
104
+ keyword = Some ( v) ;
105
+ break ;
106
+ }
107
+ }
108
+ }
109
+ return keyword. map ( |p| ( def_id, p) ) ;
110
+ }
111
+ None
112
+ } ;
113
+ if root. is_local ( ) {
114
+ tcx. hir ( )
115
+ . krate ( )
116
+ . item
117
+ . item_ids
118
+ . iter ( )
119
+ . filter_map ( |& id| {
120
+ let item = tcx. hir ( ) . item ( id) ;
121
+ match item. kind {
122
+ hir:: ItemKind :: Mod ( _) => {
123
+ as_keyword ( Res :: Def ( DefKind :: Mod , id. def_id . to_def_id ( ) ) )
124
+ }
125
+ hir:: ItemKind :: Use ( ref path, hir:: UseKind :: Single )
126
+ if item. vis . node . is_pub ( ) =>
127
+ {
128
+ as_keyword ( path. res ) . map ( |( _, prim) | ( id. def_id . to_def_id ( ) , prim) )
129
+ }
130
+ _ => None ,
131
+ }
132
+ } )
133
+ . collect ( )
134
+ } else {
135
+ tcx. item_children ( root) . iter ( ) . map ( |item| item. res ) . filter_map ( as_keyword) . collect ( )
136
+ }
137
+ }
138
+
139
+ crate fn primitives ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , PrimitiveType ) > {
140
+ let root = self . def_id ( ) ;
141
+
142
+ // Collect all inner modules which are tagged as implementations of
143
+ // primitives.
144
+ //
145
+ // Note that this loop only searches the top-level items of the crate,
146
+ // and this is intentional. If we were to search the entire crate for an
147
+ // item tagged with `#[doc(primitive)]` then we would also have to
148
+ // search the entirety of external modules for items tagged
149
+ // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
150
+ // all that metadata unconditionally).
151
+ //
152
+ // In order to keep the metadata load under control, the
153
+ // `#[doc(primitive)]` feature is explicitly designed to only allow the
154
+ // primitive tags to show up as the top level items in a crate.
155
+ //
156
+ // Also note that this does not attempt to deal with modules tagged
157
+ // duplicately for the same primitive. This is handled later on when
158
+ // rendering by delegating everything to a hash map.
159
+ let as_primitive = |res : Res | {
160
+ if let Res :: Def ( DefKind :: Mod , def_id) = res {
161
+ let attrs = tcx. get_attrs ( def_id) ;
162
+ let mut prim = None ;
163
+ for attr in attrs. lists ( sym:: doc) {
164
+ if let Some ( v) = attr. value_str ( ) {
165
+ if attr. has_name ( sym:: primitive) {
166
+ prim = PrimitiveType :: from_symbol ( v) ;
167
+ if prim. is_some ( ) {
168
+ break ;
169
+ }
170
+ // FIXME: should warn on unknown primitives?
171
+ }
172
+ }
173
+ }
174
+ return prim. map ( |p| ( def_id, p) ) ;
175
+ }
176
+ None
177
+ } ;
178
+
179
+ if root. is_local ( ) {
180
+ tcx. hir ( )
181
+ . krate ( )
182
+ . item
183
+ . item_ids
184
+ . iter ( )
185
+ . filter_map ( |& id| {
186
+ let item = tcx. hir ( ) . item ( id) ;
187
+ match item. kind {
188
+ hir:: ItemKind :: Mod ( _) => {
189
+ as_primitive ( Res :: Def ( DefKind :: Mod , id. def_id . to_def_id ( ) ) )
190
+ }
191
+ hir:: ItemKind :: Use ( ref path, hir:: UseKind :: Single )
192
+ if item. vis . node . is_pub ( ) =>
193
+ {
194
+ as_primitive ( path. res ) . map ( |( _, prim) | {
195
+ // Pretend the primitive is local.
196
+ ( id. def_id . to_def_id ( ) , prim)
197
+ } )
198
+ }
199
+ _ => None ,
200
+ }
201
+ } )
202
+ . collect ( )
203
+ } else {
204
+ tcx. item_children ( root) . iter ( ) . map ( |item| item. res ) . filter_map ( as_primitive) . collect ( )
205
+ }
206
+ }
80
207
}
81
208
82
209
/// Anything with a source location and set of attributes and, optionally, a
0 commit comments