@@ -226,15 +226,28 @@ impl ExternalCrate {
226226    } 
227227
228228    pub ( crate )  fn  keywords ( & self ,  tcx :  TyCtxt < ' _ > )  -> impl  Iterator < Item  = ( DefId ,  Symbol ) >  { 
229-         fn  as_keyword ( did :  DefId ,  tcx :  TyCtxt < ' _ > )  -> Option < ( DefId ,  Symbol ) >  { 
229+         self . retrieve_keywords_or_documented_attributes ( tcx,  sym:: keyword) 
230+     } 
231+     pub ( crate )  fn  documented_attributes ( 
232+         & self , 
233+         tcx :  TyCtxt < ' _ > , 
234+     )  -> impl  Iterator < Item  = ( DefId ,  Symbol ) >  { 
235+         self . retrieve_keywords_or_documented_attributes ( tcx,  sym:: attribute) 
236+     } 
237+ 
238+     fn  retrieve_keywords_or_documented_attributes ( 
239+         & self , 
240+         tcx :  TyCtxt < ' _ > , 
241+         name :  Symbol , 
242+     )  -> impl  Iterator < Item  = ( DefId ,  Symbol ) >  { 
243+         let  as_target = move  |did :  DefId ,  tcx :  TyCtxt < ' _ > | -> Option < ( DefId ,  Symbol ) >  { 
230244            tcx. get_attrs ( did,  sym:: doc) 
231245                . flat_map ( |attr| attr. meta_item_list ( ) . unwrap_or_default ( ) ) 
232-                 . filter ( |meta| meta. has_name ( sym :: keyword ) ) 
246+                 . filter ( |meta| meta. has_name ( name ) ) 
233247                . find_map ( |meta| meta. value_str ( ) ) 
234248                . map ( |value| ( did,  value) ) 
235-         } 
236- 
237-         self . mapped_root_modules ( tcx,  as_keyword) 
249+         } ; 
250+         self . mapped_root_modules ( tcx,  as_target) 
238251    } 
239252
240253    pub ( crate )  fn  primitives ( 
@@ -592,6 +605,9 @@ impl Item {
592605    pub ( crate )  fn  is_keyword ( & self )  -> bool  { 
593606        self . type_ ( )  == ItemType :: Keyword 
594607    } 
608+     pub ( crate )  fn  is_attribute ( & self )  -> bool  { 
609+         self . type_ ( )  == ItemType :: Attribute 
610+     } 
595611    pub ( crate )  fn  is_stripped ( & self )  -> bool  { 
596612        match  self . kind  { 
597613            StrippedItem ( ..)  => true , 
@@ -735,7 +751,9 @@ impl Item {
735751            // Primitives and Keywords are written in the source code as private modules. 
736752            // The modules need to be private so that nobody actually uses them, but the 
737753            // keywords and primitives that they are documenting are public. 
738-             ItemKind :: KeywordItem  | ItemKind :: PrimitiveItem ( _)  => return  Some ( Visibility :: Public ) , 
754+             ItemKind :: KeywordItem  | ItemKind :: PrimitiveItem ( _)  | ItemKind :: AttributeItem  => { 
755+                 return  Some ( Visibility :: Public ) ; 
756+             } 
739757            // Variant fields inherit their enum's visibility. 
740758            StructFieldItem ( ..)  if  is_field_vis_inherited ( tcx,  def_id)  => { 
741759                return  None ; 
@@ -942,7 +960,12 @@ pub(crate) enum ItemKind {
942960AssocTypeItem ( Box < TypeAlias > ,  Vec < GenericBound > ) , 
943961    /// An item that has been stripped by a rustdoc pass 
944962StrippedItem ( Box < ItemKind > ) , 
963+     /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used 
964+ /// to generate documentation for Rust keywords. 
945965KeywordItem , 
966+     /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used 
967+ /// to generate documentation for Rust builtin attributes. 
968+ AttributeItem , 
946969} 
947970
948971impl  ItemKind  { 
@@ -983,7 +1006,8 @@ impl ItemKind {
9831006            | RequiredAssocTypeItem ( ..) 
9841007            | AssocTypeItem ( ..) 
9851008            | StrippedItem ( _) 
986-             | KeywordItem  => [ ] . iter ( ) , 
1009+             | KeywordItem 
1010+             | AttributeItem  => [ ] . iter ( ) , 
9871011        } 
9881012    } 
9891013
0 commit comments