@@ -395,7 +395,7 @@ pub fn make_test(s: &str,
395395
396396 // Uses libsyntax to parse the doctest and find if there's a main fn and the extern
397397 // 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 ( || {
399399 use crate :: syntax:: { ast, parse:: { self , ParseSess } , source_map:: FilePathMapping } ;
400400 use crate :: syntax_pos:: FileName ;
401401 use errors:: emitter:: EmitterWriter ;
@@ -415,6 +415,7 @@ pub fn make_test(s: &str,
415415
416416 let mut found_main = false ;
417417 let mut found_extern_crate = cratename. is_none ( ) ;
418+ let mut found_macro = false ;
418419
419420 let mut parser = match parse:: maybe_new_parser_from_source_str ( & sess, filename, source) {
420421 Ok ( p) => p,
@@ -423,7 +424,7 @@ pub fn make_test(s: &str,
423424 err. cancel ( ) ;
424425 }
425426
426- return ( found_main, found_extern_crate) ;
427+ return ( found_main, found_extern_crate, found_macro ) ;
427428 }
428429 } ;
429430
@@ -451,6 +452,12 @@ pub fn make_test(s: &str,
451452 }
452453 }
453454
455+ if !found_macro {
456+ if let ast:: ItemKind :: Mac ( ..) = item. node {
457+ found_macro = true ;
458+ }
459+ }
460+
454461 if found_main && found_extern_crate {
455462 break ;
456463 }
@@ -463,9 +470,28 @@ pub fn make_test(s: &str,
463470 }
464471 }
465472
466- ( found_main, found_extern_crate)
473+ ( found_main, found_extern_crate, found_macro )
467474 } ) ;
468475
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+
469495 // Don't inject `extern crate std` because it's already injected by the
470496 // compiler.
471497 if !already_has_extern_crate && !opts. no_crate_inject && cratename != Some ( "std" ) {
@@ -1106,4 +1132,23 @@ assert_eq!(asdf::foo, 4);
11061132 let output = make_test ( input, Some ( "asdf" ) , false , & opts) ;
11071133 assert_eq ! ( output, ( expected, 3 ) ) ;
11081134 }
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+ }
11091154}
0 commit comments