Skip to content

Commit 4fbc9ab

Browse files
committed
Even more optimizing documentation lints? (3/2)
Avoid creating so many SessionGlobals Improve filtering and account for spacing Actually return early
1 parent 506411d commit 4fbc9ab

File tree

3 files changed

+157
-4
lines changed

3 files changed

+157
-4
lines changed

clippy_lints/src/doc/needless_doctest_main.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub fn check(
7272
if !ignore {
7373
get_test_spans(&item, *ident, &mut test_attr_spans);
7474
}
75+
7576
let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. }));
7677
let returns_nothing = match &sig.decl.output {
7778
FnRetTy::Default(..) => true,
@@ -86,13 +87,25 @@ pub fn check(
8687
// This main function should not be linted, we're done
8788
eligible = false;
8889
}
90+
// Return early if we're in an ignore codeblock, as
91+
// test_attr_in_doctest
92+
// won't do anything useful in these cases and we already have our
93+
// problematic function.
94+
if ignore {
95+
return (true, vec![]);
96+
}
8997
},
9098
// Another function was found; this case is ignored for needless_doctest_main
9199
ItemKind::Fn(fn_) => {
92100
eligible = false;
93-
if !ignore {
94-
get_test_spans(&item, fn_.ident, &mut test_attr_spans);
101+
if ignore {
102+
// If ignore is active invalidating one lint,
103+
// and we already found another function thus
104+
// invalidating the other one, we have no
105+
// business continuing.
106+
return (false, test_attr_spans);
95107
}
108+
get_test_spans(&item, fn_.ident, &mut test_attr_spans);
96109
},
97110
// Tests with one of these items are ignored
98111
ItemKind::Static(..)
@@ -120,6 +133,18 @@ pub fn check(
120133

121134
let trailing_whitespace = text.len() - text.trim_end().len();
122135

136+
// We currently only test for "fn main". Checking for the real
137+
// entrypoint (with tcx.entry_fn(())) in each block would be unnecessarily
138+
// expensive, as those are probably intended and relevant. Same goes for
139+
// macros and other weird ways of declaring a main function.
140+
//
141+
// Also, as we only check for attribute names and don't do macro expansion,
142+
// we can check only for #[test]
143+
144+
if !((text.contains("main") && text.contains("fn")) || text.contains("#[test]")) {
145+
return;
146+
}
147+
123148
// Because of the global session, we need to create a new session in a different thread with
124149
// the edition we need.
125150
let text = text.to_owned();

tests/ui/doc/needless_doctest_main.rs

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//@ check-pass
2-
31
#![warn(clippy::needless_doctest_main)]
42
//! issue 10491:
53
//! ```rust,no_test
@@ -19,4 +17,98 @@
1917
/// ```
2018
fn foo() {}
2119

20+
#[rustfmt::skip]
21+
/// Description
22+
/// ```rust
23+
/// fn main() {
24+
//~^ error: needless `fn main` in doctest
25+
/// let a = 0;
26+
/// }
27+
/// ```
28+
fn mulpipulpi() {}
29+
30+
#[rustfmt::skip]
31+
/// With a `#[no_main]`
32+
/// ```rust
33+
/// #[no_main]
34+
/// fn a() {
35+
/// let _ = 0;
36+
/// }
37+
/// ```
38+
fn pulpimulpi() {}
39+
40+
// Without a `#[no_main]` attribute
41+
/// ```rust
42+
/// fn a() {
43+
/// let _ = 0;
44+
/// }
45+
/// ```
46+
fn plumilupi() {}
47+
48+
#[rustfmt::skip]
49+
/// Additional function, shouldn't trigger
50+
/// ```rust
51+
/// fn additional_function() {
52+
/// let _ = 0;
53+
/// // Thus `fn main` is actually relevant!
54+
/// }
55+
/// fn main() {
56+
/// let _ = 0;
57+
/// }
58+
/// ```
59+
fn mlupipupi() {}
60+
61+
#[rustfmt::skip]
62+
/// Additional function AFTER main, shouldn't trigger
63+
/// ```rust
64+
/// fn main() {
65+
/// let _ = 0;
66+
/// }
67+
/// fn additional_function() {
68+
/// let _ = 0;
69+
/// // Thus `fn main` is actually relevant!
70+
/// }
71+
/// ```
72+
fn lumpimupli() {}
73+
74+
#[rustfmt::skip]
75+
/// Ignore code block, should not lint at all
76+
/// ```rust, ignore
77+
/// fn main() {
78+
//~^ error: needless `fn main` in doctest
79+
/// // Hi!
80+
/// let _ = 0;
81+
/// }
82+
/// ```
83+
fn mpulpilumi() {}
84+
85+
#[rustfmt::skip]
86+
/// Spaces in weird positions (including an \u{A0} after `main`)
87+
/// ```rust
88+
/// fn main (){
89+
//~^ error: needless `fn main` in doctest
90+
/// let _ = 0;
91+
/// }
92+
/// ```
93+
fn plumpiplupi() {}
94+
95+
/// 4 Functions, this should not lint because there are several function
96+
///
97+
/// ```rust
98+
/// fn a() {let _ = 0; }
99+
/// fn b() {let _ = 0; }
100+
/// fn main() { let _ = 0; }
101+
/// fn d() { let _ = 0; }
102+
/// ```
103+
fn pulmipulmip() {}
104+
105+
/// 3 Functions but main is first, should also not lint
106+
///
107+
///```rust
108+
/// fn main() { let _ = 0; }
109+
/// fn b() { let _ = 0; }
110+
/// fn c() { let _ = 0; }
111+
/// ```
112+
fn pmuplimulip() {}
113+
22114
fn main() {}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
error: needless `fn main` in doctest
2+
--> tests/ui/doc/needless_doctest_main.rs:23:5
3+
|
4+
LL | /// fn main() {
5+
| _____^
6+
LL | |
7+
LL | | /// let a = 0;
8+
LL | | /// }
9+
| |_____^
10+
|
11+
= note: `-D clippy::needless-doctest-main` implied by `-D warnings`
12+
= help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]`
13+
14+
error: needless `fn main` in doctest
15+
--> tests/ui/doc/needless_doctest_main.rs:77:5
16+
|
17+
LL | /// fn main() {
18+
| _____^
19+
LL | |
20+
LL | | /// // Hi!
21+
LL | | /// let _ = 0;
22+
LL | | /// }
23+
| |_____^
24+
25+
error: needless `fn main` in doctest
26+
--> tests/ui/doc/needless_doctest_main.rs:88:5
27+
|
28+
LL | /// fn main (){
29+
| _____^
30+
LL | |
31+
LL | | /// let _ = 0;
32+
LL | | /// }
33+
| |_____^
34+
35+
error: aborting due to 3 previous errors
36+

0 commit comments

Comments
 (0)