@@ -25,6 +25,7 @@ struct Test {
2525
2626struct TestCtxt < ' a > {
2727 ext_cx : ExtCtxt < ' a > ,
28+ def_site : Span ,
2829 test_cases : Vec < Test > ,
2930 reexport_test_harness_main : Option < Symbol > ,
3031 test_runner : Option < ast:: Path > ,
@@ -125,6 +126,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
125126struct EntryPointCleaner {
126127 // Current depth in the ast
127128 depth : usize ,
129+ def_site : Span ,
128130}
129131
130132impl MutVisitor for EntryPointCleaner {
@@ -141,8 +143,10 @@ impl MutVisitor for EntryPointCleaner {
141143 EntryPointType :: MainAttr |
142144 EntryPointType :: Start =>
143145 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+ ) ;
146150 let allow_dead_code_item = attr:: mk_list_item ( allow_ident, vec ! [ dc_nested] ) ;
147151 let allow_dead_code = attr:: mk_attr_outer ( allow_dead_code_item) ;
148152
@@ -180,15 +184,26 @@ fn generate_test_harness(sess: &ParseSess,
180184 krate : & mut ast:: Crate ,
181185 features : & Features ,
182186 test_runner : Option < ast:: Path > ) {
183- // Remove the entry points
184- let mut cleaner = EntryPointCleaner { depth : 0 } ;
185- cleaner. visit_crate ( krate) ;
186-
187187 let mut econfig = ExpansionConfig :: default ( "test" . to_string ( ) ) ;
188188 econfig. features = Some ( features) ;
189189
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+
190204 let cx = TestCtxt {
191- ext_cx : ExtCtxt :: new ( sess, econfig, resolver) ,
205+ ext_cx,
206+ def_site,
192207 test_cases : Vec :: new ( ) ,
193208 reexport_test_harness_main,
194209 test_runner
@@ -202,27 +217,40 @@ fn generate_test_harness(sess: &ParseSess,
202217
203218/// Creates a function item for use as the main function of a test build.
204219/// 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`.
205246fn 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 ;
218248 let ecx = & cx. ext_cx ;
219249 let test_id = Ident :: new ( sym:: test, sp) ;
220250
221251 // test::test_main_static(...)
222252 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) ] ) ) ;
226254
227255 test_runner. span = sp;
228256
@@ -231,17 +259,17 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
231259 vec ! [ mk_tests_slice( cx, sp) ] ) ;
232260 let call_test_main = ecx. stmt_expr ( call_test_main) ;
233261
234- // #![main]
235- let main_meta = ecx. meta_word ( sp, sym:: main) ;
236- let main_attr = ecx. attribute ( main_meta) ;
237-
238262 // extern crate test
239263 let test_extern_stmt = ecx. stmt_item ( sp, ecx. item ( sp,
240264 test_id,
241265 vec ! [ ] ,
242266 ast:: ItemKind :: ExternCrate ( None )
243267 ) ) ;
244268
269+ // #[main]
270+ let main_meta = ecx. meta_word ( sp, sym:: main) ;
271+ let main_attr = ecx. attribute ( main_meta) ;
272+
245273 // pub fn main() { ... }
246274 let main_ret_ty = ecx. ty ( sp, ast:: TyKind :: Tup ( vec ! [ ] ) ) ;
247275
@@ -279,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
279307}
280308
281309/// Creates a slice containing every test like so:
282- /// &[test1, test2]
310+ /// &[& test1, & test2]
283311fn mk_tests_slice ( cx : & TestCtxt < ' _ > , sp : Span ) -> P < ast:: Expr > {
284312 debug ! ( "building test vector from {} tests" , cx. test_cases. len( ) ) ;
285313 let ref ecx = cx. ext_cx ;
0 commit comments