]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
Rollup merge of #102187 - b-naber:inline-const-source-info, r=eholk
[rust.git] / src / tools / clippy / clippy_lints / src / operators / misrefactored_assign_op.rs
1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::eq_expr_value;
3 use clippy_utils::source::snippet_opt;
4 use clippy_utils::sugg;
5 use rustc_errors::Applicability;
6 use rustc_hir as hir;
7 use rustc_lint::LateContext;
8
9 use super::MISREFACTORED_ASSIGN_OP;
10
11 pub(super) fn check<'tcx>(
12     cx: &LateContext<'tcx>,
13     expr: &'tcx hir::Expr<'_>,
14     op: hir::BinOpKind,
15     lhs: &'tcx hir::Expr<'_>,
16     rhs: &'tcx hir::Expr<'_>,
17 ) {
18     if let hir::ExprKind::Binary(binop, l, r) = &rhs.kind {
19         if op != binop.node {
20             return;
21         }
22         // lhs op= l op r
23         if eq_expr_value(cx, lhs, l) {
24             lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, r);
25         }
26         // lhs op= l commutative_op r
27         if is_commutative(op) && eq_expr_value(cx, lhs, r) {
28             lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, l);
29         }
30     }
31 }
32
33 fn lint_misrefactored_assign_op(
34     cx: &LateContext<'_>,
35     expr: &hir::Expr<'_>,
36     op: hir::BinOpKind,
37     rhs: &hir::Expr<'_>,
38     assignee: &hir::Expr<'_>,
39     rhs_other: &hir::Expr<'_>,
40 ) {
41     span_lint_and_then(
42         cx,
43         MISREFACTORED_ASSIGN_OP,
44         expr.span,
45         "variable appears on both sides of an assignment operation",
46         |diag| {
47             if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
48                 let a = &sugg::Sugg::hir(cx, assignee, "..");
49                 let r = &sugg::Sugg::hir(cx, rhs, "..");
50                 let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
51                 diag.span_suggestion(
52                     expr.span,
53                     &format!(
54                         "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
55                         op.as_str()
56                     ),
57                     format!("{snip_a} {}= {snip_r}", op.as_str()),
58                     Applicability::MaybeIncorrect,
59                 );
60                 diag.span_suggestion(
61                     expr.span,
62                     "or",
63                     long,
64                     Applicability::MaybeIncorrect, // snippet
65                 );
66             }
67         },
68     );
69 }
70
71 #[must_use]
72 fn is_commutative(op: hir::BinOpKind) -> bool {
73     use rustc_hir::BinOpKind::{
74         Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub,
75     };
76     match op {
77         Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true,
78         Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false,
79     }
80 }