-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #10578 - blyxyas:items_after_test_module, r=dswij
Add `items_after_test_module` lint Resolves task *3* of #10506, alongside *1* resolved at #10543 in an effort to help standarize a little bit more testing modules. --- changelog:[`items_after_test_module`]: Added the lint.
- Loading branch information
Showing
6 changed files
with
127 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use clippy_utils::{diagnostics::span_lint_and_help, is_in_cfg_test}; | ||
use rustc_hir::{HirId, ItemId, ItemKind, Mod}; | ||
use rustc_lint::{LateContext, LateLintPass, LintContext}; | ||
use rustc_middle::lint::in_external_macro; | ||
use rustc_session::{declare_lint_pass, declare_tool_lint}; | ||
use rustc_span::{sym, Span}; | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Triggers if an item is declared after the testing module marked with `#[cfg(test)]`. | ||
/// ### Why is this bad? | ||
/// Having items declared after the testing module is confusing and may lead to bad test coverage. | ||
/// ### Example | ||
/// ```rust | ||
/// #[cfg(test)] | ||
/// mod tests { | ||
/// // [...] | ||
/// } | ||
/// | ||
/// fn my_function() { | ||
/// // [...] | ||
/// } | ||
/// ``` | ||
/// Use instead: | ||
/// ```rust | ||
/// fn my_function() { | ||
/// // [...] | ||
/// } | ||
/// | ||
/// #[cfg(test)] | ||
/// mod tests { | ||
/// // [...] | ||
/// } | ||
/// ``` | ||
#[clippy::version = "1.70.0"] | ||
pub ITEMS_AFTER_TEST_MODULE, | ||
style, | ||
"An item was found after the testing module `tests`" | ||
} | ||
|
||
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]); | ||
|
||
impl LateLintPass<'_> for ItemsAfterTestModule { | ||
fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { | ||
let mut was_test_mod_visited = false; | ||
let mut test_mod_span: Option<Span> = None; | ||
|
||
let hir = cx.tcx.hir(); | ||
let items = hir.items().collect::<Vec<ItemId>>(); | ||
|
||
for (i, itid) in items.iter().enumerate() { | ||
let item = hir.item(*itid); | ||
|
||
if_chain! { | ||
if was_test_mod_visited; | ||
if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */); | ||
if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash | ||
== cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail | ||
if !matches!(item.kind, ItemKind::Mod(_)); | ||
if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself | ||
if !in_external_macro(cx.sess(), item.span); | ||
|
||
then { | ||
span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); | ||
}}; | ||
|
||
if matches!(item.kind, ItemKind::Mod(_)) { | ||
for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { | ||
if_chain! { | ||
if attr.has_name(sym::cfg); | ||
if let Some(mitems) = attr.meta_item_list(); | ||
if let [mitem] = &*mitems; | ||
if mitem.has_name(sym::test); | ||
then { | ||
was_test_mod_visited = true; | ||
test_mod_span = Some(item.span); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
//@compile-flags: --test | ||
#![allow(unused)] | ||
#![warn(clippy::items_after_test_module)] | ||
|
||
fn main() {} | ||
|
||
fn should_not_lint() {} | ||
|
||
#[allow(dead_code)] | ||
#[allow(unused)] // Some attributes to check that span replacement is good enough | ||
#[allow(clippy::allow_attributes)] | ||
#[cfg(test)] | ||
mod tests { | ||
#[test] | ||
fn hi() {} | ||
} | ||
|
||
fn should_lint() {} | ||
|
||
const SHOULD_ALSO_LINT: usize = 1; | ||
macro_rules! should_not_lint { | ||
() => {}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
error: items were found after the testing module | ||
--> $DIR/items_after_test_module.rs:13:1 | ||
| | ||
LL | / mod tests { | ||
LL | | #[test] | ||
LL | | fn hi() {} | ||
LL | | } | ||
... | | ||
LL | | () => {}; | ||
LL | | } | ||
| |_^ | ||
| | ||
= help: move the items to before the testing module was defined | ||
= note: `-D clippy::items-after-test-module` implied by `-D warnings` | ||
|
||
error: aborting due to previous error | ||
|