Skip to content

Commit c89513b

Browse files
committed
Add lint unflagged_test_modules
1 parent 5afa93b commit c89513b

7 files changed

+127
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4963,6 +4963,7 @@ Released 2018-09-13
49634963
[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
49644964
[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
49654965
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
4966+
[`unflagged_test_modules`]: https://rust-lang.github.io/rust-clippy/master/index.html#unflagged_test_modules
49664967
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
49674968
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
49684969
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
605605
crate::types::VEC_BOX_INFO,
606606
crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
607607
crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
608+
crate::unflagged_test_modules::UNFLAGGED_TEST_MODULES_INFO,
608609
crate::unicode::INVISIBLE_CHARACTERS_INFO,
609610
crate::unicode::NON_ASCII_LITERAL_INFO,
610611
crate::unicode::UNICODE_NOT_NFC_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ mod trait_bounds;
294294
mod transmute;
295295
mod types;
296296
mod undocumented_unsafe_blocks;
297+
mod unflagged_test_modules;
297298
mod unicode;
298299
mod uninit_vec;
299300
mod unit_return_expecting_ord;
@@ -936,6 +937,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
936937
store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock));
937938
store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
938939
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
940+
store.register_late_pass(|_| Box::new(unflagged_test_modules::UnflaggedTestModules));
939941
// add lints here, do not remove this comment, it's used in `new_lint`
940942
}
941943

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use rustc_hir::*;
3+
use rustc_lint::{LateContext, LateLintPass};
4+
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
use rustc_span::{symbol::sym, BytePos};
6+
7+
declare_clippy_lint! {
8+
/// ### What it does
9+
///
10+
/// Triggers when a testing module (that contains "test" or "tests" in its name) isn't flagged with the `#[cfg(test)]` attribute.
11+
///
12+
/// ### Why is this bad?
13+
///
14+
/// The attribute `#[cfg(test)]` is used to tell Rust to compile and run the test code only when you run `cargo test` and not when you run `cargo build`. This saves compile time and space in the resulting compiled artifact because tests are not included. So not using `#[cfg(test)]` for tests is both a waste of time and space.
15+
///
16+
/// ### Example
17+
/// ```rust
18+
/// mod my_cool_tests {
19+
/// // [...]
20+
/// }
21+
/// ```
22+
/// Use instead:
23+
/// ```rust
24+
/// #[cfg(test)]
25+
/// mod my_cool_tests {
26+
/// // [...]
27+
/// }
28+
/// ```
29+
#[clippy::version = "1.70.0"]
30+
pub UNFLAGGED_TEST_MODULES,
31+
pedantic,
32+
"the testing module `my_cool_tests` wasn't marked with `#[cfg(test)]`"
33+
}
34+
declare_lint_pass!(UnflaggedTestModules => [UNFLAGGED_TEST_MODULES]);
35+
36+
impl LateLintPass<'_> for UnflaggedTestModules {
37+
fn check_item_post(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
38+
if let ItemKind::Mod(_) = item.kind {
39+
// If module name contains *test* or *tests*. This rules out things like my_super
40+
if item
41+
.ident
42+
.name
43+
.to_ident_string()
44+
.split('_')
45+
.any(|seg| seg == "test" || seg == "tests")
46+
{
47+
for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
48+
if_chain! {
49+
if attr.has_name(sym::cfg);
50+
if let Some(items) = attr.meta_item_list();
51+
if let [item] = &*items;
52+
if item.has_name(sym::test);
53+
then {
54+
return;
55+
}
56+
}
57+
}
58+
// If no #[cfg(test)] is found
59+
span_lint_and_sugg(
60+
cx,
61+
UNFLAGGED_TEST_MODULES,
62+
item.ident.span.with_lo(
63+
item.ident.span.lo() - BytePos(4), // Add `mod` keyword
64+
),
65+
"this testing module isn't flagged with #[cfg(test)]",
66+
"add the attribute",
67+
format!("#[cfg(test)]\nmod {}", item.ident.as_str()),
68+
rustc_errors::Applicability::MachineApplicable,
69+
);
70+
}
71+
}
72+
}
73+
}

tests/ui/unflagged_test_modules.fixed

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
// compile-flags: --test
3+
#![allow(unused)]
4+
#![warn(clippy::unflagged_test_modules)]
5+
6+
fn main() {
7+
// test code goes here
8+
}
9+
10+
#[cfg(test)]
11+
mod tests {
12+
fn my_test() {}
13+
}
14+
15+
#[cfg(test)]
16+
mod test {
17+
fn my_other_test() {}
18+
}

tests/ui/unflagged_test_modules.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// run-rustfix
2+
// compile-flags: --test
3+
#![allow(unused)]
4+
#![warn(clippy::unflagged_test_modules)]
5+
6+
fn main() {
7+
// test code goes here
8+
}
9+
10+
#[cfg(test)]
11+
mod tests {
12+
fn my_test() {}
13+
}
14+
15+
mod test {
16+
fn my_other_test() {}
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: this testing module isn't flagged with #[cfg(test)]
2+
--> $DIR/unflagged_test_modules.rs:15:1
3+
|
4+
LL | mod test {
5+
| ^^^^^^^^
6+
|
7+
= note: `-D clippy::unflagged-test-modules` implied by `-D warnings`
8+
help: add the attribute
9+
|
10+
LL + #[cfg(test)]
11+
LL ~ mod test {
12+
|
13+
14+
error: aborting due to previous error
15+

0 commit comments

Comments
 (0)