From b0b03047b6bfac511f4433408f3dab770ecede79 Mon Sep 17 00:00:00 2001 From: Daniel Sommermann Date: Thu, 6 Aug 2026 15:43:14 -0700 Subject: [PATCH] Add `allow-panic-in-result-fn-in-tests` configuration Add a dedicated test exemption for `panic_in_result_fn` rather than broadening `allow-panic-in-tests`, since this lint also covers assertions. Apply it to test functions and code under `#[cfg(test)]`. changelog: [`panic_in_result_fn`]: add `allow-panic-in-result-fn-in-tests` to allow panics and assertions in tests --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 10 ++++++ clippy_config/src/conf.rs | 3 ++ clippy_lints/src/lib.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 31 +++++++++++++++---- tests/ui-toml/panic_in_result_fn/clippy.toml | 1 + .../panic_in_result_fn/panic_in_result_fn.rs | 24 ++++++++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 1 + 8 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 tests/ui-toml/panic_in_result_fn/clippy.toml create mode 100644 tests/ui-toml/panic_in_result_fn/panic_in_result_fn.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 3876af9b2f37..b2031d748f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7674,6 +7674,7 @@ Released 2018-09-13 [`allow-large-stack-frames-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-large-stack-frames-in-tests [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings +[`allow-panic-in-result-fn-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-result-fn-in-tests [`allow-panic-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-tests [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 6869cc56ed95..3a4490d6f655 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -141,6 +141,16 @@ Whether to allow `r#""#` when `r""` can be used * [`needless_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes) +## `allow-panic-in-result-fn-in-tests` +Whether `panic_in_result_fn` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`panic_in_result_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn) + + ## `allow-panic-in-tests` Whether `panic` should be allowed in test functions or `#[cfg(test)]` diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 13c73e944581..bcec8a0327ae 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -259,6 +259,9 @@ define_Conf! { /// Whether to allow `r#""#` when `r""` can be used #[lints(needless_raw_string_hashes)] allow_one_hash_in_raw_strings("allow-one-hash-in-raw-strings"): bool = false, + /// Whether `panic_in_result_fn` should be allowed in test functions or `#[cfg(test)]` + #[lints(panic_in_result_fn)] + allow_panic_in_result_fn_in_tests("allow-panic-in-result-fn-in-tests"): bool = false, /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` #[lints(panic)] allow_panic_in_tests("allow-panic-in-tests"): bool = false, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8b0765fb6c01..d75a124fef14 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -704,7 +704,7 @@ rustc_lint::late_lint_methods!( IfNotElse: if_not_else::IfNotElse = if_not_else::IfNotElse, PatternEquality: equatable_if_let::PatternEquality = equatable_if_let::PatternEquality, ManualAsyncFn: manual_async_fn::ManualAsyncFn = manual_async_fn::ManualAsyncFn, - PanicInResultFn: panic_in_result_fn::PanicInResultFn = panic_in_result_fn::PanicInResultFn, + PanicInResultFn: panic_in_result_fn::PanicInResultFn = panic_in_result_fn::PanicInResultFn::new(conf), MacroUseImports: macro_use::MacroUseImports = ::default(), PatternTypeMismatch: pattern_type_mismatch::PatternTypeMismatch = pattern_type_mismatch::PatternTypeMismatch, UnwrapInResult: unwrap_in_result::UnwrapInResult = ::default(), diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 08c316af42b0..a5879f73bf1e 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,13 +1,14 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::res::MaybeDef as _; use clippy_utils::visitors::{Descend, for_each_expr}; -use clippy_utils::{is_inside_always_const_context, return_ty}; +use clippy_utils::{is_in_test, is_inside_always_const_context, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -40,7 +41,19 @@ declare_clippy_lint! { "functions of type `Result<..>` that contain `panic!()` or assertion" } -declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]); +impl_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]); + +pub struct PanicInResultFn { + allow_panic_in_result_fn_in_tests: bool, +} + +impl PanicInResultFn { + pub fn new(conf: &'static Conf) -> Self { + Self { + allow_panic_in_result_fn_in_tests: conf.allow_panic_in_result_fn_in_tests, + } + } +} impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn check_fn( @@ -57,18 +70,24 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { } let owner = cx.tcx.local_def_id_to_hir_id(def_id).expect_owner(); if return_ty(cx, owner).is_diag_item(cx, sym::Result) { - lint_impl_body(cx, span, body); + lint_impl_body(cx, span, body, self.allow_panic_in_result_fn_in_tests); } } } -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { +fn lint_impl_body<'tcx>( + cx: &LateContext<'tcx>, + impl_span: Span, + body: &'tcx hir::Body<'tcx>, + allow_panic_in_result_fn_in_tests: bool, +) { let mut panics = Vec::new(); let _: Option = for_each_expr(cx.tcx, body.value, |e| { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; - if !is_inside_always_const_context(cx.tcx, e.hir_id) + if !(is_inside_always_const_context(cx.tcx, e.hir_id) + || allow_panic_in_result_fn_in_tests && is_in_test(cx.tcx, e.hir_id)) && (is_panic(cx, macro_call.def_id) || matches!( cx.tcx.get_diagnostic_name(macro_call.def_id), diff --git a/tests/ui-toml/panic_in_result_fn/clippy.toml b/tests/ui-toml/panic_in_result_fn/clippy.toml new file mode 100644 index 000000000000..d56fc54b54f0 --- /dev/null +++ b/tests/ui-toml/panic_in_result_fn/clippy.toml @@ -0,0 +1 @@ +allow-panic-in-result-fn-in-tests = true diff --git a/tests/ui-toml/panic_in_result_fn/panic_in_result_fn.rs b/tests/ui-toml/panic_in_result_fn/panic_in_result_fn.rs new file mode 100644 index 000000000000..58f0fb6b1cf2 --- /dev/null +++ b/tests/ui-toml/panic_in_result_fn/panic_in_result_fn.rs @@ -0,0 +1,24 @@ +//@compile-flags: --test +//@check-pass +#![warn(clippy::panic_in_result_fn)] +#![allow(clippy::unnecessary_wraps)] + +#[test] +fn test_function() -> Result<(), ()> { + cfg_test_function()?; + assert!(std::hint::black_box(false)); + tests::helper() +} + +#[cfg(test)] +fn cfg_test_function() -> Result<(), ()> { + panic!(); +} + +#[cfg(test)] +mod tests { + pub(super) fn helper() -> Result<(), ()> { + assert_eq!(std::hint::black_box(1), 2); + Ok(()) + } +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index bee9e63ef742..03ea8b0635ea 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -18,6 +18,7 @@ LL | foobar = 42 allow-large-stack-frames-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings + allow-panic-in-result-fn-in-tests allow-panic-in-tests allow-print-in-tests allow-private-module-inception