about summary refs log tree commit diff
path: root/src/tools/clippy/clippy_utils
diff options
context:
space:
mode:
authorOli Scherer <github333195615777966@oli-obk.de>2024-12-11 16:50:45 +0000
committerOli Scherer <github333195615777966@oli-obk.de>2025-01-08 07:33:46 +0000
commitc9365dd09f30ff2df8fd335e80b82202ba9f8a85 (patch)
treeb840db73eb406f9ed1f566f41104a90131007966 /src/tools/clippy/clippy_utils
parent5df69191cb89dd5e5a23d01d0d69d0d507f45a77 (diff)
downloadrust-c9365dd09f30ff2df8fd335e80b82202ba9f8a85.tar.gz
rust-c9365dd09f30ff2df8fd335e80b82202ba9f8a85.zip
Exhaustively handle expressions in patterns
Diffstat (limited to 'src/tools/clippy/clippy_utils')
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs59
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs46
2 files changed, 76 insertions, 29 deletions
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 43ddf06730d..d46beddf731 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -4,7 +4,6 @@
 //! executable MIR bodies, so we have to do this instead.
 #![allow(clippy::float_cmp)]
 
-use crate::macros::HirNode;
 use crate::source::{SpanRangeExt, walk_span_to_context};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 
@@ -13,7 +12,7 @@ use rustc_apfloat::ieee::{Half, Quad};
 use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
+use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind};
 use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::ConstValue;
@@ -442,30 +441,48 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
         }
     }
 
+    pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant<'tcx>> {
+        match &pat_expr.kind {
+            PatExprKind::Lit { lit, negated } => {
+                let ty = self.typeck.node_type_opt(pat_expr.hir_id);
+                let val = lit_to_mir_constant(&lit.node, ty);
+                if *negated {
+                    self.constant_negate(&val, ty?)
+                } else {
+                    Some(val)
+                }
+            }
+            PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value),
+            PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
+        }
+    }
+
+    fn qpath(&self, qpath: &QPath<'_>, hir_id: HirId) -> Option<Constant<'tcx>> {
+        let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, hir_id).opt_def_id() {
+            self.tcx.crate_name(def_id.krate) == sym::core
+        } else {
+            false
+        };
+        self.fetch_path_and_apply(qpath, hir_id, self.typeck.node_type(hir_id), |self_, result| {
+            let result = mir_to_const(self_.tcx, result)?;
+            // If source is already Constant we wouldn't want to override it with CoreConstant
+            self_.source.set(
+                if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
+                    ConstantSource::CoreConstant
+                } else {
+                    ConstantSource::Constant
+                },
+            );
+            Some(result)
+        })
+    }
+
     /// Simple constant folding: Insert an expression, get a constant or none.
     fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
         match e.kind {
             ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
             ExprKind::DropTemps(e) => self.expr(e),
-            ExprKind::Path(ref qpath) => {
-                let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
-                    self.tcx.crate_name(def_id.krate) == sym::core
-                } else {
-                    false
-                };
-                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
-                    let result = mir_to_const(self_.tcx, result)?;
-                    // If source is already Constant we wouldn't want to override it with CoreConstant
-                    self_.source.set(
-                        if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
-                            ConstantSource::CoreConstant
-                        } else {
-                            ConstantSource::Constant
-                        },
-                    );
-                    Some(result)
-                })
-            },
+            ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
             ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(lit) => {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 7c4e834f841..b3b81412d08 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
     AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
     ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
-    Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
-    TyKind,
+    Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
+    TraitBoundModifiers, Ty, TyKind,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::LateContext;
@@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
         li.name == ri.name && self.eq_pat(lp, rp)
     }
 
+    fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
+        match (&left.kind, &right.kind) {
+            (
+                &PatExprKind::Lit {
+                    lit: left,
+                    negated: left_neg,
+                },
+                &PatExprKind::Lit {
+                    lit: right,
+                    negated: right_neg,
+                },
+            ) => left_neg == right_neg && left.node == right.node,
+            (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
+            (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
+            (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
+        }
+    }
+
     /// Checks whether two patterns are the same.
     fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
@@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
                 eq
             },
             (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
-            (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+            (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_pat_expr(l, r),
             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
-                both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b))
-                    && both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b))
+                both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b))
+                    && both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
                     && (li == ri)
             },
             (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
@@ -1073,6 +1091,18 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
     }
 
+    pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) {
+        std::mem::discriminant(&lit.kind).hash(&mut self.s);
+        match &lit.kind {
+            PatExprKind::Lit { lit, negated } => {
+                lit.node.hash(&mut self.s);
+                negated.hash(&mut self.s);
+            },
+            PatExprKind::ConstBlock(c) => self.hash_body(c.body),
+            PatExprKind::Path(qpath) => self.hash_qpath(qpath),
+        }
+    }
+
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
@@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
-            PatKind::Lit(expr) => self.hash_expr(expr),
+            PatKind::Lit(expr) => self.hash_pat_expr(expr),
             PatKind::Or(pats) => {
                 for pat in pats {
                     self.hash_pat(pat);
@@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             PatKind::Path(ref qpath) => self.hash_qpath(qpath),
             PatKind::Range(s, e, i) => {
                 if let Some(s) = s {
-                    self.hash_expr(s);
+                    self.hash_pat_expr(s);
                 }
                 if let Some(e) = e {
-                    self.hash_expr(e);
+                    self.hash_pat_expr(e);
                 }
                 std::mem::discriminant(&i).hash(&mut self.s);
             },