@@ -25,6 +25,7 @@ struct Test {
25
25
26
26
struct TestCtxt < ' a > {
27
27
ext_cx : ExtCtxt < ' a > ,
28
+ def_site : Span ,
28
29
test_cases : Vec < Test > ,
29
30
reexport_test_harness_main : Option < Symbol > ,
30
31
test_runner : Option < ast:: Path > ,
@@ -125,6 +126,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
125
126
struct EntryPointCleaner {
126
127
// Current depth in the ast
127
128
depth : usize ,
129
+ def_site : Span ,
128
130
}
129
131
130
132
impl MutVisitor for EntryPointCleaner {
@@ -141,8 +143,10 @@ impl MutVisitor for EntryPointCleaner {
141
143
EntryPointType :: MainAttr |
142
144
EntryPointType :: Start =>
143
145
item. map ( |ast:: Item { id, ident, attrs, node, vis, span, tokens} | {
144
- let allow_ident = Ident :: with_dummy_span ( sym:: allow) ;
145
- let dc_nested = attr:: mk_nested_word_item ( Ident :: from_str ( "dead_code" ) ) ;
146
+ let allow_ident = Ident :: new ( sym:: allow, self . def_site ) ;
147
+ let dc_nested = attr:: mk_nested_word_item (
148
+ Ident :: from_str_and_span ( "dead_code" , self . def_site ) ,
149
+ ) ;
146
150
let allow_dead_code_item = attr:: mk_list_item ( allow_ident, vec ! [ dc_nested] ) ;
147
151
let allow_dead_code = attr:: mk_attr_outer ( allow_dead_code_item) ;
148
152
@@ -180,15 +184,26 @@ fn generate_test_harness(sess: &ParseSess,
180
184
krate : & mut ast:: Crate ,
181
185
features : & Features ,
182
186
test_runner : Option < ast:: Path > ) {
183
- // Remove the entry points
184
- let mut cleaner = EntryPointCleaner { depth : 0 } ;
185
- cleaner. visit_crate ( krate) ;
186
-
187
187
let mut econfig = ExpansionConfig :: default ( "test" . to_string ( ) ) ;
188
188
econfig. features = Some ( features) ;
189
189
190
+ let ext_cx = ExtCtxt :: new ( sess, econfig, resolver) ;
191
+
192
+ let expn_id = ext_cx. resolver . expansion_for_ast_pass (
193
+ DUMMY_SP ,
194
+ AstPass :: TestHarness ,
195
+ & [ sym:: main, sym:: test, sym:: rustc_attrs] ,
196
+ None ,
197
+ ) ;
198
+ let def_site = DUMMY_SP . with_def_site_ctxt ( expn_id) ;
199
+
200
+ // Remove the entry points
201
+ let mut cleaner = EntryPointCleaner { depth : 0 , def_site } ;
202
+ cleaner. visit_crate ( krate) ;
203
+
190
204
let cx = TestCtxt {
191
- ext_cx : ExtCtxt :: new ( sess, econfig, resolver) ,
205
+ ext_cx,
206
+ def_site,
192
207
test_cases : Vec :: new ( ) ,
193
208
reexport_test_harness_main,
194
209
test_runner
@@ -202,27 +217,40 @@ fn generate_test_harness(sess: &ParseSess,
202
217
203
218
/// Creates a function item for use as the main function of a test build.
204
219
/// This function will call the `test_runner` as specified by the crate attribute
220
+ ///
221
+ /// By default this expands to
222
+ ///
223
+ /// #[main]
224
+ /// pub fn main() {
225
+ /// extern crate test;
226
+ /// test::test_main_static(&[
227
+ /// &test_const1,
228
+ /// &test_const2,
229
+ /// &test_const3,
230
+ /// ]);
231
+ /// }
232
+ ///
233
+ /// Most of the Ident have the usual def-site hygiene for the AST pass. The
234
+ /// exception is the `test_const`s. These have a syntax context that has two
235
+ /// opaque marks: one from the expansion of `test` or `test_case`, and one
236
+ /// generated in `TestHarnessGenerator::flat_map_item`. When resolving this
237
+ /// identifier after failing to find a matching identifier in the root module
238
+ /// we remove the outer mark, and try resolving at its def-site, which will
239
+ /// then resolve to `test_const`.
240
+ ///
241
+ /// The expansion here can be controlled by two attributes:
242
+ ///
243
+ /// `reexport_test_harness_main` provides a different name for the `main`
244
+ /// function and `test_runner` provides a path that replaces
245
+ /// `test::test_main_static`.
205
246
fn mk_main ( cx : & mut TestCtxt < ' _ > ) -> P < ast:: Item > {
206
- // Writing this out by hand:
207
- // pub fn main() {
208
- // #![main]
209
- // test::test_main_static(&[..tests]);
210
- // }
211
- let expn_id = cx. ext_cx . resolver . expansion_for_ast_pass (
212
- DUMMY_SP ,
213
- AstPass :: TestHarness ,
214
- & [ sym:: main, sym:: test, sym:: rustc_attrs] ,
215
- None ,
216
- ) ;
217
- let sp = DUMMY_SP . with_def_site_ctxt ( expn_id) ;
247
+ let sp = cx. def_site ;
218
248
let ecx = & cx. ext_cx ;
219
249
let test_id = Ident :: new ( sym:: test, sp) ;
220
250
221
251
// test::test_main_static(...)
222
252
let mut test_runner = cx. test_runner . clone ( ) . unwrap_or (
223
- ecx. path ( sp, vec ! [
224
- test_id, ecx. ident_of( "test_main_static" )
225
- ] ) ) ;
253
+ ecx. path ( sp, vec ! [ test_id, Ident :: from_str_and_span( "test_main_static" , sp) ] ) ) ;
226
254
227
255
test_runner. span = sp;
228
256
@@ -231,17 +259,17 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
231
259
vec ! [ mk_tests_slice( cx, sp) ] ) ;
232
260
let call_test_main = ecx. stmt_expr ( call_test_main) ;
233
261
234
- // #![main]
235
- let main_meta = ecx. meta_word ( sp, sym:: main) ;
236
- let main_attr = ecx. attribute ( main_meta) ;
237
-
238
262
// extern crate test
239
263
let test_extern_stmt = ecx. stmt_item ( sp, ecx. item ( sp,
240
264
test_id,
241
265
vec ! [ ] ,
242
266
ast:: ItemKind :: ExternCrate ( None )
243
267
) ) ;
244
268
269
+ // #[main]
270
+ let main_meta = ecx. meta_word ( sp, sym:: main) ;
271
+ let main_attr = ecx. attribute ( main_meta) ;
272
+
245
273
// pub fn main() { ... }
246
274
let main_ret_ty = ecx. ty ( sp, ast:: TyKind :: Tup ( vec ! [ ] ) ) ;
247
275
@@ -279,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
279
307
}
280
308
281
309
/// Creates a slice containing every test like so:
282
- /// &[test1, test2]
310
+ /// &[& test1, & test2]
283
311
fn mk_tests_slice ( cx : & TestCtxt < ' _ > , sp : Span ) -> P < ast:: Expr > {
284
312
debug ! ( "building test vector from {} tests" , cx. test_cases. len( ) ) ;
285
313
let ref ecx = cx. ext_cx ;
0 commit comments