rust/clippy_lints/src/operators/misrefactored_assign_op.rs
2022-12-20 05:12:13 -05:00

81 lines
2.5 KiB
Rust

use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::eq_expr_value;
use clippy_utils::source::snippet_opt;
use clippy_utils::sugg;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use super::MISREFACTORED_ASSIGN_OP;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
op: hir::BinOpKind,
lhs: &'tcx hir::Expr<'_>,
rhs: &'tcx hir::Expr<'_>,
) {
if let hir::ExprKind::Binary(binop, l, r) = &rhs.kind {
if op != binop.node {
return;
}
// lhs op= l op r
if eq_expr_value(cx, lhs, l) {
lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, r);
}
// lhs op= l commutative_op r
if is_commutative(op) && eq_expr_value(cx, lhs, r) {
lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, l);
}
}
}
fn lint_misrefactored_assign_op(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
op: hir::BinOpKind,
rhs: &hir::Expr<'_>,
assignee: &hir::Expr<'_>,
rhs_other: &hir::Expr<'_>,
) {
span_lint_and_then(
cx,
MISREFACTORED_ASSIGN_OP,
expr.span,
"variable appears on both sides of an assignment operation",
|diag| {
if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
let a = &sugg::Sugg::hir(cx, assignee, "..");
let r = &sugg::Sugg::hir(cx, rhs, "..");
let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
diag.span_suggestion(
expr.span,
format!(
"did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
op.as_str()
),
format!("{snip_a} {}= {snip_r}", op.as_str()),
Applicability::MaybeIncorrect,
);
diag.span_suggestion(
expr.span,
"or",
long,
Applicability::MaybeIncorrect, // snippet
);
}
},
);
}
#[must_use]
fn is_commutative(op: hir::BinOpKind) -> bool {
use rustc_hir::BinOpKind::{
Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub,
};
match op {
Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true,
Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false,
}
}