11use crate::utils::{is_direct_expn_of, span_lint};
2+ use core::ops::Deref;
23use if_chain::if_chain;
34use matches::matches;
4- use rustc::hir::{Expr, ExprKind, Mutability, StmtKind, UnOp};
5+ use rustc::hir::{Expr, ExprKind, Guard, Mutability, StmtKind, UnOp};
56use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
67use rustc::{declare_lint_pass, declare_tool_lint, ty};
78use syntax_pos::Span;
@@ -31,19 +32,67 @@ declare_clippy_lint! {
3132
3233declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);
3334
34- fn check_for_mutable_call(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
35+ fn check_for_mutable_call(cx: &LateContext<'_, '_>, span: Span, e: &Expr) -> Option<Span> {
3536 match &e.kind {
36- ExprKind::AddrOf(Mutability::MutMutable, _) => true,
37- ExprKind::AddrOf(Mutability::MutImmutable, expr) | ExprKind::Unary(_, expr) => check_for_mutable_call(cx, expr),
38- ExprKind::Binary(_, lhs, rhs) => check_for_mutable_call(cx, lhs) | check_for_mutable_call(cx, rhs),
39- ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => {
40- (*args).iter().any(|a| check_for_mutable_call(cx, a))
37+ ExprKind::AddrOf(Mutability::MutMutable, _) => Some(span),
38+ ExprKind::AddrOf(Mutability::MutImmutable, expr)
39+ | ExprKind::Assign(_, expr)
40+ | ExprKind::AssignOp(_, _, expr)
41+ | ExprKind::Box(expr)
42+ | ExprKind::Break(_, Some(expr))
43+ | ExprKind::Cast(expr, _)
44+ | ExprKind::DropTemps(expr)
45+ | ExprKind::Field(expr, _)
46+ | ExprKind::Repeat(expr, _)
47+ | ExprKind::Ret(Some(expr))
48+ | ExprKind::Type(expr, _)
49+ | ExprKind::Unary(_, expr)
50+ | ExprKind::Yield(expr, _) => check_for_mutable_call(cx, expr.span, expr),
51+ ExprKind::Binary(_, lhs, rhs) | ExprKind::Index(lhs, rhs) => {
52+ check_for_mutable_call(cx, lhs.span, lhs).or_else(|| check_for_mutable_call(cx, rhs.span, rhs))
4153 },
42- ExprKind::Path(_) => cx.tables.adjustments().get(e.hir_id).map_or(false, |adj| {
43- adj.iter()
54+ ExprKind::Array(args) | ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) | ExprKind::Tup(args) => {
55+ (*args).iter().find_map(|a| check_for_mutable_call(cx, span, a))
56+ },
57+ ExprKind::Path(_) => cx.tables.adjustments().get(e.hir_id).and_then(|adj| {
58+ if adj
59+ .iter()
4460 .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::MutMutable)))
61+ {
62+ Some(span)
63+ } else {
64+ None
65+ }
66+ }),
67+ ExprKind::Match(header, arm, _) => check_for_mutable_call(cx, header.span, header).or_else(|| {
68+ (*arm).iter().find_map(|a| {
69+ check_for_mutable_call(cx, a.body.span, &a.body).or_else(|| {
70+ a.guard.as_ref().and_then(|g| {
71+ let Guard::If(e) = g;
72+ check_for_mutable_call(cx, e.span, &e)
73+ })
74+ })
75+ })
4576 }),
46- _ => false,
77+ ExprKind::Block(block, _) | ExprKind::Loop(block, _, _) => block
78+ .stmts
79+ .iter()
80+ .filter_map(|s| match &s.kind {
81+ StmtKind::Local(l) => l.init.as_ref().map(|x| x.deref()),
82+ StmtKind::Expr(e) => Some(e),
83+ StmtKind::Semi(e) => Some(e),
84+ StmtKind::Item(_) => None,
85+ })
86+ .chain(block.expr.as_ref().map(|x| x.deref()))
87+ .find_map(|a| check_for_mutable_call(cx, a.span, a)),
88+ ExprKind::Err
89+ | ExprKind::Lit(_)
90+ | ExprKind::Continue(_)
91+ | ExprKind::InlineAsm(_, _, _)
92+ | ExprKind::Struct(_, _, _)
93+ | ExprKind::Closure(_, _, _, _, _)
94+ | ExprKind::Break(_, None)
95+ | ExprKind::Ret(None) => None,
4796 }
4897}
4998
@@ -60,9 +109,7 @@ fn extract_call(cx: &LateContext<'_, '_>, e: &Expr) -> Option<Span> {
60109 if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
61110 then {
62111 // debug_assert
63- if check_for_mutable_call(cx, condition) {
64- return Some(condition.span);
65- }
112+ return check_for_mutable_call(cx, condition.span, condition)
66113 } else {
67114 // debug_assert_{eq,ne}
68115 if_chain! {
@@ -73,13 +120,13 @@ fn extract_call(cx: &LateContext<'_, '_>, e: &Expr) -> Option<Span> {
73120 if conditions.len() == 2;
74121 then {
75122 if let ExprKind::AddrOf(_, ref lhs) = conditions[0].kind {
76- if check_for_mutable_call(cx, lhs) {
77- return Some(lhs. span);
123+ if let Some(span) = check_for_mutable_call(cx, lhs.span , lhs) {
124+ return Some(span);
78125 }
79126 }
80127 if let ExprKind::AddrOf(_, ref rhs) = conditions[1].kind {
81- if check_for_mutable_call(cx, rhs) {
82- return Some(rhs. span);
128+ if let Some(span) = check_for_mutable_call(cx, rhs.span , rhs) {
129+ return Some(span);
83130 }
84131 }
85132 }
0 commit comments