about summary refs log tree commit diff
diff options
context:
space:
mode:
authorest31 <MTest31@outlook.com>2023-06-30 18:41:10 +0200
committerest31 <MTest31@outlook.com>2023-06-30 19:47:22 +0200
commit20dfaba0351d81748f2c1bbbb8a5e1d8bd77c3cb (patch)
tree2134569dad90dcb1a49b18c79b88a44d9a30d7bf
parentc6be62159ff6c100786a86b6a5687ded883ace5f (diff)
downloadrust-20dfaba0351d81748f2c1bbbb8a5e1d8bd77c3cb.tar.gz
rust-20dfaba0351d81748f2c1bbbb8a5e1d8bd77c3cb.zip
Put into one pass
-rw-r--r--clippy_lints/src/lib.rs3
-rw-r--r--clippy_lints/src/manual_let_else.rs77
-rw-r--r--clippy_lints/src/question_mark.rs72
3 files changed, 74 insertions, 78 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 5ab28b5c70c..771f13bda15 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -662,7 +662,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
     let matches_for_let_else = conf.matches_for_let_else;
-    store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else)));
     store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
     store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
     store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
@@ -771,7 +770,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
     store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
     store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
-    store.register_late_pass(|_| Box::<question_mark::QuestionMark>::default());
+    store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(msrv(), matches_for_let_else)));
     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));
diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index dcfc365a348..363018f1381 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -1,19 +1,19 @@
+use crate::question_mark::{pat_and_expr_can_be_question_mark, QuestionMark};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLetOrMatch;
-use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::msrvs;
+use clippy_utils::peel_blocks;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{Descend, Visitable};
-use clippy_utils::{is_refutable, is_res_lang_ctor, peel_blocks};
 use if_chain::if_chain;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::declare_tool_lint;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use serde::Deserialize;
@@ -51,25 +51,8 @@ declare_clippy_lint! {
     "manual implementation of a let...else statement"
 }
 
-pub struct ManualLetElse {
-    msrv: Msrv,
-    matches_behaviour: MatchLintBehaviour,
-}
-
-impl ManualLetElse {
-    #[must_use]
-    pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
-        Self {
-            msrv,
-            matches_behaviour,
-        }
-    }
-}
-
-impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
-    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
+impl<'tcx> QuestionMark {
+    pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
         if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
             return;
         }
@@ -130,8 +113,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
             }
         };
     }
-
-    extract_msrv_attr!(LateContext);
 }
 
 fn emit_manual_let_else(
@@ -169,50 +150,6 @@ fn emit_manual_let_else(
     );
 }
 
-/// Returns whether the given let pattern and else body can be turned into a question mark
-///
-/// For this example:
-/// ```ignore
-/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None };
-/// ```
-/// We get as parameters:
-/// ```ignore
-/// pat: Some(a)
-/// else_body: return None
-/// ```
-
-/// And for this example:
-/// ```ignore
-/// let Some(FooBar { a, b }) = ex else { return None };
-/// ```
-/// We get as parameters:
-/// ```ignore
-/// pat: Some(FooBar { a, b })
-/// else_body: return None
-/// ```
-
-/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
-/// the question mark operator is applicable here. Callers have to check whether we are in a
-/// constant or not.
-pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
-    cx: &LateContext<'_>,
-    pat: &'a Pat<'hir>,
-    else_body: &Expr<'_>,
-) -> Option<&'a Pat<'hir>> {
-    if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind &&
-        is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) &&
-        !is_refutable(cx, inner_pat) &&
-        let else_body = peel_blocks(else_body) &&
-        let ExprKind::Ret(Some(ret_val)) = else_body.kind &&
-        let ExprKind::Path(ret_path) = ret_val.kind &&
-        is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
-    {
-        Some(inner_pat)
-    } else {
-        None
-    }
-}
-
 /// Replaces the locals in the pattern
 ///
 /// For this example:
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index b1eeedc26bd..d473b6fd5c4 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -1,10 +1,11 @@
-use crate::manual_let_else::pat_and_expr_can_be_question_mark;
+use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
-    eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id,
-    peel_blocks, peel_blocks_with_stmt,
+    eq_expr_value, get_parent_node, in_constant, is_else_clause, is_refutable, is_res_lang_ctor, path_to_local,
+    path_to_local_id, peel_blocks, peel_blocks_with_stmt,
 };
 use clippy_utils::{higher, is_path_lang_item};
 use if_chain::if_chain;
@@ -12,7 +13,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
+    BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, Pat, PatKind, PathSegment, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -45,8 +46,9 @@ declare_clippy_lint! {
     "checks for expressions that could be replaced by the question mark operator"
 }
 
-#[derive(Default)]
 pub struct QuestionMark {
+    pub(crate) msrv: Msrv,
+    pub(crate) matches_behaviour: MatchLintBehaviour,
     /// Keeps track of how many try blocks we are in at any point during linting.
     /// This allows us to answer the question "are we inside of a try block"
     /// very quickly, without having to walk up the parent chain, by simply checking
@@ -54,7 +56,19 @@ pub struct QuestionMark {
     /// As for why we need this in the first place: <https://github.com/rust-lang/rust-clippy/issues/8628>
     try_block_depth_stack: Vec<u32>,
 }
-impl_lint_pass!(QuestionMark => [QUESTION_MARK]);
+
+impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]);
+
+impl QuestionMark {
+    #[must_use]
+    pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
+        Self {
+            msrv,
+            matches_behaviour,
+            try_block_depth_stack: Vec::new(),
+        }
+    }
+}
 
 enum IfBlockType<'hir> {
     /// An `if x.is_xxx() { a } else { b } ` expression.
@@ -81,6 +95,50 @@ enum IfBlockType<'hir> {
     ),
 }
 
+/// Returns whether the given let pattern and else body can be turned into a question mark
+///
+/// For this example:
+/// ```ignore
+/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None };
+/// ```
+/// We get as parameters:
+/// ```ignore
+/// pat: Some(a)
+/// else_body: return None
+/// ```
+
+/// And for this example:
+/// ```ignore
+/// let Some(FooBar { a, b }) = ex else { return None };
+/// ```
+/// We get as parameters:
+/// ```ignore
+/// pat: Some(FooBar { a, b })
+/// else_body: return None
+/// ```
+
+/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
+/// the question mark operator is applicable here. Callers have to check whether we are in a
+/// constant or not.
+pub(crate) fn pat_and_expr_can_be_question_mark<'a, 'hir>(
+    cx: &LateContext<'_>,
+    pat: &'a Pat<'hir>,
+    else_body: &Expr<'_>,
+) -> Option<&'a Pat<'hir>> {
+    if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind &&
+        is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) &&
+        !is_refutable(cx, inner_pat) &&
+        let else_body = peel_blocks(else_body) &&
+        let ExprKind::Ret(Some(ret_val)) = else_body.kind &&
+        let ExprKind::Path(ret_path) = ret_val.kind &&
+        is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
+    {
+        Some(inner_pat)
+    } else {
+        None
+    }
+}
+
 fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind &&
         let Block { stmts: &[], expr: Some(els), .. } = els &&
@@ -289,6 +347,7 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
         if !in_constant(cx, stmt.hir_id) {
             check_let_some_else_return_none(cx, stmt);
         }
+        self.check_manual_let_else(cx, stmt);
     }
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !in_constant(cx, expr.hir_id) {
@@ -322,4 +381,5 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
                 .expect("blocks are always part of bodies and must have a depth") -= 1;
         }
     }
+    extract_msrv_attr!(LateContext);
 }