3
3
use std:: env;
4
4
use std:: sync:: Arc ;
5
5
6
+ use rustc_ast_pretty:: pprust;
6
7
use rustc_data_structures:: fx:: FxHashSet ;
7
8
use rustc_hir:: def_id:: { CRATE_DEF_ID , LocalDefId } ;
8
9
use rustc_hir:: { self as hir, CRATE_HIR_ID , intravisit} ;
9
10
use rustc_middle:: hir:: nested_filter;
10
11
use rustc_middle:: ty:: TyCtxt ;
11
12
use rustc_resolve:: rustdoc:: span_of_fragments;
12
13
use 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 } ;
14
15
15
16
use super :: { DocTestVisitor , ScrapedDocTest } ;
16
17
use crate :: clean:: { Attributes , extract_cfg_from_attrs} ;
@@ -21,6 +22,7 @@ struct RustCollector {
21
22
tests : Vec < ScrapedDocTest > ,
22
23
cur_path : Vec < String > ,
23
24
position : Span ,
25
+ global_crate_attrs : Vec < String > ,
24
26
}
25
27
26
28
impl RustCollector {
@@ -54,6 +56,7 @@ impl DocTestVisitor for RustCollector {
54
56
self . cur_path . clone ( ) ,
55
57
config,
56
58
test,
59
+ self . global_crate_attrs . clone ( ) ,
57
60
) ) ;
58
61
}
59
62
@@ -73,6 +76,7 @@ impl<'tcx> HirCollector<'tcx> {
73
76
cur_path : vec ! [ ] ,
74
77
position : DUMMY_SP ,
75
78
tests : vec ! [ ] ,
79
+ global_crate_attrs : Vec :: new ( ) ,
76
80
} ;
77
81
Self { codes, tcx, collector }
78
82
}
@@ -149,6 +153,46 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
149
153
self . tcx
150
154
}
151
155
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
+
152
196
fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' _ > ) {
153
197
let name = match & item. kind {
154
198
hir:: ItemKind :: Impl ( impl_) => {
0 commit comments