@@ -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 ;
@@ -74,7 +74,6 @@ crate struct TraitWithExtraInfo {
7474crate struct ExternalCrate {
7575 crate crate_num : CrateNum ,
7676 crate attrs : Attributes ,
77- crate primitives : ThinVec < ( DefId , PrimitiveType ) > ,
7877 crate keywords : ThinVec < ( DefId , Symbol ) > ,
7978}
8079
@@ -88,6 +87,75 @@ impl ExternalCrate {
8887 crate fn name ( & self , tcx : TyCtxt < ' _ > ) -> Symbol {
8988 tcx. crate_name ( self . crate_num )
9089 }
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+ }
91159}
92160
93161/// Anything with a source location and set of attributes and, optionally, a
0 commit comments