@@ -9,37 +9,32 @@ use pulldown_cmark::Event::{
9
9
} ;
10
10
use pulldown_cmark:: Tag :: { CodeBlock , Heading , Item , Link , Paragraph } ;
11
11
use pulldown_cmark:: { BrokenLink , CodeBlockKind , CowStr , Options } ;
12
- use rustc_ast:: ast:: { Async , Attribute , Fn , FnRetTy , ItemKind } ;
12
+ use rustc_ast:: ast:: Attribute ;
13
13
use rustc_ast:: token:: CommentKind ;
14
14
use rustc_ast:: { AttrKind , AttrStyle } ;
15
15
use rustc_data_structures:: fx:: FxHashSet ;
16
- use rustc_data_structures:: sync:: Lrc ;
17
- use rustc_errors:: emitter:: EmitterWriter ;
18
- use rustc_errors:: { Applicability , Handler } ;
16
+ use rustc_errors:: Applicability ;
19
17
use rustc_hir as hir;
20
18
use rustc_hir:: intravisit:: { self , Visitor } ;
21
19
use rustc_hir:: { AnonConst , Expr } ;
22
20
use rustc_lint:: { LateContext , LateLintPass } ;
23
21
use rustc_middle:: hir:: nested_filter;
24
22
use rustc_middle:: lint:: in_external_macro;
25
23
use rustc_middle:: ty;
26
- use rustc_parse:: maybe_new_parser_from_source_str;
27
- use rustc_parse:: parser:: ForceCollect ;
28
24
use rustc_resolve:: rustdoc:: {
29
25
add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment ,
30
26
} ;
31
- use rustc_session:: parse:: ParseSess ;
32
27
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
33
28
use rustc_span:: edition:: Edition ;
34
- use rustc_span:: source_map:: { FilePathMapping , SourceMap , Span } ;
35
- use rustc_span:: { sym, FileName } ;
29
+ use rustc_span:: source_map:: Span ;
30
+ use rustc_span:: sym;
36
31
use std:: ops:: Range ;
37
- use std:: { io, thread} ;
38
32
use url:: Url ;
39
33
40
34
mod link_with_quotes;
41
35
mod markdown;
42
36
mod missing_headers;
37
+ mod needless_doctest_main;
43
38
44
39
declare_clippy_lint ! {
45
40
/// ### What it does
@@ -624,7 +619,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
624
619
if in_code {
625
620
if is_rust && !no_test {
626
621
let edition = edition. unwrap_or_else ( || cx. tcx . sess . edition ( ) ) ;
627
- check_code ( cx, & text, edition, range. clone ( ) , fragments) ;
622
+ needless_doctest_main :: check ( cx, & text, edition, range. clone ( ) , fragments) ;
628
623
}
629
624
} else {
630
625
if in_link. is_some ( ) {
@@ -645,87 +640,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
645
640
headers
646
641
}
647
642
648
- fn check_code ( cx : & LateContext < ' _ > , text : & str , edition : Edition , range : Range < usize > , fragments : Fragments < ' _ > ) {
649
- fn has_needless_main ( code : String , edition : Edition ) -> bool {
650
- rustc_driver:: catch_fatal_errors ( || {
651
- rustc_span:: create_session_globals_then ( edition, || {
652
- let filename = FileName :: anon_source_code ( & code) ;
653
-
654
- let sm = Lrc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
655
- let fallback_bundle =
656
- rustc_errors:: fallback_fluent_bundle ( rustc_driver:: DEFAULT_LOCALE_RESOURCES . to_vec ( ) , false ) ;
657
- let emitter = EmitterWriter :: new ( Box :: new ( io:: sink ( ) ) , fallback_bundle) ;
658
- let handler = Handler :: with_emitter ( Box :: new ( emitter) ) . disable_warnings ( ) ;
659
- let sess = ParseSess :: with_span_handler ( handler, sm) ;
660
-
661
- let mut parser = match maybe_new_parser_from_source_str ( & sess, filename, code) {
662
- Ok ( p) => p,
663
- Err ( errs) => {
664
- drop ( errs) ;
665
- return false ;
666
- } ,
667
- } ;
668
-
669
- let mut relevant_main_found = false ;
670
- loop {
671
- match parser. parse_item ( ForceCollect :: No ) {
672
- Ok ( Some ( item) ) => match & item. kind {
673
- ItemKind :: Fn ( box Fn {
674
- sig, body : Some ( block) , ..
675
- } ) if item. ident . name == sym:: main => {
676
- let is_async = matches ! ( sig. header. asyncness, Async :: Yes { .. } ) ;
677
- let returns_nothing = match & sig. decl . output {
678
- FnRetTy :: Default ( ..) => true ,
679
- FnRetTy :: Ty ( ty) if ty. kind . is_unit ( ) => true ,
680
- FnRetTy :: Ty ( _) => false ,
681
- } ;
682
-
683
- if returns_nothing && !is_async && !block. stmts . is_empty ( ) {
684
- // This main function should be linted, but only if there are no other functions
685
- relevant_main_found = true ;
686
- } else {
687
- // This main function should not be linted, we're done
688
- return false ;
689
- }
690
- } ,
691
- // Tests with one of these items are ignored
692
- ItemKind :: Static ( ..)
693
- | ItemKind :: Const ( ..)
694
- | ItemKind :: ExternCrate ( ..)
695
- | ItemKind :: ForeignMod ( ..)
696
- // Another function was found; this case is ignored
697
- | ItemKind :: Fn ( ..) => return false ,
698
- _ => { } ,
699
- } ,
700
- Ok ( None ) => break ,
701
- Err ( e) => {
702
- e. cancel ( ) ;
703
- return false ;
704
- } ,
705
- }
706
- }
707
-
708
- relevant_main_found
709
- } )
710
- } )
711
- . ok ( )
712
- . unwrap_or_default ( )
713
- }
714
-
715
- let trailing_whitespace = text. len ( ) - text. trim_end ( ) . len ( ) ;
716
-
717
- // Because of the global session, we need to create a new session in a different thread with
718
- // the edition we need.
719
- let text = text. to_owned ( ) ;
720
- if thread:: spawn ( move || has_needless_main ( text, edition) )
721
- . join ( )
722
- . expect ( "thread::spawn failed" )
723
- && let Some ( span) = fragments. span ( cx, range. start ..range. end - trailing_whitespace)
724
- {
725
- span_lint ( cx, NEEDLESS_DOCTEST_MAIN , span, "needless `fn main` in doctest" ) ;
726
- }
727
- }
728
-
729
643
struct FindPanicUnwrap < ' a , ' tcx > {
730
644
cx : & ' a LateContext < ' tcx > ,
731
645
panic_span : Option < Span > ,
0 commit comments