@@ -10,6 +10,7 @@ use syntax::ast::Attribute;
1010use syntax:: source_map:: { BytePos , Span } ;
1111use syntax_pos:: Pos ;
1212use url:: Url ;
13+ use syn:: * ;
1314
1415declare_clippy_lint ! {
1516 /// **What it does:** Checks for the presence of `_`, `::` or camel-case words
@@ -73,7 +74,9 @@ declare_clippy_lint! {
7374 /// **What it does:** Checks for `fn main() { .. }` in doctests
7475 ///
7576 /// **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.
7780 ///
7881 /// **Known problems:** None.
7982 ///
@@ -86,6 +89,7 @@ declare_clippy_lint! {
8689 /// /// ```
8790 /// /// fn main() {
8891 /// /// // this needs not be in an `fn`
92+ /// /// unimplemented!();
8993 /// /// }
9094 /// /// ```
9195 /// fn needless_main() {
@@ -344,9 +348,34 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
344348 safety_header
345349}
346350
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+ }
350379 }
351380}
352381
0 commit comments