| use clippy_utils::diagnostics::span_lint; |
| use clippy_utils::res::MaybeResPath; |
| use clippy_utils::ty::InteriorMut; |
| use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, search_same}; |
| use rustc_hir::{Expr, ExprKind}; |
| use rustc_lint::LateContext; |
| |
| use super::IFS_SAME_COND; |
| |
| fn method_caller_is_mutable<'tcx>( |
| cx: &LateContext<'tcx>, |
| caller_expr: &Expr<'_>, |
| interior_mut: &mut InteriorMut<'tcx>, |
| ) -> bool { |
| let caller_ty = cx.typeck_results().expr_ty(caller_expr); |
| |
| interior_mut.is_interior_mut_ty(cx, caller_ty) |
| || caller_ty.is_mutable_ptr() |
| // `find_binding_init` will return the binding iff its not mutable |
| || caller_expr.res_local_id() |
| .and_then(|hid| find_binding_init(cx, hid)) |
| .is_none() |
| } |
| |
| /// Implementation of `IFS_SAME_COND`. |
| pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) { |
| for group in search_same( |
| conds, |
| |e| hash_expr(cx, e), |
| |lhs, rhs| { |
| // Ignore eq_expr side effects iff one of the expression kind is a method call |
| // and the caller is not a mutable, including inner mutable type. |
| if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { |
| if method_caller_is_mutable(cx, caller, interior_mut) { |
| false |
| } else { |
| SpanlessEq::new(cx).eq_expr(lhs, rhs) |
| } |
| } else { |
| eq_expr_value(cx, lhs, rhs) |
| } |
| }, |
| ) { |
| let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect(); |
| span_lint(cx, IFS_SAME_COND, spans, "these `if` branches have the same condition"); |
| } |
| } |