• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function};
2 use rustc_hir::{intravisit::FnKind, Body, FnDecl};
3 use rustc_lint::{LateContext, LateLintPass};
4 use rustc_session::{declare_lint_pass, declare_tool_lint};
5 use rustc_span::{def_id::LocalDefId, Span};
6 
7 declare_clippy_lint! {
8     /// ### What it does
9     /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module
10     /// (marked with `#[cfg(test)]`).
11     /// ### Why is this bad?
12     /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`),
13     /// having test functions outside of this module is confusing and may lead to them being "hidden".
14     /// ### Example
15     /// ```rust
16     /// #[test]
17     /// fn my_cool_test() {
18     ///     // [...]
19     /// }
20     ///
21     /// #[cfg(test)]
22     /// mod tests {
23     ///     // [...]
24     /// }
25     ///
26     /// ```
27     /// Use instead:
28     /// ```rust
29     /// #[cfg(test)]
30     /// mod tests {
31     ///     #[test]
32     ///     fn my_cool_test() {
33     ///         // [...]
34     ///     }
35     /// }
36     /// ```
37     #[clippy::version = "1.70.0"]
38     pub TESTS_OUTSIDE_TEST_MODULE,
39     restriction,
40     "A test function is outside the testing module."
41 }
42 
43 declare_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]);
44 
45 impl LateLintPass<'_> for TestsOutsideTestModule {
check_fn( &mut self, cx: &LateContext<'_>, kind: FnKind<'_>, _: &FnDecl<'_>, body: &Body<'_>, sp: Span, _: LocalDefId, )46     fn check_fn(
47         &mut self,
48         cx: &LateContext<'_>,
49         kind: FnKind<'_>,
50         _: &FnDecl<'_>,
51         body: &Body<'_>,
52         sp: Span,
53         _: LocalDefId,
54     ) {
55         if_chain! {
56             if !matches!(kind, FnKind::Closure);
57             if is_in_test_function(cx.tcx, body.id().hir_id);
58             if !is_in_cfg_test(cx.tcx, body.id().hir_id);
59             then {
60                 span_lint_and_note(
61                     cx,
62                     TESTS_OUTSIDE_TEST_MODULE,
63                     sp,
64                     "this function marked with #[test] is outside a #[cfg(test)] module",
65                     None,
66                     "move it to a testing module marked with #[cfg(test)]",
67                 );
68             }
69         }
70     }
71 }
72