Skip to content

Commit fcd7e14

Browse files
committed
Auto merge of #4729 - rust-lang:needless-doc-main-syn, r=<try>
Use syn in needless_doctest_main lint changelog: none This fixes #4698 by only linting non-empty `fn main()`s. This is not a perfect solution, but I don't want to omit linting if any macro call or attribute is detected, as that would result in many false negatives.
2 parents dbdd75a + 1077c23 commit fcd7e14

File tree

4 files changed

+64
-6
lines changed

4 files changed

+64
-6
lines changed

clippy_lints/Cargo.toml

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@ matches = "0.1.7"
2525
pulldown-cmark = "0.6.0"
2626
quine-mc_cluskey = "0.2.2"
2727
regex-syntax = "0.6"
28+
semver = "0.9.0"
2829
serde = { version = "1.0", features = ["derive"] }
2930
smallvec = { version = "1", features = ["union"] }
31+
syn = { version = "1.0", features = ["full"] }
3032
toml = "0.5.3"
3133
unicode-normalization = "0.1"
32-
semver = "0.9.0"
33-
# NOTE: cargo requires serde feat in its url dep
34-
# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
34+
# cargo requires serde feat in its url dep
35+
# see https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864
3536
url = { version = "2.1.0", features = ["serde"] }
3637

3738
[features]

clippy_lints/src/doc.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,29 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
342342
safety_header
343343
}
344344

345-
fn check_code(cx: &LateContext<'_, '_>, text: &str, span: Span) {
346-
if text.contains("fn main() {") {
347-
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
345+
// check a syn Item for non-empty `fn main() { .. }`
346+
fn is_default_main_fn(item: &syn::Item) -> bool {
347+
match item {
348+
syn::Item::Fn(syn::ItemFn { ref sig, ref block, .. }) => {
349+
!block.stmts.is_empty()
350+
&& sig.ident == "main"
351+
&& match sig.output {
352+
syn::ReturnType::Default => true,
353+
syn::ReturnType::Type(_, ref ty) => match **ty {
354+
syn::Type::Tuple(syn::TypeTuple { ref elems, .. }) => elems.is_empty(),
355+
_ => false,
356+
},
357+
}
358+
},
359+
_ => false,
360+
}
361+
}
362+
363+
fn check_code(cx: &LateContext<'_, '_>, code: &str, span: Span) {
364+
if let Ok(file) = syn::parse_file(code) {
365+
if file.items.iter().any(is_default_main_fn) {
366+
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main() {}` in doctest");
367+
}
348368
}
349369
}
350370

tests/ui/needless_doc_main.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// This method does nothing. It's just there for testing.
2+
///
3+
/// # Examples:
4+
///
5+
/// ```text,ignore
6+
/// This is not Rust code
7+
/// Just check that parsing won't crash
8+
/// R€fridger@tør.
9+
/// ```
10+
///
11+
/// ```
12+
/// fn main() {
13+
/// let this_is_linted = 42u8;
14+
/// assert_eq!(this_is_linted / 2, 21);
15+
/// }
16+
/// ```
17+
///
18+
/// ```
19+
/// #[allow(unused)]
20+
/// const I = 1;
21+
/// fn main() {
22+
/// // this main method contains no code and is thus not linted.
23+
/// }
24+
/// ```
25+
fn main() {
26+
// nothing to see here, move along.
27+
}

tests/ui/needless_doc_main.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: needless `fn main() {}` in doctest
2+
--> $DIR/needless_doc_main.rs:12:4
3+
|
4+
LL | /// fn main() {
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::needless-doctest-main` implied by `-D warnings`
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)