]> git.lizzy.rs Git - rust.git/blob - clippy_utils/src/hir_utils.rs
Add manual_bits lint
[rust.git] / clippy_utils / src / hir_utils.rs
1 use crate::consts::{constant_context, constant_simple};
2 use crate::differing_macro_contexts;
3 use crate::source::snippet_opt;
4 use rustc_ast::ast::InlineAsmTemplatePiece;
5 use rustc_data_structures::fx::FxHasher;
6 use rustc_hir::def::Res;
7 use rustc_hir::HirIdMap;
8 use rustc_hir::{
9     BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
10     InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
11     StmtKind, Ty, TyKind, TypeBinding,
12 };
13 use rustc_lexer::{tokenize, TokenKind};
14 use rustc_lint::LateContext;
15 use rustc_middle::ty::TypeckResults;
16 use rustc_span::Symbol;
17 use std::hash::{Hash, Hasher};
18
19 /// Type used to check whether two ast are the same. This is different from the
20 /// operator
21 /// `==` on ast types as this operator would compare true equality with ID and
22 /// span.
23 ///
24 /// Note that some expressions kinds are not considered but could be added.
25 pub struct SpanlessEq<'a, 'tcx> {
26     /// Context used to evaluate constant expressions.
27     cx: &'a LateContext<'tcx>,
28     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
29     allow_side_effects: bool,
30     expr_fallback: Option<Box<dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
31 }
32
33 impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
34     pub fn new(cx: &'a LateContext<'tcx>) -> Self {
35         Self {
36             cx,
37             maybe_typeck_results: cx.maybe_typeck_results(),
38             allow_side_effects: true,
39             expr_fallback: None,
40         }
41     }
42
43     /// Consider expressions containing potential side effects as not equal.
44     #[must_use]
45     pub fn deny_side_effects(self) -> Self {
46         Self {
47             allow_side_effects: false,
48             ..self
49         }
50     }
51
52     #[must_use]
53     pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
54         Self {
55             expr_fallback: Some(Box::new(expr_fallback)),
56             ..self
57         }
58     }
59
60     /// Use this method to wrap comparisons that may involve inter-expression context.
61     /// See `self.locals`.
62     pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
63         HirEqInterExpr {
64             inner: self,
65             locals: HirIdMap::default(),
66         }
67     }
68
69     #[allow(dead_code)]
70     pub fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
71         self.inter_expr().eq_block(left, right)
72     }
73
74     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
75         self.inter_expr().eq_expr(left, right)
76     }
77
78     pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
79         self.inter_expr().eq_path_segment(left, right)
80     }
81
82     pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
83         self.inter_expr().eq_path_segments(left, right)
84     }
85 }
86
87 pub struct HirEqInterExpr<'a, 'b, 'tcx> {
88     inner: &'a mut SpanlessEq<'b, 'tcx>,
89
90     // When binding are declared, the binding ID in the left expression is mapped to the one on the
91     // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`,
92     // these blocks are considered equal since `x` is mapped to `y`.
93     locals: HirIdMap<HirId>,
94 }
95
96 impl HirEqInterExpr<'_, '_, '_> {
97     pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
98         match (&left.kind, &right.kind) {
99             (&StmtKind::Local(l), &StmtKind::Local(r)) => {
100                 // This additional check ensures that the type of the locals are equivalent even if the init
101                 // expression or type have some inferred parts.
102                 if let Some(typeck) = self.inner.maybe_typeck_results {
103                     let l_ty = typeck.pat_ty(l.pat);
104                     let r_ty = typeck.pat_ty(r.pat);
105                     if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) {
106                         return false;
107                     }
108                 }
109
110                 // eq_pat adds the HirIds to the locals map. We therefor call it last to make sure that
111                 // these only get added if the init and type is equal.
112                 both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
113                     && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
114                     && self.eq_pat(l.pat, r.pat)
115             },
116             (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
117             _ => false,
118         }
119     }
120
121     /// Checks whether two blocks are the same.
122     fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
123         match (left.stmts, left.expr, right.stmts, right.expr) {
124             ([], None, [], None) => {
125                 // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro
126                 // expanded to nothing, or the cfg attribute was used.
127                 let (left, right) = match (
128                     snippet_opt(self.inner.cx, left.span),
129                     snippet_opt(self.inner.cx, right.span),
130                 ) {
131                     (Some(left), Some(right)) => (left, right),
132                     _ => return true,
133                 };
134                 let mut left_pos = 0;
135                 let left = tokenize(&left)
136                     .map(|t| {
137                         let end = left_pos + t.len;
138                         let s = &left[left_pos..end];
139                         left_pos = end;
140                         (t, s)
141                     })
142                     .filter(|(t, _)| {
143                         !matches!(
144                             t.kind,
145                             TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
146                         )
147                     })
148                     .map(|(_, s)| s);
149                 let mut right_pos = 0;
150                 let right = tokenize(&right)
151                     .map(|t| {
152                         let end = right_pos + t.len;
153                         let s = &right[right_pos..end];
154                         right_pos = end;
155                         (t, s)
156                     })
157                     .filter(|(t, _)| {
158                         !matches!(
159                             t.kind,
160                             TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
161                         )
162                     })
163                     .map(|(_, s)| s);
164                 left.eq(right)
165             },
166             _ => {
167                 over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
168                     && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
169             },
170         }
171     }
172
173     pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
174         let cx = self.inner.cx;
175         let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
176         eval_const(left) == eval_const(right)
177     }
178
179     #[allow(clippy::similar_names)]
180     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
181         if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
182             return false;
183         }
184
185         if let Some(typeck_results) = self.inner.maybe_typeck_results {
186             if let (Some(l), Some(r)) = (
187                 constant_simple(self.inner.cx, typeck_results, left),
188                 constant_simple(self.inner.cx, typeck_results, right),
189             ) {
190                 if l == r {
191                     return true;
192                 }
193             }
194         }
195
196         let is_eq = match (
197             &reduce_exprkind(self.inner.cx, &left.kind),
198             &reduce_exprkind(self.inner.cx, &right.kind),
199         ) {
200             (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
201                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
202             },
203             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
204                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
205             },
206             (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
207                 self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
208             },
209             (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
210                 self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
211             },
212             (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
213             (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
214                 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
215                     || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
216                         l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
217                     })
218             },
219             (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => {
220                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
221                     && both(le, re, |l, r| self.eq_expr(l, r))
222             },
223             (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
224             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
225                 self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
226             },
227             (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => {
228                 self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
229             },
230             (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
231                 l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
232             },
233             (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
234             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
235                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
236             },
237             (&ExprKind::Let(l), &ExprKind::Let(r)) => {
238                 self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
239             },
240             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
241             (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
242                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
243             },
244             (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
245                 ls == rs
246                     && self.eq_expr(le, re)
247                     && over(la, ra, |l, r| {
248                         self.eq_pat(l.pat, r.pat)
249                             && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
250                             && self.eq_expr(l.body, r.body)
251                     })
252             },
253             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
254                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
255             },
256             (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
257                 self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
258             },
259             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
260             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
261             (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
262                 self.eq_qpath(l_path, r_path)
263                     && both(lo, ro, |l, r| self.eq_expr(l, r))
264                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
265             },
266             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
267             (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
268             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
269             (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
270             _ => false,
271         };
272         is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
273     }
274
275     fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
276         over(left, right, |l, r| self.eq_expr(l, r))
277     }
278
279     fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool {
280         left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
281     }
282
283     fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
284         match (left, right) {
285             (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r),
286             (Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
287             _ => false,
288         }
289     }
290
291     fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
292         match (left, right) {
293             (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
294             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
295             (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
296             (GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()),
297             _ => false,
298         }
299     }
300
301     fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool {
302         left.name == right.name
303     }
304
305     fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool {
306         let (PatField { ident: li, pat: lp, .. }, PatField { ident: ri, pat: rp, .. }) = (&left, &right);
307         li.name == ri.name && self.eq_pat(lp, rp)
308     }
309
310     /// Checks whether two patterns are the same.
311     fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
312         match (&left.kind, &right.kind) {
313             (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
314             (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
315                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
316             },
317             (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
318                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
319             },
320             (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
321                 let eq = lb == rb && both(lp, rp, |l, r| self.eq_pat(l, r));
322                 if eq {
323                     self.locals.insert(li, ri);
324                 }
325                 eq
326             },
327             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
328             (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
329             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
330             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
331                 both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
332             },
333             (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
334             (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
335                 over(ls, rs, |l, r| self.eq_pat(l, r))
336                     && over(le, re, |l, r| self.eq_pat(l, r))
337                     && both(li, ri, |l, r| self.eq_pat(l, r))
338             },
339             (&PatKind::Wild, &PatKind::Wild) => true,
340             _ => false,
341         }
342     }
343
344     #[allow(clippy::similar_names)]
345     fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
346         match (left, right) {
347             (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
348                 both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
349             },
350             (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
351                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
352             },
353             (&QPath::LangItem(llang_item, ..), &QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item,
354             _ => false,
355         }
356     }
357
358     fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool {
359         match (left.res, right.res) {
360             (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
361             (Res::Local(_), _) | (_, Res::Local(_)) => false,
362             _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)),
363         }
364     }
365
366     fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
367         if !(left.parenthesized || right.parenthesized) {
368             over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
369                 && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
370         } else if left.parenthesized && right.parenthesized {
371             over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
372                 && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
373                     self.eq_ty(l, r)
374                 })
375         } else {
376             false
377         }
378     }
379
380     pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
381         left.len() == right.len() && left.iter().zip(right).all(|(l, r)| self.eq_path_segment(l, r))
382     }
383
384     pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
385         // The == of idents doesn't work with different contexts,
386         // we have to be explicit about hygiene
387         left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
388     }
389
390     #[allow(clippy::similar_names)]
391     pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
392         match (&left.kind, &right.kind) {
393             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
394             (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
395                 self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
396             },
397             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
398                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
399             },
400             (&TyKind::Rptr(_, ref l_rmut), &TyKind::Rptr(_, ref r_rmut)) => {
401                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
402             },
403             (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
404             (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
405             (&TyKind::Infer, &TyKind::Infer) => true,
406             _ => false,
407         }
408     }
409
410     fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
411         left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
412     }
413 }
414
415 /// Some simple reductions like `{ return }` => `return`
416 fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &'hir ExprKind<'hir> {
417     if let ExprKind::Block(block, _) = kind {
418         match (block.stmts, block.expr) {
419             // From an `if let` expression without an `else` block. The arm for the implicit wild pattern is an empty
420             // block with an empty span.
421             ([], None) if block.span.is_empty() => &ExprKind::Tup(&[]),
422             // `{}` => `()`
423             ([], None) => match snippet_opt(cx, block.span) {
424                 // Don't reduce if there are any tokens contained in the braces
425                 Some(snip)
426                     if tokenize(&snip)
427                         .map(|t| t.kind)
428                         .filter(|t| {
429                             !matches!(
430                                 t,
431                                 TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
432                             )
433                         })
434                         .ne([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) =>
435                 {
436                     kind
437                 },
438                 _ => &ExprKind::Tup(&[]),
439             },
440             ([], Some(expr)) => match expr.kind {
441                 // `{ return .. }` => `return ..`
442                 ExprKind::Ret(..) => &expr.kind,
443                 _ => kind,
444             },
445             ([stmt], None) => match stmt.kind {
446                 StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
447                     // `{ return ..; }` => `return ..`
448                     ExprKind::Ret(..) => &expr.kind,
449                     _ => kind,
450                 },
451                 _ => kind,
452             },
453             _ => kind,
454         }
455     } else {
456         kind
457     }
458 }
459
460 fn swap_binop<'a>(
461     binop: BinOpKind,
462     lhs: &'a Expr<'a>,
463     rhs: &'a Expr<'a>,
464 ) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> {
465     match binop {
466         BinOpKind::Add | BinOpKind::Eq | BinOpKind::Ne | BinOpKind::BitAnd | BinOpKind::BitXor | BinOpKind::BitOr => {
467             Some((binop, rhs, lhs))
468         },
469         BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)),
470         BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)),
471         BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)),
472         BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)),
473         BinOpKind::Mul // Not always commutative, e.g. with matrices. See issue #5698
474         | BinOpKind::Shl
475         | BinOpKind::Shr
476         | BinOpKind::Rem
477         | BinOpKind::Sub
478         | BinOpKind::Div
479         | BinOpKind::And
480         | BinOpKind::Or => None,
481     }
482 }
483
484 /// Checks if the two `Option`s are both `None` or some equal values as per
485 /// `eq_fn`.
486 pub fn both<X>(l: &Option<X>, r: &Option<X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
487     l.as_ref()
488         .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
489 }
490
491 /// Checks if two slices are equal as per `eq_fn`.
492 pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
493     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
494 }
495
496 /// Counts how many elements of the slices are equal as per `eq_fn`.
497 pub fn count_eq<X: Sized>(
498     left: &mut dyn Iterator<Item = X>,
499     right: &mut dyn Iterator<Item = X>,
500     mut eq_fn: impl FnMut(&X, &X) -> bool,
501 ) -> usize {
502     left.zip(right).take_while(|(l, r)| eq_fn(l, r)).count()
503 }
504
505 /// Checks if two expressions evaluate to the same value, and don't contain any side effects.
506 pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool {
507     SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right)
508 }
509
510 /// Type used to hash an ast element. This is different from the `Hash` trait
511 /// on ast types as this
512 /// trait would consider IDs and spans.
513 ///
514 /// All expressions kind are hashed, but some might have a weaker hash.
515 pub struct SpanlessHash<'a, 'tcx> {
516     /// Context used to evaluate constant expressions.
517     cx: &'a LateContext<'tcx>,
518     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
519     s: FxHasher,
520 }
521
522 impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
523     pub fn new(cx: &'a LateContext<'tcx>) -> Self {
524         Self {
525             cx,
526             maybe_typeck_results: cx.maybe_typeck_results(),
527             s: FxHasher::default(),
528         }
529     }
530
531     pub fn finish(self) -> u64 {
532         self.s.finish()
533     }
534
535     pub fn hash_block(&mut self, b: &Block<'_>) {
536         for s in b.stmts {
537             self.hash_stmt(s);
538         }
539
540         if let Some(e) = b.expr {
541             self.hash_expr(e);
542         }
543
544         std::mem::discriminant(&b.rules).hash(&mut self.s);
545     }
546
547     #[allow(clippy::too_many_lines)]
548     pub fn hash_expr(&mut self, e: &Expr<'_>) {
549         let simple_const = self
550             .maybe_typeck_results
551             .and_then(|typeck_results| constant_simple(self.cx, typeck_results, e));
552
553         // const hashing may result in the same hash as some unrelated node, so add a sort of
554         // discriminant depending on which path we're choosing next
555         simple_const.hash(&mut self.s);
556         if simple_const.is_some() {
557             return;
558         }
559
560         std::mem::discriminant(&e.kind).hash(&mut self.s);
561
562         match e.kind {
563             ExprKind::AddrOf(kind, m, e) => {
564                 std::mem::discriminant(&kind).hash(&mut self.s);
565                 m.hash(&mut self.s);
566                 self.hash_expr(e);
567             },
568             ExprKind::Continue(i) => {
569                 if let Some(i) = i.label {
570                     self.hash_name(i.ident.name);
571                 }
572             },
573             ExprKind::Assign(l, r, _) => {
574                 self.hash_expr(l);
575                 self.hash_expr(r);
576             },
577             ExprKind::AssignOp(ref o, l, r) => {
578                 std::mem::discriminant(&o.node).hash(&mut self.s);
579                 self.hash_expr(l);
580                 self.hash_expr(r);
581             },
582             ExprKind::Block(b, _) => {
583                 self.hash_block(b);
584             },
585             ExprKind::Binary(op, l, r) => {
586                 std::mem::discriminant(&op.node).hash(&mut self.s);
587                 self.hash_expr(l);
588                 self.hash_expr(r);
589             },
590             ExprKind::Break(i, ref j) => {
591                 if let Some(i) = i.label {
592                     self.hash_name(i.ident.name);
593                 }
594                 if let Some(j) = *j {
595                     self.hash_expr(&*j);
596                 }
597             },
598             ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
599                 self.hash_expr(e);
600             },
601             ExprKind::Call(fun, args) => {
602                 self.hash_expr(fun);
603                 self.hash_exprs(args);
604             },
605             ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => {
606                 self.hash_expr(e);
607                 self.hash_ty(ty);
608             },
609             ExprKind::Closure(cap, _, eid, _, _) => {
610                 std::mem::discriminant(&cap).hash(&mut self.s);
611                 // closures inherit TypeckResults
612                 self.hash_expr(&self.cx.tcx.hir().body(eid).value);
613             },
614             ExprKind::Field(e, ref f) => {
615                 self.hash_expr(e);
616                 self.hash_name(f.name);
617             },
618             ExprKind::Index(a, i) => {
619                 self.hash_expr(a);
620                 self.hash_expr(i);
621             },
622             ExprKind::InlineAsm(asm) => {
623                 for piece in asm.template {
624                     match piece {
625                         InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
626                         InlineAsmTemplatePiece::Placeholder {
627                             operand_idx,
628                             modifier,
629                             span: _,
630                         } => {
631                             operand_idx.hash(&mut self.s);
632                             modifier.hash(&mut self.s);
633                         },
634                     }
635                 }
636                 asm.options.hash(&mut self.s);
637                 for (op, _op_sp) in asm.operands {
638                     match op {
639                         InlineAsmOperand::In { reg, expr } => {
640                             reg.hash(&mut self.s);
641                             self.hash_expr(expr);
642                         },
643                         InlineAsmOperand::Out { reg, late, expr } => {
644                             reg.hash(&mut self.s);
645                             late.hash(&mut self.s);
646                             if let Some(expr) = expr {
647                                 self.hash_expr(expr);
648                             }
649                         },
650                         InlineAsmOperand::InOut { reg, late, expr } => {
651                             reg.hash(&mut self.s);
652                             late.hash(&mut self.s);
653                             self.hash_expr(expr);
654                         },
655                         InlineAsmOperand::SplitInOut {
656                             reg,
657                             late,
658                             in_expr,
659                             out_expr,
660                         } => {
661                             reg.hash(&mut self.s);
662                             late.hash(&mut self.s);
663                             self.hash_expr(in_expr);
664                             if let Some(out_expr) = out_expr {
665                                 self.hash_expr(out_expr);
666                             }
667                         },
668                         InlineAsmOperand::Const { anon_const } => self.hash_body(anon_const.body),
669                         InlineAsmOperand::Sym { expr } => self.hash_expr(expr),
670                     }
671                 }
672             },
673             ExprKind::Let(Let { pat, init, ty, .. }) => {
674                 self.hash_expr(init);
675                 if let Some(ty) = ty {
676                     self.hash_ty(ty);
677                 }
678                 self.hash_pat(pat);
679             },
680             ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},
681             ExprKind::Lit(ref l) => {
682                 l.node.hash(&mut self.s);
683             },
684             ExprKind::Loop(b, ref i, ..) => {
685                 self.hash_block(b);
686                 if let Some(i) = *i {
687                     self.hash_name(i.ident.name);
688                 }
689             },
690             ExprKind::If(cond, then, ref else_opt) => {
691                 self.hash_expr(cond);
692                 self.hash_expr(then);
693                 if let Some(e) = *else_opt {
694                     self.hash_expr(e);
695                 }
696             },
697             ExprKind::Match(e, arms, ref s) => {
698                 self.hash_expr(e);
699
700                 for arm in arms {
701                     self.hash_pat(arm.pat);
702                     if let Some(ref e) = arm.guard {
703                         self.hash_guard(e);
704                     }
705                     self.hash_expr(arm.body);
706                 }
707
708                 s.hash(&mut self.s);
709             },
710             ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => {
711                 self.hash_name(path.ident.name);
712                 self.hash_exprs(args);
713             },
714             ExprKind::ConstBlock(ref l_id) => {
715                 self.hash_body(l_id.body);
716             },
717             ExprKind::Repeat(e, ref l_id) => {
718                 self.hash_expr(e);
719                 self.hash_body(l_id.body);
720             },
721             ExprKind::Ret(ref e) => {
722                 if let Some(e) = *e {
723                     self.hash_expr(e);
724                 }
725             },
726             ExprKind::Path(ref qpath) => {
727                 self.hash_qpath(qpath);
728             },
729             ExprKind::Struct(path, fields, ref expr) => {
730                 self.hash_qpath(path);
731
732                 for f in fields {
733                     self.hash_name(f.ident.name);
734                     self.hash_expr(f.expr);
735                 }
736
737                 if let Some(e) = *expr {
738                     self.hash_expr(e);
739                 }
740             },
741             ExprKind::Tup(tup) => {
742                 self.hash_exprs(tup);
743             },
744             ExprKind::Array(v) => {
745                 self.hash_exprs(v);
746             },
747             ExprKind::Unary(lop, le) => {
748                 std::mem::discriminant(&lop).hash(&mut self.s);
749                 self.hash_expr(le);
750             },
751         }
752     }
753
754     pub fn hash_exprs(&mut self, e: &[Expr<'_>]) {
755         for e in e {
756             self.hash_expr(e);
757         }
758     }
759
760     pub fn hash_name(&mut self, n: Symbol) {
761         n.hash(&mut self.s);
762     }
763
764     pub fn hash_qpath(&mut self, p: &QPath<'_>) {
765         match *p {
766             QPath::Resolved(_, path) => {
767                 self.hash_path(path);
768             },
769             QPath::TypeRelative(_, path) => {
770                 self.hash_name(path.ident.name);
771             },
772             QPath::LangItem(lang_item, ..) => {
773                 std::mem::discriminant(&lang_item).hash(&mut self.s);
774             },
775         }
776         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
777     }
778
779     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
780         std::mem::discriminant(&pat.kind).hash(&mut self.s);
781         match pat.kind {
782             PatKind::Binding(ann, _, _, pat) => {
783                 std::mem::discriminant(&ann).hash(&mut self.s);
784                 if let Some(pat) = pat {
785                     self.hash_pat(pat);
786                 }
787             },
788             PatKind::Box(pat) => self.hash_pat(pat),
789             PatKind::Lit(expr) => self.hash_expr(expr),
790             PatKind::Or(pats) => {
791                 for pat in pats {
792                     self.hash_pat(pat);
793                 }
794             },
795             PatKind::Path(ref qpath) => self.hash_qpath(qpath),
796             PatKind::Range(s, e, i) => {
797                 if let Some(s) = s {
798                     self.hash_expr(s);
799                 }
800                 if let Some(e) = e {
801                     self.hash_expr(e);
802                 }
803                 std::mem::discriminant(&i).hash(&mut self.s);
804             },
805             PatKind::Ref(pat, mu) => {
806                 self.hash_pat(pat);
807                 std::mem::discriminant(&mu).hash(&mut self.s);
808             },
809             PatKind::Slice(l, m, r) => {
810                 for pat in l {
811                     self.hash_pat(pat);
812                 }
813                 if let Some(pat) = m {
814                     self.hash_pat(pat);
815                 }
816                 for pat in r {
817                     self.hash_pat(pat);
818                 }
819             },
820             PatKind::Struct(ref qpath, fields, e) => {
821                 self.hash_qpath(qpath);
822                 for f in fields {
823                     self.hash_name(f.ident.name);
824                     self.hash_pat(f.pat);
825                 }
826                 e.hash(&mut self.s);
827             },
828             PatKind::Tuple(pats, e) => {
829                 for pat in pats {
830                     self.hash_pat(pat);
831                 }
832                 e.hash(&mut self.s);
833             },
834             PatKind::TupleStruct(ref qpath, pats, e) => {
835                 self.hash_qpath(qpath);
836                 for pat in pats {
837                     self.hash_pat(pat);
838                 }
839                 e.hash(&mut self.s);
840             },
841             PatKind::Wild => {},
842         }
843     }
844
845     pub fn hash_path(&mut self, path: &Path<'_>) {
846         match path.res {
847             // constant hash since equality is dependant on inter-expression context
848             // e.g. The expressions `if let Some(x) = foo() {}` and `if let Some(y) = foo() {}` are considered equal
849             // even though the binding names are different and they have different `HirId`s.
850             Res::Local(_) => 1_usize.hash(&mut self.s),
851             _ => {
852                 for seg in path.segments {
853                     self.hash_name(seg.ident.name);
854                     self.hash_generic_args(seg.args().args);
855                 }
856             },
857         }
858     }
859
860     pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
861         std::mem::discriminant(&b.kind).hash(&mut self.s);
862
863         match &b.kind {
864             StmtKind::Local(local) => {
865                 self.hash_pat(local.pat);
866                 if let Some(init) = local.init {
867                     self.hash_expr(init);
868                 }
869             },
870             StmtKind::Item(..) => {},
871             StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
872                 self.hash_expr(expr);
873             },
874         }
875     }
876
877     pub fn hash_guard(&mut self, g: &Guard<'_>) {
878         match g {
879             Guard::If(expr) | Guard::IfLet(_, expr) => {
880                 self.hash_expr(expr);
881             },
882         }
883     }
884
885     pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
886         std::mem::discriminant(&lifetime.name).hash(&mut self.s);
887         if let LifetimeName::Param(ref name) = lifetime.name {
888             std::mem::discriminant(name).hash(&mut self.s);
889             match name {
890                 ParamName::Plain(ref ident) => {
891                     ident.name.hash(&mut self.s);
892                 },
893                 ParamName::Fresh(ref size) => {
894                     size.hash(&mut self.s);
895                 },
896                 ParamName::Error => {},
897             }
898         }
899     }
900
901     pub fn hash_ty(&mut self, ty: &Ty<'_>) {
902         std::mem::discriminant(&ty.kind).hash(&mut self.s);
903         self.hash_tykind(&ty.kind);
904     }
905
906     pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
907         match ty {
908             TyKind::Slice(ty) => {
909                 self.hash_ty(ty);
910             },
911             TyKind::Array(ty, anon_const) => {
912                 self.hash_ty(ty);
913                 self.hash_body(anon_const.body);
914             },
915             TyKind::Ptr(ref mut_ty) => {
916                 self.hash_ty(mut_ty.ty);
917                 mut_ty.mutbl.hash(&mut self.s);
918             },
919             TyKind::Rptr(lifetime, ref mut_ty) => {
920                 self.hash_lifetime(*lifetime);
921                 self.hash_ty(mut_ty.ty);
922                 mut_ty.mutbl.hash(&mut self.s);
923             },
924             TyKind::BareFn(bfn) => {
925                 bfn.unsafety.hash(&mut self.s);
926                 bfn.abi.hash(&mut self.s);
927                 for arg in bfn.decl.inputs {
928                     self.hash_ty(arg);
929                 }
930                 std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
931                 match bfn.decl.output {
932                     FnRetTy::DefaultReturn(_) => {},
933                     FnRetTy::Return(ty) => {
934                         self.hash_ty(ty);
935                     },
936                 }
937                 bfn.decl.c_variadic.hash(&mut self.s);
938             },
939             TyKind::Tup(ty_list) => {
940                 for ty in *ty_list {
941                     self.hash_ty(ty);
942                 }
943             },
944             TyKind::Path(ref qpath) => self.hash_qpath(qpath),
945             TyKind::OpaqueDef(_, arg_list) => {
946                 self.hash_generic_args(arg_list);
947             },
948             TyKind::TraitObject(_, lifetime, _) => {
949                 self.hash_lifetime(*lifetime);
950             },
951             TyKind::Typeof(anon_const) => {
952                 self.hash_body(anon_const.body);
953             },
954             TyKind::Err | TyKind::Infer | TyKind::Never => {},
955         }
956     }
957
958     pub fn hash_body(&mut self, body_id: BodyId) {
959         // swap out TypeckResults when hashing a body
960         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
961         self.hash_expr(&self.cx.tcx.hir().body(body_id).value);
962         self.maybe_typeck_results = old_maybe_typeck_results;
963     }
964
965     fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
966         for arg in arg_list {
967             match *arg {
968                 GenericArg::Lifetime(l) => self.hash_lifetime(l),
969                 GenericArg::Type(ref ty) => self.hash_ty(ty),
970                 GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
971                 GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
972             }
973         }
974     }
975 }