rust/clippy_lints/src/tests_outside_test_module.rs

74 lines
2.2 KiB
Rust
Raw Normal View History

2023-04-03 11:42:00 -05:00
use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function};
use rustc_hir::{intravisit::FnKind, Body, FnDecl};
2023-03-24 16:39:26 -05:00
use rustc_lint::{LateContext, LateLintPass};
2023-04-03 11:42:00 -05:00
use rustc_session::{declare_lint_pass, declare_tool_lint};
2023-03-24 16:39:26 -05:00
use rustc_span::{def_id::LocalDefId, Span};
declare_clippy_lint! {
/// ### What it does
///
/// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module (marked with `#[cfg(test)]`).
///
/// ### Why is this bad?
///
/// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), having test functions outside of this module is confusing and may lead to them being "hidden".
///
/// ### Example
/// ```rust
/// #[test]
/// fn my_cool_test() {
/// // [...]
/// }
///
/// #[cfg(test)]
/// mod tests {
/// // [...]
/// }
///
/// ```
/// Use instead:
/// ```rust
/// #[cfg(test)]
/// mod tests {
/// #[test]
/// fn my_cool_test() {
/// // [...]
/// }
/// }
/// ```
#[clippy::version = "1.70.0"]
pub TESTS_OUTSIDE_TEST_MODULE,
restriction,
"The test function `my_cool_test` is outside the testing module `tests`."
}
2023-04-03 11:42:00 -05:00
declare_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]);
2023-03-24 16:39:26 -05:00
impl LateLintPass<'_> for TestsOutsideTestModule {
fn check_fn(
&mut self,
cx: &LateContext<'_>,
kind: FnKind<'_>,
_: &FnDecl<'_>,
body: &Body<'_>,
sp: Span,
_: LocalDefId,
) {
if_chain! {
if !matches!(kind, FnKind::Closure);
if is_in_test_function(cx.tcx, body.id().hir_id);
if !is_in_cfg_test(cx.tcx, body.id().hir_id);
then {
span_lint_and_note(
cx,
TESTS_OUTSIDE_TEST_MODULE,
sp,
"this function marked with #[test] is outside a #[cfg(test)] module",
None,
"move it to a testing module marked with #[cfg(test)]",
);
}
}
}
}