@@ -10,6 +10,7 @@ use syntax::ast::Attribute;
10
10
use syntax:: source_map:: { BytePos , Span } ;
11
11
use syntax_pos:: Pos ;
12
12
use url:: Url ;
13
+ use syn:: * ;
13
14
14
15
declare_clippy_lint ! {
15
16
/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
@@ -73,7 +74,9 @@ declare_clippy_lint! {
73
74
/// **What it does:** Checks for `fn main() { .. }` in doctests
74
75
///
75
76
/// **Why is this bad?** The test can be shorter (and likely more readable)
76
- /// if the `fn main()` is left implicit.
77
+ /// if the `fn main()` is left implicit. In some cases, you'll need an
78
+ /// empty `fn main() {}` in your doctest to avoid rustdoc introducing one,
79
+ /// which is why the line will ignore empty `main` functions.
77
80
///
78
81
/// **Known problems:** None.
79
82
///
@@ -86,6 +89,7 @@ declare_clippy_lint! {
86
89
/// /// ```
87
90
/// /// fn main() {
88
91
/// /// // this needs not be in an `fn`
92
+ /// /// unimplemented!();
89
93
/// /// }
90
94
/// /// ```
91
95
/// fn needless_main() {
@@ -344,9 +348,34 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
344
348
safety_header
345
349
}
346
350
347
- fn check_code ( cx : & LateContext < ' _ , ' _ > , text : & str , span : Span ) {
348
- if text. contains ( "fn main() {" ) {
349
- span_lint ( cx, NEEDLESS_DOCTEST_MAIN , span, "needless `fn main` in doctest" ) ;
351
+ // check a syn Item for non-empty `fn main() { .. }`
352
+ fn is_default_main_fn ( item : & syn:: Item ) -> bool {
353
+ match item {
354
+ Item :: Fn ( ItemFn { ref sig, ref block, .. } ) => {
355
+ !block. stmts . is_empty ( )
356
+ && sig. ident == "main"
357
+ && match sig. output {
358
+ ReturnType :: Default => true ,
359
+ ReturnType :: Type ( _, ref ty) => match * * ty {
360
+ Type :: Tuple ( TypeTuple { ref elems, .. } ) => elems. is_empty ( ) ,
361
+ _ => false ,
362
+ } ,
363
+ }
364
+ } ,
365
+ _ => false ,
366
+ }
367
+ }
368
+
369
+ fn check_code ( cx : & LateContext < ' _ , ' _ > , code : & str , span : Span ) {
370
+ if let Ok ( file) = syn:: parse_file ( code) {
371
+ if file. items . iter ( ) . any ( is_default_main_fn) {
372
+ span_lint (
373
+ cx,
374
+ NEEDLESS_DOCTEST_MAIN ,
375
+ span,
376
+ "needless `fn main() {} in doctest" ,
377
+ ) ;
378
+ }
350
379
}
351
380
}
352
381
0 commit comments