@@ -395,7 +395,7 @@ pub fn make_test(s: &str,
395
395
396
396
// Uses libsyntax to parse the doctest and find if there's a main fn and the extern
397
397
// crate already is included.
398
- let ( already_has_main, already_has_extern_crate) = crate :: syntax:: with_globals ( || {
398
+ let ( already_has_main, already_has_extern_crate, found_macro ) = crate :: syntax:: with_globals ( || {
399
399
use crate :: syntax:: { ast, parse:: { self , ParseSess } , source_map:: FilePathMapping } ;
400
400
use crate :: syntax_pos:: FileName ;
401
401
use errors:: emitter:: EmitterWriter ;
@@ -415,6 +415,7 @@ pub fn make_test(s: &str,
415
415
416
416
let mut found_main = false ;
417
417
let mut found_extern_crate = cratename. is_none ( ) ;
418
+ let mut found_macro = false ;
418
419
419
420
let mut parser = match parse:: maybe_new_parser_from_source_str ( & sess, filename, source) {
420
421
Ok ( p) => p,
@@ -423,7 +424,7 @@ pub fn make_test(s: &str,
423
424
err. cancel ( ) ;
424
425
}
425
426
426
- return ( found_main, found_extern_crate) ;
427
+ return ( found_main, found_extern_crate, found_macro ) ;
427
428
}
428
429
} ;
429
430
@@ -451,6 +452,12 @@ pub fn make_test(s: &str,
451
452
}
452
453
}
453
454
455
+ if !found_macro {
456
+ if let ast:: ItemKind :: Mac ( ..) = item. node {
457
+ found_macro = true ;
458
+ }
459
+ }
460
+
454
461
if found_main && found_extern_crate {
455
462
break ;
456
463
}
@@ -463,9 +470,28 @@ pub fn make_test(s: &str,
463
470
}
464
471
}
465
472
466
- ( found_main, found_extern_crate)
473
+ ( found_main, found_extern_crate, found_macro )
467
474
} ) ;
468
475
476
+ // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't
477
+ // see it. In that case, run the old text-based scan to see if they at least have a main
478
+ // function written inside a macro invocation. See
479
+ // https://github.com/rust-lang/rust/issues/56898
480
+ let already_has_main = if found_macro && !already_has_main {
481
+ s. lines ( )
482
+ . map ( |line| {
483
+ let comment = line. find ( "//" ) ;
484
+ if let Some ( comment_begins) = comment {
485
+ & line[ 0 ..comment_begins]
486
+ } else {
487
+ line
488
+ }
489
+ } )
490
+ . any ( |code| code. contains ( "fn main" ) )
491
+ } else {
492
+ already_has_main
493
+ } ;
494
+
469
495
// Don't inject `extern crate std` because it's already injected by the
470
496
// compiler.
471
497
if !already_has_extern_crate && !opts. no_crate_inject && cratename != Some ( "std" ) {
@@ -1106,4 +1132,23 @@ assert_eq!(asdf::foo, 4);
1106
1132
let output = make_test ( input, Some ( "asdf" ) , false , & opts) ;
1107
1133
assert_eq ! ( output, ( expected, 3 ) ) ;
1108
1134
}
1135
+
1136
+ #[ test]
1137
+ fn make_test_main_in_macro ( ) {
1138
+ let opts = TestOptions :: default ( ) ;
1139
+ let input =
1140
+ "#[macro_use] extern crate my_crate;
1141
+ test_wrapper! {
1142
+ fn main() {}
1143
+ }" ;
1144
+ let expected =
1145
+ "#![allow(unused)]
1146
+ #[macro_use] extern crate my_crate;
1147
+ test_wrapper! {
1148
+ fn main() {}
1149
+ }" . to_string ( ) ;
1150
+
1151
+ let output = make_test ( input, Some ( "my_crate" ) , false , & opts) ;
1152
+ assert_eq ! ( output, ( expected, 1 ) ) ;
1153
+ }
1109
1154
}
0 commit comments