@@ -200,16 +200,27 @@ impl ExternalCrate {
200200 }
201201
202202 pub ( crate ) fn keywords ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , Symbol ) > {
203+ self . retrieve_keywords_or_documented_attributes ( tcx, sym:: keyword)
204+ }
205+ pub ( crate ) fn documented_attributes ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , Symbol ) > {
206+ self . retrieve_keywords_or_documented_attributes ( tcx, sym:: attribute)
207+ }
208+
209+ fn retrieve_keywords_or_documented_attributes (
210+ & self ,
211+ tcx : TyCtxt < ' _ > ,
212+ name : Symbol ,
213+ ) -> ThinVec < ( DefId , Symbol ) > {
203214 let root = self . def_id ( ) ;
204215
205- let as_keyword = |res : Res < !> | {
216+ let as_target = |res : Res < !> | {
206217 if let Res :: Def ( DefKind :: Mod , def_id) = res {
207218 let mut keyword = None ;
208219 let meta_items = tcx
209220 . get_attrs ( def_id, sym:: doc)
210221 . flat_map ( |attr| attr. meta_item_list ( ) . unwrap_or_default ( ) ) ;
211222 for meta in meta_items {
212- if meta. has_name ( sym :: keyword )
223+ if meta. has_name ( name )
213224 && let Some ( v) = meta. value_str ( )
214225 {
215226 keyword = Some ( v) ;
@@ -228,14 +239,14 @@ impl ExternalCrate {
228239 let item = tcx. hir_item ( id) ;
229240 match item. kind {
230241 hir:: ItemKind :: Mod ( ..) => {
231- as_keyword ( Res :: Def ( DefKind :: Mod , id. owner_id . to_def_id ( ) ) )
242+ as_target ( Res :: Def ( DefKind :: Mod , id. owner_id . to_def_id ( ) ) )
232243 }
233244 _ => None ,
234245 }
235246 } )
236247 . collect ( )
237248 } else {
238- tcx. module_children ( root) . iter ( ) . map ( |item| item. res ) . filter_map ( as_keyword ) . collect ( )
249+ tcx. module_children ( root) . iter ( ) . map ( |item| item. res ) . filter_map ( as_target ) . collect ( )
239250 }
240251 }
241252
@@ -597,6 +608,9 @@ impl Item {
597608 pub ( crate ) fn is_keyword ( & self ) -> bool {
598609 self . type_ ( ) == ItemType :: Keyword
599610 }
611+ pub ( crate ) fn is_attribute ( & self ) -> bool {
612+ self . type_ ( ) == ItemType :: Attribute
613+ }
600614 pub ( crate ) fn is_stripped ( & self ) -> bool {
601615 match self . kind {
602616 StrippedItem ( ..) => true ,
@@ -727,7 +741,9 @@ impl Item {
727741 // Primitives and Keywords are written in the source code as private modules.
728742 // The modules need to be private so that nobody actually uses them, but the
729743 // keywords and primitives that they are documenting are public.
730- ItemKind :: KeywordItem | ItemKind :: PrimitiveItem ( _) => return Some ( Visibility :: Public ) ,
744+ ItemKind :: KeywordItem | ItemKind :: PrimitiveItem ( _) | ItemKind :: AttributeItem => {
745+ return Some ( Visibility :: Public ) ;
746+ }
731747 // Variant fields inherit their enum's visibility.
732748 StructFieldItem ( ..) if is_field_vis_inherited ( tcx, def_id) => {
733749 return None ;
@@ -943,7 +959,12 @@ pub(crate) enum ItemKind {
943959 AssocTypeItem ( Box < TypeAlias > , Vec < GenericBound > ) ,
944960 /// An item that has been stripped by a rustdoc pass
945961 StrippedItem ( Box < ItemKind > ) ,
962+ /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used
963+ /// to generate documentation for Rust keywords.
946964 KeywordItem ,
965+ /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used
966+ /// to generate documentation for Rust builtin attributes.
967+ AttributeItem ,
947968}
948969
949970impl ItemKind {
@@ -984,7 +1005,8 @@ impl ItemKind {
9841005 | RequiredAssocTypeItem ( ..)
9851006 | AssocTypeItem ( ..)
9861007 | StrippedItem ( _)
987- | KeywordItem => [ ] . iter ( ) ,
1008+ | KeywordItem
1009+ | AttributeItem => [ ] . iter ( ) ,
9881010 }
9891011 }
9901012
0 commit comments