diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 683ff650a49d..54e1e89bf3b6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -112,6 +112,7 @@ use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, TypeFlags, TypeVisitableExt, TypeckResults, UintTy, UpvarCapture, }; +use rustc_session::config::Input; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; @@ -2498,7 +2499,18 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { /// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]` pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { - is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id) + is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id) || is_in_integration_test_file(tcx) +} + +/// Check if the node is in an integration test file (i.e. under `tests/`). +fn is_in_integration_test_file(tcx: TyCtxt<'_>) -> bool { + if let Input::File(ref path) = tcx.sess.io.input + && !tcx.sess.opts.unstable_opts.ui_testing + { + path.starts_with("tests") + } else { + false + } } /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. diff --git a/tests/allow-unwrap-in-integration-tests.rs b/tests/allow-unwrap-in-integration-tests.rs new file mode 100644 index 000000000000..5aac56597e9c --- /dev/null +++ b/tests/allow-unwrap-in-integration-tests.rs @@ -0,0 +1,39 @@ +use std::path::PathBuf; +use std::process::Command; +use test_utils::{CARGO_CLIPPY_PATH, IS_RUSTC_TEST_SUITE}; + +mod test_utils; + +#[test] +fn test_allow_unwrap_in_integration_tests() { + if IS_RUSTC_TEST_SUITE { + return; + } + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let target_dir = root.join("target").join("integration_test"); + let cwd = root.join("tests/integration_test"); + + // Make sure we start with a clean state + Command::new("cargo") + .current_dir(&cwd) + .env("CARGO_TARGET_DIR", &target_dir) + .arg("clean") + .output() + .unwrap(); + + let output = Command::new(&*CARGO_CLIPPY_PATH) + .current_dir(&cwd) + .env("CARGO_INCREMENTAL", "0") + .env("CARGO_TARGET_DIR", &target_dir) + .arg("clippy") + .arg("--all-targets") + .arg("--") + .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir + .output() + .unwrap(); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + assert!(output.status.success()); +} diff --git a/tests/integration_test/Cargo.toml b/tests/integration_test/Cargo.toml new file mode 100644 index 000000000000..58f6e18c83cc --- /dev/null +++ b/tests/integration_test/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "integration_test" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[lints.clippy] +unwrap_used = "deny" diff --git a/tests/integration_test/clippy.toml b/tests/integration_test/clippy.toml new file mode 100644 index 000000000000..154626ef4e81 --- /dev/null +++ b/tests/integration_test/clippy.toml @@ -0,0 +1 @@ +allow-unwrap-in-tests = true diff --git a/tests/integration_test/src/main.rs b/tests/integration_test/src/main.rs new file mode 100644 index 000000000000..0856df57c137 --- /dev/null +++ b/tests/integration_test/src/main.rs @@ -0,0 +1,20 @@ +#![allow(clippy::disallowed_names)] + +fn main() { + println!("testing 123"); +} + +#[cfg(test)] +mod tests { + fn foo() -> Option { + Some(1) + } + + #[test] + fn integration_test() { + // should not lint in test file + // see https://github.com/rust-lang/rust-clippy/issues/13981 + let bar = foo().unwrap(); + println!("bar: {bar}"); + } +} diff --git a/tests/integration_test/tests/unwrap_in_integration.rs b/tests/integration_test/tests/unwrap_in_integration.rs new file mode 100644 index 000000000000..9cd8816446d9 --- /dev/null +++ b/tests/integration_test/tests/unwrap_in_integration.rs @@ -0,0 +1,20 @@ +#![allow(clippy::disallowed_names)] + +fn foo() -> Option { + Some(1) +} + +fn helper_function() { + // Should not lint in integration test file, see https://github.com/rust-lang/rust-clippy/issues/13981 + let baz = foo().unwrap(); + println!("baz: {baz}"); +} + +#[test] +fn integration_test() { + helper_function(); + + // Should not lint in integration test file, see https://github.com/rust-lang/rust-clippy/issues/13981 + let bar = foo().unwrap(); + println!("bar: {bar}"); +}