1 use clippy_utils::diagnostics::span_lint_and_help; 2 3 use clippy_utils::macros::span_is_local; 4 use rustc_hir::{Expr, ExprKind, MatchSource}; 5 use rustc_lint::{LateContext, LateLintPass}; 6 use rustc_session::{declare_lint_pass, declare_tool_lint}; 7 8 declare_clippy_lint! { 9 /// ### What it does 10 /// Checks for expressions that use the question mark operator and rejects them. 11 /// 12 /// ### Why is this bad? 13 /// Sometimes code wants to avoid the question mark operator because for instance a local 14 /// block requires a macro to re-throw errors to attach additional information to the 15 /// error. 16 /// 17 /// ### Example 18 /// ```ignore 19 /// let result = expr?; 20 /// ``` 21 /// 22 /// Could be written: 23 /// 24 /// ```ignore 25 /// utility_macro!(expr); 26 /// ``` 27 #[clippy::version = "1.69.0"] 28 pub QUESTION_MARK_USED, 29 restriction, 30 "complains if the question mark operator is used" 31 } 32 33 declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); 34 35 impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)36 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { 37 if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind { 38 if !span_is_local(expr.span) { 39 return; 40 } 41 42 span_lint_and_help( 43 cx, 44 QUESTION_MARK_USED, 45 expr.span, 46 "question mark operator was used", 47 None, 48 "consider using a custom macro or match expression", 49 ); 50 } 51 } 52 } 53