@@ -17,8 +17,8 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
1717use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
1818use rustc_data_structures:: thin_vec:: ThinVec ;
1919use 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 } ;
2222use rustc_hir:: lang_items:: LangItem ;
2323use rustc_hir:: { BodyId , Mutability } ;
2424use rustc_index:: vec:: IndexVec ;
@@ -72,11 +72,138 @@ crate struct TraitWithExtraInfo {
7272
7373#[ derive( Clone , Debug ) ]
7474crate struct ExternalCrate {
75- crate name : Symbol ,
76- crate src : FileName ,
75+ crate crate_num : CrateNum ,
7776 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+ }
80207}
81208
82209/// Anything with a source location and set of attributes and, optionally, a
0 commit comments