| use clippy_utils::diagnostics::span_lint_and_then; | |
| use clippy_utils::{is_in_cfg_test, is_in_test_function}; | |
| use rustc_hir::intravisit::FnKind; | |
| use rustc_hir::{Body, FnDecl}; | |
| use rustc_lint::{LateContext, LateLintPass}; | |
| use rustc_session::declare_lint_pass; | |
| use rustc_span::Span; | |
| use rustc_span::def_id::LocalDefId; | |
| 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 restrict this? | |
| /// 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 | |
| /// ```no_run | |
| /// #[test] | |
| /// fn my_cool_test() { | |
| /// // [...] | |
| /// } | |
| /// | |
| /// #[cfg(test)] | |
| /// mod tests { | |
| /// // [...] | |
| /// } | |
| /// | |
| /// ``` | |
| /// Use instead: | |
| /// ```no_run | |
| /// #[cfg(test)] | |
| /// mod tests { | |
| /// #[test] | |
| /// fn my_cool_test() { | |
| /// // [...] | |
| /// } | |
| /// } | |
| /// ``` | |
| #[clippy::version = "1.70.0"] | |
| pub TESTS_OUTSIDE_TEST_MODULE, | |
| restriction, | |
| "A test function is outside the testing module." | |
| } | |
| declare_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]); | |
| impl LateLintPass<'_> for TestsOutsideTestModule { | |
| fn check_fn( | |
| &mut self, | |
| cx: &LateContext<'_>, | |
| kind: FnKind<'_>, | |
| _: &FnDecl<'_>, | |
| body: &Body<'_>, | |
| sp: Span, | |
| _: LocalDefId, | |
| ) { | |
| if !matches!(kind, FnKind::Closure) | |
| && is_in_test_function(cx.tcx, body.id().hir_id) | |
| && !is_in_cfg_test(cx.tcx, body.id().hir_id) | |
| { | |
| #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] | |
| span_lint_and_then( | |
| cx, | |
| TESTS_OUTSIDE_TEST_MODULE, | |
| sp, | |
| "this function marked with #[test] is outside a #[cfg(test)] module", | |
| |diag| { | |
| diag.note("move it to a testing module marked with #[cfg(test)]"); | |
| }, | |
| ); | |
| } | |
| } | |
| } |