33use std:: env;
44use std:: sync:: Arc ;
55
6+ use rustc_ast_pretty:: pprust;
67use rustc_data_structures:: fx:: FxHashSet ;
78use rustc_hir:: def_id:: { CRATE_DEF_ID , LocalDefId } ;
89use rustc_hir:: { self as hir, CRATE_HIR_ID , intravisit} ;
910use rustc_middle:: hir:: nested_filter;
1011use rustc_middle:: ty:: TyCtxt ;
1112use rustc_resolve:: rustdoc:: span_of_fragments;
1213use rustc_span:: source_map:: SourceMap ;
13- use rustc_span:: { BytePos , DUMMY_SP , FileName , Pos , Span } ;
14+ use rustc_span:: { BytePos , DUMMY_SP , FileName , Pos , Span , sym } ;
1415
1516use super :: { DocTestVisitor , ScrapedDocTest } ;
1617use crate :: clean:: { Attributes , extract_cfg_from_attrs} ;
@@ -21,6 +22,7 @@ struct RustCollector {
2122 tests : Vec < ScrapedDocTest > ,
2223 cur_path : Vec < String > ,
2324 position : Span ,
25+ global_crate_attrs : Vec < String > ,
2426}
2527
2628impl RustCollector {
@@ -54,6 +56,7 @@ impl DocTestVisitor for RustCollector {
5456 self . cur_path . clone ( ) ,
5557 config,
5658 test,
59+ self . global_crate_attrs . clone ( ) ,
5760 ) ) ;
5861 }
5962
@@ -73,6 +76,7 @@ impl<'tcx> HirCollector<'tcx> {
7376 cur_path : vec ! [ ] ,
7477 position : DUMMY_SP ,
7578 tests : vec ! [ ] ,
79+ global_crate_attrs : Vec :: new ( ) ,
7680 } ;
7781 Self { codes, tcx, collector }
7882 }
@@ -149,6 +153,46 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
149153 self . tcx
150154 }
151155
156+ fn visit_mod ( & mut self , m : & ' tcx hir:: Mod < ' tcx > , _s : Span , hir_id : hir:: HirId ) {
157+ let attrs = self . tcx . hir_attrs ( hir_id) ;
158+
159+ if !attrs. is_empty ( ) {
160+ // Try collecting `#![doc(test(attr(...)))]` from the attribute module
161+ //
162+ // We do it in 2 steps since the first `meta_item_list` returns owned
163+ // `MetaItemInner` instead of reference to them.
164+ let test_attrs: Vec < _ > = attrs
165+ . iter ( )
166+ . filter ( |a| a. has_name ( sym:: doc) )
167+ . flat_map ( |a| a. meta_item_list ( ) . unwrap_or_default ( ) )
168+ . filter ( |a| a. has_name ( sym:: test) )
169+ . collect ( ) ;
170+ let additional_global_crate_attrs: Vec < _ > = test_attrs
171+ . iter ( )
172+ . flat_map ( |a| a. meta_item_list ( ) . unwrap_or_default ( ) )
173+ . filter ( |a| a. has_name ( sym:: attr) )
174+ . flat_map ( |a| a. meta_item_list ( ) . unwrap_or_default ( ) )
175+ . map ( |i| pprust:: meta_list_item_to_string ( i) )
176+ . collect ( ) ;
177+
178+ if additional_global_crate_attrs. is_empty ( ) {
179+ intravisit:: walk_mod ( self , m)
180+ } else {
181+ // Add the additional attributes to the global_crate_attrs vector
182+ let old_len = self . collector . global_crate_attrs . len ( ) ;
183+ self . collector . global_crate_attrs . extend ( additional_global_crate_attrs) ;
184+
185+ let r = intravisit:: walk_mod ( self , m) ;
186+
187+ // Restore global_crate_attrs to it's previous size/content
188+ self . collector . global_crate_attrs . truncate ( old_len) ;
189+ r
190+ }
191+ } else {
192+ intravisit:: walk_mod ( self , m)
193+ }
194+ }
195+
152196 fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' _ > ) {
153197 let name = match & item. kind {
154198 hir:: ItemKind :: Impl ( impl_) => {
0 commit comments