]> git.lizzy.rs Git - rust.git/blobdiff - clippy_utils/src/hir_utils.rs
Add testcases
[rust.git] / clippy_utils / src / hir_utils.rs
index 2fc12702f4829df8a311116adb96fa9b560e8517..7438b6eabf9e61f267670b1c3df24b4018414ebd 100644 (file)
@@ -2,20 +2,19 @@
 use crate::differing_macro_contexts;
 use crate::source::snippet_opt;
 use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
-    GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+    InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+    StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
-use rustc_middle::ich::StableHashingContextProvider;
 use rustc_middle::ty::TypeckResults;
 use rustc_span::Symbol;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 
 /// Type used to check whether two ast are the same. This is different from the
 /// operator
@@ -169,6 +168,12 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
         }
     }
 
+    pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
+        let cx = self.inner.cx;
+        let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
+        eval_const(left) == eval_const(right)
+    }
+
     #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
@@ -227,6 +232,7 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
+            (&ExprKind::Let(lp, le, _), &ExprKind::Let(rp, re, _)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
             (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
@@ -244,12 +250,7 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
-                let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
-                let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
-
-                self.eq_expr(le, re) && ll == rl
+                self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
@@ -285,8 +286,10 @@ fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
 
     fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
         match (left, right) {
+            (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
             (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
+            (GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()),
             _ => false,
         }
     }
@@ -385,10 +388,7 @@ fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
             (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
-                let cx = self.inner.cx;
-                let eval_const =
-                    |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
-                self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
+                self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
@@ -512,7 +512,7 @@ pub struct SpanlessHash<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-    s: StableHasher,
+    s: FxHasher,
 }
 
 impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
@@ -520,7 +520,7 @@ pub fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            s: StableHasher::new(),
+            s: FxHasher::default(),
         }
     }
 
@@ -537,16 +537,10 @@ pub fn hash_block(&mut self, b: &Block<'_>) {
             self.hash_expr(e);
         }
 
-        match b.rules {
-            BlockCheckMode::DefaultBlock => 0,
-            BlockCheckMode::UnsafeBlock(_) => 1,
-            BlockCheckMode::PushUnsafeBlock(_) => 2,
-            BlockCheckMode::PopUnsafeBlock(_) => 3,
-        }
-        .hash(&mut self.s);
+        std::mem::discriminant(&b.rules).hash(&mut self.s);
     }
 
-    #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
+    #[allow(clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr<'_>) {
         let simple_const = self
             .maybe_typeck_results
@@ -554,21 +548,16 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
-        simple_const.is_some().hash(&mut self.s);
-
-        if let Some(e) = simple_const {
-            return e.hash(&mut self.s);
+        simple_const.hash(&mut self.s);
+        if simple_const.is_some() {
+            return;
         }
 
         std::mem::discriminant(&e.kind).hash(&mut self.s);
 
         match e.kind {
             ExprKind::AddrOf(kind, m, e) => {
-                match kind {
-                    BorrowKind::Ref => 0,
-                    BorrowKind::Raw => 1,
-                }
-                .hash(&mut self.s);
+                std::mem::discriminant(&kind).hash(&mut self.s);
                 m.hash(&mut self.s);
                 self.hash_expr(e);
             },
@@ -582,8 +571,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 self.hash_expr(r);
             },
             ExprKind::AssignOp(ref o, l, r) => {
-                o.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&o.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
@@ -591,8 +579,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 self.hash_block(b);
             },
             ExprKind::Binary(op, l, r) => {
-                op.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&op.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
@@ -616,11 +603,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 self.hash_ty(ty);
             },
             ExprKind::Closure(cap, _, eid, _, _) => {
-                match cap {
-                    CaptureBy::Value => 0,
-                    CaptureBy::Ref => 1,
-                }
-                .hash(&mut self.s);
+                std::mem::discriminant(&cap).hash(&mut self.s);
                 // closures inherit TypeckResults
                 self.hash_expr(&self.cx.tcx.hir().body(eid).value);
             },
@@ -683,6 +666,10 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                     }
                 }
             },
+            ExprKind::Let(pat, expr, _) => {
+                self.hash_expr(expr);
+                self.hash_pat(pat);
+            },
             ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
@@ -694,8 +681,6 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 }
             },
             ExprKind::If(cond, then, ref else_opt) => {
-                let c: fn(_, _, _) -> _ = ExprKind::If;
-                c.hash(&mut self.s);
                 self.hash_expr(cond);
                 self.hash_expr(then);
                 if let Some(e) = *else_opt {
@@ -753,7 +738,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 self.hash_exprs(v);
             },
             ExprKind::Unary(lop, le) => {
-                lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
             },
         }
@@ -766,7 +751,7 @@ pub fn hash_exprs(&mut self, e: &[Expr<'_>]) {
     }
 
     pub fn hash_name(&mut self, n: Symbol) {
-        n.as_str().hash(&mut self.s);
+        n.hash(&mut self.s);
     }
 
     pub fn hash_qpath(&mut self, p: &QPath<'_>) {
@@ -778,7 +763,7 @@ pub fn hash_qpath(&mut self, p: &QPath<'_>) {
                 self.hash_name(path.ident.name);
             },
             QPath::LangItem(lang_item, ..) => {
-                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&lang_item).hash(&mut self.s);
             },
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
@@ -788,7 +773,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
             PatKind::Binding(ann, _, _, pat) => {
-                ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&ann).hash(&mut self.s);
                 if let Some(pat) = pat {
                     self.hash_pat(pat);
                 }
@@ -808,11 +793,11 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
                 if let Some(e) = e {
                     self.hash_expr(e);
                 }
-                i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&i).hash(&mut self.s);
             },
-            PatKind::Ref(pat, m) => {
+            PatKind::Ref(pat, mu) => {
                 self.hash_pat(pat);
-                m.hash(&mut self.s);
+                std::mem::discriminant(&mu).hash(&mut self.s);
             },
             PatKind::Slice(l, m, r) => {
                 for pat in l {
@@ -831,7 +816,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
                     self.hash_name(f.ident.name);
                     self.hash_pat(f.pat);
                 }
-                e.hash(&mut self.s)
+                e.hash(&mut self.s);
             },
             PatKind::Tuple(pats, e) => {
                 for pat in pats {
@@ -857,6 +842,7 @@ pub fn hash_path(&mut self, path: &Path<'_>) {
             _ => {
                 for seg in path.segments {
                     self.hash_name(seg.ident.name);
+                    self.hash_generic_args(seg.args().args);
                 }
             },
         }
@@ -905,7 +891,11 @@ pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
 
     pub fn hash_ty(&mut self, ty: &Ty<'_>) {
         std::mem::discriminant(&ty.kind).hash(&mut self.s);
-        match ty.kind {
+        self.hash_tykind(&ty.kind);
+    }
+
+    pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
+        match ty {
             TyKind::Slice(ty) => {
                 self.hash_ty(ty);
             },
@@ -918,7 +908,7 @@ pub fn hash_ty(&mut self, ty: &Ty<'_>) {
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::Rptr(lifetime, ref mut_ty) => {
-                self.hash_lifetime(lifetime);
+                self.hash_lifetime(*lifetime);
                 self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
@@ -928,10 +918,9 @@ pub fn hash_ty(&mut self, ty: &Ty<'_>) {
                 for arg in bfn.decl.inputs {
                     self.hash_ty(arg);
                 }
+                std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
                 match bfn.decl.output {
-                    FnRetTy::DefaultReturn(_) => {
-                        ().hash(&mut self.s);
-                    },
+                    FnRetTy::DefaultReturn(_) => {},
                     FnRetTy::Return(ty) => {
                         self.hash_ty(ty);
                     },
@@ -939,33 +928,16 @@ pub fn hash_ty(&mut self, ty: &Ty<'_>) {
                 bfn.decl.c_variadic.hash(&mut self.s);
             },
             TyKind::Tup(ty_list) => {
-                for ty in ty_list {
+                for ty in *ty_list {
                     self.hash_ty(ty);
                 }
             },
-            TyKind::Path(ref qpath) => match qpath {
-                QPath::Resolved(ref maybe_ty, path) => {
-                    if let Some(ty) = maybe_ty {
-                        self.hash_ty(ty);
-                    }
-                    for segment in path.segments {
-                        segment.ident.name.hash(&mut self.s);
-                        self.hash_generic_args(segment.args().args);
-                    }
-                },
-                QPath::TypeRelative(ty, segment) => {
-                    self.hash_ty(ty);
-                    segment.ident.name.hash(&mut self.s);
-                },
-                QPath::LangItem(lang_item, ..) => {
-                    lang_item.hash(&mut self.s);
-                },
-            },
+            TyKind::Path(ref qpath) => self.hash_qpath(qpath),
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
             },
             TyKind::TraitObject(_, lifetime, _) => {
-                self.hash_lifetime(lifetime);
+                self.hash_lifetime(*lifetime);
             },
             TyKind::Typeof(anon_const) => {
                 self.hash_body(anon_const.body);
@@ -987,6 +959,7 @@ fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
                 GenericArg::Lifetime(l) => self.hash_lifetime(l),
                 GenericArg::Type(ref ty) => self.hash_ty(ty),
                 GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
+                GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
             }
         }
     }