@@ -5,7 +5,9 @@ use rustc_hir::{Body, FnDecl};
55use rustc_lint:: { LateContext , LateLintPass } ;
66use rustc_session:: declare_lint_pass;
77use rustc_span:: def_id:: LocalDefId ;
8- use rustc_span:: Span ;
8+ use rustc_span:: source_map:: SourceMap ;
9+ use rustc_span:: { FileName , RealFileName , Span } ;
10+ use std:: path:: Component ;
911
1012declare_clippy_lint ! {
1113 /// ### What it does
@@ -15,6 +17,7 @@ declare_clippy_lint! {
1517 /// ### Why restrict this?
1618 /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`),
1719 /// having test functions outside of this module is confusing and may lead to them being "hidden".
20+ /// This does not apply to integration tests though, and this lint will ignore those.
1821 ///
1922 /// ### Example
2023 /// ```no_run
@@ -59,6 +62,7 @@ impl LateLintPass<'_> for TestsOutsideTestModule {
5962 ) {
6063 if !matches ! ( kind, FnKind :: Closure )
6164 && is_in_test_function ( cx. tcx , body. id ( ) . hir_id )
65+ && !is_integration_test ( cx. tcx . sess . source_map ( ) , sp)
6266 && !is_in_cfg_test ( cx. tcx , body. id ( ) . hir_id )
6367 {
6468 #[ expect( clippy:: collapsible_span_lint_calls, reason = "rust-clippy#7797" ) ]
@@ -74,3 +78,12 @@ impl LateLintPass<'_> for TestsOutsideTestModule {
7478 }
7579 }
7680}
81+
82+ fn is_integration_test ( sm : & SourceMap , sp : Span ) -> bool {
83+ match sm. span_to_filename ( sp) {
84+ FileName :: Real ( RealFileName :: LocalPath ( name) ) => {
85+ name. components ( ) . next ( ) == Some ( Component :: Normal ( "tests" . as_ref ( ) ) )
86+ } ,
87+ _ => false ,
88+ }
89+ }
0 commit comments