From 89314a08054cea924c807032ebdb62e031453bb3 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 13 Feb 2023 20:50:08 +0100 Subject: [PATCH] Add question-mark-used lint This lint complains when the question mark operator (try operator) is used. This is a restriction lint that can be useful on local scopes where a custom error handling macro is supposed to be used to augment the error based on local scope data before returning. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/question_mark_used.rs | 47 ++++++++++++++++++++++++++ tests/ui/question_mark_used.rs | 15 ++++++++ tests/ui/question_mark_used.stderr | 11 ++++++ 6 files changed, 77 insertions(+) create mode 100644 clippy_lints/src/question_mark_used.rs create mode 100644 tests/ui/question_mark_used.rs create mode 100644 tests/ui/question_mark_used.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 30727beb8e7..077e60af931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4675,6 +4675,7 @@ Released 2018-09-13 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use [`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark +[`question_mark_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark_used [`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index c1feabf05aa..61ce0c5a469 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -507,6 +507,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO, crate::pub_use::PUB_USE_INFO, crate::question_mark::QUESTION_MARK_INFO, + crate::question_mark_used::QUESTION_MARK_USED_INFO, crate::ranges::MANUAL_RANGE_CONTAINS_INFO, crate::ranges::RANGE_MINUS_ONE_INFO, crate::ranges::RANGE_PLUS_ONE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 565c5b7af00..e4926c0ed08 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -242,6 +242,7 @@ mod ptr; mod ptr_offset_with_cast; mod pub_use; mod question_mark; +mod question_mark_used; mod ranges; mod rc_clone_in_vec_init; mod read_zero_byte_vec; @@ -693,6 +694,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher)); store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom)); store.register_late_pass(|_| Box::new(question_mark::QuestionMark)); + store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed)); store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)); store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl)); store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit)); diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs new file mode 100644 index 00000000000..1a103dc35a4 --- /dev/null +++ b/clippy_lints/src/question_mark_used.rs @@ -0,0 +1,47 @@ +use clippy_utils::diagnostics::span_lint_and_help; + +use rustc_hir::{Expr, ExprKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions that use the question mark operator and rejects them. + /// + /// ### Why is this bad? + /// Sometimes code wants to avoid the question mark operator because for instance a local + /// block requires a macro to re-throw errors to attach additional information to the + /// error. + /// + /// ### Example + /// ```ignore + /// let result = expr?; + /// ``` + /// + /// Could be written: + /// + /// ```ignore + /// utility_macro!(expr); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub QUESTION_MARK_USED, + restriction, + "complains if the question mark operator is used" +} + +declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); + +impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind { + span_lint_and_help( + cx, + QUESTION_MARK_USED, + expr.span, + "question mark operator was used", + None, + "consider using a custom macro or match expression", + ); + } + } +} diff --git a/tests/ui/question_mark_used.rs b/tests/ui/question_mark_used.rs new file mode 100644 index 00000000000..8c3ef789697 --- /dev/null +++ b/tests/ui/question_mark_used.rs @@ -0,0 +1,15 @@ +// non rustfixable +#![allow(unreachable_code)] +#![allow(dead_code)] +#![warn(clippy::question_mark_used)] + +fn other_function() -> Option { + Some(32) +} + +fn my_function() -> Option { + other_function()?; + None +} + +fn main() {} diff --git a/tests/ui/question_mark_used.stderr b/tests/ui/question_mark_used.stderr new file mode 100644 index 00000000000..8b5fcbcdbfd --- /dev/null +++ b/tests/ui/question_mark_used.stderr @@ -0,0 +1,11 @@ +error: question mark operator was used + --> $DIR/question_mark_used.rs:11:5 + | +LL | other_function()?; + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using a custom macro or match expression + = note: `-D clippy::question-mark-used` implied by `-D warnings` + +error: aborting due to previous error +