summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/operators
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/operators')
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic.rs119
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs198
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/eq_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/self_assignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs2
17 files changed, 296 insertions, 257 deletions
diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index 1ec4240af..d29ca37ea 100644
--- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -34,13 +34,12 @@ pub(super) fn check<'tcx>(
};
let help = format!(
- "because `{}` is the {} value for this type, {}",
+ "because `{}` is the {} value for this type, {conclusion}",
snippet(cx, culprit.expr.span, "x"),
match culprit.which {
ExtremeType::Minimum => "minimum",
ExtremeType::Maximum => "maximum",
- },
- conclusion
+ }
);
span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs
deleted file mode 100644
index 800cf249f..000000000
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-#![allow(
- // False positive
- clippy::match_same_arms
-)]
-
-use super::ARITHMETIC;
-use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-use rustc_span::source_map::Span;
-
-const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"];
-
-#[derive(Debug)]
-pub struct Arithmetic {
- allowed: FxHashSet<String>,
- // Used to check whether expressions are constants, such as in enum discriminants and consts
- const_span: Option<Span>,
- expr_span: Option<Span>,
-}
-
-impl_lint_pass!(Arithmetic => [ARITHMETIC]);
-
-impl Arithmetic {
- #[must_use]
- pub fn new(mut allowed: FxHashSet<String>) -> Self {
- allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
- Self {
- allowed,
- const_span: None,
- expr_span: None,
- }
- }
-
- /// Checks if the given `expr` has any of the inner `allowed` elements.
- fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
- self.allowed.contains(
- cx.typeck_results()
- .expr_ty(expr)
- .to_string()
- .split('<')
- .next()
- .unwrap_or_default(),
- )
- }
-
- fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
- span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected");
- self.expr_span = Some(expr.span);
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for Arithmetic {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if self.expr_span.is_some() {
- return;
- }
- if let Some(span) = self.const_span && span.contains(expr.span) {
- return;
- }
- match &expr.kind {
- hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
- let (
- hir::BinOpKind::Add
- | hir::BinOpKind::Sub
- | hir::BinOpKind::Mul
- | hir::BinOpKind::Div
- | hir::BinOpKind::Rem
- | hir::BinOpKind::Shl
- | hir::BinOpKind::Shr
- ) = op.node else {
- return;
- };
- if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
- return;
- }
- self.issue_lint(cx, expr);
- },
- hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
- // CTFE already takes care of things like `-1` that do not overflow.
- if constant_simple(cx, cx.typeck_results(), expr).is_none() {
- self.issue_lint(cx, expr);
- }
- },
- _ => {},
- }
- }
-
- fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
- let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
- match cx.tcx.hir().body_owner_kind(body_owner) {
- hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
- let body_span = cx.tcx.def_span(body_owner);
- if let Some(span) = self.const_span && span.contains(body_span) {
- return;
- }
- self.const_span = Some(body_span);
- },
- hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {},
- }
- }
-
- fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
- let body_owner = cx.tcx.hir().body_owner(body.id());
- let body_span = cx.tcx.hir().span(body_owner);
- if let Some(span) = self.const_span && span.contains(body_span) {
- return;
- }
- self.const_span = None;
- }
-
- fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if Some(expr.span) == self.expr_span {
- self.expr_span = None;
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
new file mode 100644
index 000000000..8827daaa3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -0,0 +1,198 @@
+use super::ARITHMETIC_SIDE_EFFECTS;
+use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
+use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::source_map::{Span, Spanned};
+
+const HARD_CODED_ALLOWED: &[&str] = &[
+ "&str",
+ "f32",
+ "f64",
+ "std::num::Saturating",
+ "std::num::Wrapping",
+ "std::string::String",
+];
+
+#[derive(Debug)]
+pub struct ArithmeticSideEffects {
+ allowed: FxHashSet<String>,
+ // Used to check whether expressions are constants, such as in enum discriminants and consts
+ const_span: Option<Span>,
+ expr_span: Option<Span>,
+}
+
+impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
+
+impl ArithmeticSideEffects {
+ #[must_use]
+ pub fn new(mut allowed: FxHashSet<String>) -> Self {
+ allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
+ Self {
+ allowed,
+ const_span: None,
+ expr_span: None,
+ }
+ }
+
+ /// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a
+ /// non-constant environment that won't overflow.
+ fn has_valid_op(op: &Spanned<hir::BinOpKind>, expr: &hir::Expr<'_>) -> bool {
+ if let hir::ExprKind::Lit(ref lit) = expr.kind &&
+ let ast::LitKind::Int(value, _) = lit.node
+ {
+ match (&op.node, value) {
+ (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
+ (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
+ | (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
+ | (hir::BinOpKind::Mul, 0 | 1) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ }
+
+ /// Checks if the given `expr` has any of the inner `allowed` elements.
+ fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
+ self.allowed
+ .contains(ty.to_string().split('<').next().unwrap_or_default())
+ }
+
+ // For example, 8i32 or &i64::MAX.
+ fn is_integral(ty: Ty<'_>) -> bool {
+ ty.peel_refs().is_integral()
+ }
+
+ // Common entry-point to avoid code duplication.
+ fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+ let msg = "arithmetic operation that can potentially result in unexpected side-effects";
+ span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
+ self.expr_span = Some(expr.span);
+ }
+
+ /// If `expr` does not match any variant of `LiteralIntegerTy`, returns `None`.
+ fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<LiteralIntegerTy<'expr, 'tcx>> {
+ if matches!(expr.kind, hir::ExprKind::Lit(_)) {
+ return Some(LiteralIntegerTy::Value(expr));
+ }
+ if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind {
+ return Some(LiteralIntegerTy::Ref(inn));
+ }
+ None
+ }
+
+ /// Manages when the lint should be triggered. Operations in constant environments, hard coded
+ /// types, custom allowed types and non-constant operations that won't overflow are ignored.
+ fn manage_bin_ops<'tcx>(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ expr: &hir::Expr<'tcx>,
+ op: &Spanned<hir::BinOpKind>,
+ lhs: &hir::Expr<'tcx>,
+ rhs: &hir::Expr<'tcx>,
+ ) {
+ if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+ return;
+ }
+ if !matches!(
+ op.node,
+ hir::BinOpKind::Add
+ | hir::BinOpKind::Sub
+ | hir::BinOpKind::Mul
+ | hir::BinOpKind::Div
+ | hir::BinOpKind::Rem
+ | hir::BinOpKind::Shl
+ | hir::BinOpKind::Shr
+ ) {
+ return;
+ };
+ let lhs_ty = cx.typeck_results().expr_ty(lhs);
+ let rhs_ty = cx.typeck_results().expr_ty(rhs);
+ let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
+ if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
+ return;
+ }
+ let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
+ match (Self::literal_integer(lhs), Self::literal_integer(rhs)) {
+ (None, Some(lit_int_ty)) | (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()),
+ (Some(LiteralIntegerTy::Value(_)), Some(LiteralIntegerTy::Value(_))) => true,
+ (None, None) | (Some(_), Some(_)) => false,
+ }
+ } else {
+ false
+ };
+ if !has_valid_op {
+ self.issue_lint(cx, expr);
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
+ if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
+ return;
+ }
+ match &expr.kind {
+ hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
+ self.manage_bin_ops(cx, expr, op, lhs, rhs);
+ },
+ hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
+ if constant_simple(cx, cx.typeck_results(), expr).is_none() {
+ self.issue_lint(cx, expr);
+ }
+ },
+ _ => {},
+ }
+ }
+
+ fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+ let body_owner = cx.tcx.hir().body_owner(body.id());
+ let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+ let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
+ if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+ let body_span = cx.tcx.hir().span_with_body(body_owner);
+ if let Some(span) = self.const_span && span.contains(body_span) {
+ return;
+ }
+ self.const_span = Some(body_span);
+ }
+ }
+
+ fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+ let body_owner = cx.tcx.hir().body_owner(body.id());
+ let body_span = cx.tcx.hir().span(body_owner);
+ if let Some(span) = self.const_span && span.contains(body_span) {
+ return;
+ }
+ self.const_span = None;
+ }
+
+ fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if Some(expr.span) == self.expr_span {
+ self.expr_span = None;
+ }
+ }
+}
+
+/// Tells if an expression is a integer declared by value or by reference.
+///
+/// If `LiteralIntegerTy::Ref`, then the contained value will be `hir::ExprKind::Lit` rather
+/// than `hirExprKind::Addr`.
+enum LiteralIntegerTy<'expr, 'tcx> {
+ /// For example, `&199`
+ Ref(&'expr hir::Expr<'tcx>),
+ /// For example, `1` or `i32::MAX`
+ Value(&'expr hir::Expr<'tcx>),
+}
+
+impl<'expr, 'tcx> From<LiteralIntegerTy<'expr, 'tcx>> for &'expr hir::Expr<'tcx> {
+ fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self {
+ match from {
+ LiteralIntegerTy::Ref(elem) | LiteralIntegerTy::Value(elem) => elem,
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 945a09a64..ee9fd9406 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -2,16 +2,17 @@ use clippy_utils::binop_traits;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::for_each_expr;
use clippy_utils::{eq_expr_value, trait_ref_of_method};
+use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_lint::LateContext;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::BorrowKind;
use rustc_trait_selection::infer::TyCtxtInferExt;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use super::ASSIGN_OP_PATTERN;
@@ -28,7 +29,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some((_, lang_item)) = binop_traits(op.node);
if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item);
- let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
+ let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if trait_ref_of_method(cx, parent_fn)
.map_or(true, |t| t.path.res.def_id() != trait_id);
if implements_trait(cx, ty, trait_id, &[rty.into()]);
@@ -55,7 +56,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion(
expr.span,
"replace it with",
- format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
+ format!("{snip_a} {}= {snip_r}", op.node.as_str()),
Applicability::MachineApplicable,
);
}
@@ -65,15 +66,19 @@ pub(super) fn check<'tcx>(
}
};
- let mut visitor = ExprVisitor {
- assignee,
- counter: 0,
- cx,
- };
-
- walk_expr(&mut visitor, e);
+ let mut found = false;
+ let found_multiple = for_each_expr(e, |e| {
+ if eq_expr_value(cx, assignee, e) {
+ if found {
+ return ControlFlow::Break(());
+ }
+ found = true;
+ }
+ ControlFlow::Continue(())
+ })
+ .is_some();
- if visitor.counter == 1 {
+ if found && !found_multiple {
// a = a op b
if eq_expr_value(cx, assignee, l) {
lint(assignee, r);
@@ -98,22 +103,6 @@ pub(super) fn check<'tcx>(
}
}
-struct ExprVisitor<'a, 'tcx> {
- assignee: &'a hir::Expr<'a>,
- counter: u8,
- cx: &'a LateContext<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- if eq_expr_value(self.cx, self.assignee, expr) {
- self.counter += 1;
- }
-
- walk_expr(self, expr);
- }
-}
-
fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet {
struct S(hir::HirIdSet);
impl Delegate<'_> for S {
@@ -134,16 +123,15 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet
}
let mut s = S(hir::HirIdSet::default());
- cx.tcx.infer_ctxt().enter(|infcx| {
- let mut v = ExprUseVisitor::new(
- &mut s,
- &infcx,
- cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
- cx.param_env,
- cx.typeck_results(),
- );
- v.consume_expr(e);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut v = ExprUseVisitor::new(
+ &mut s,
+ &infcx,
+ cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+ cx.param_env,
+ cx.typeck_results(),
+ );
+ v.consume_expr(e);
s.0
}
@@ -167,15 +155,14 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet
}
let mut s = S(hir::HirIdSet::default());
- cx.tcx.infer_ctxt().enter(|infcx| {
- let mut v = ExprUseVisitor::new(
- &mut s,
- &infcx,
- cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
- cx.param_env,
- cx.typeck_results(),
- );
- v.consume_expr(e);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut v = ExprUseVisitor::new(
+ &mut s,
+ &infcx,
+ cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+ cx.param_env,
+ cx.typeck_results(),
+ );
+ v.consume_expr(e);
s.0
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 74387fbc8..1369b3e74 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -64,10 +64,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ & {}` can never be equal to `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"),
);
}
} else if mask_value == 0 {
@@ -80,10 +77,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ | {}` can never be equal to `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"),
);
}
},
@@ -96,10 +90,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ & {}` will always be lower than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
@@ -111,10 +102,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ | {}` will never be lower than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"),
);
} else {
check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
@@ -130,10 +118,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ & {}` will never be higher than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
@@ -145,10 +130,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ | {}` will always be higher than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"),
);
} else {
check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
@@ -167,10 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
cx,
INEFFECTIVE_BIT_MASK,
span,
- &format!(
- "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
- op, m, c
- ),
+ &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
);
}
}
@@ -181,10 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
cx,
INEFFECTIVE_BIT_MASK,
span,
- &format!(
- "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
- op, m, c
- ),
+ &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index e1f9b5906..24aeb82a3 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{match_any_def_paths, path_def_id, paths};
+use clippy_utils::{match_def_path, path_def_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::LateContext;
@@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
let typeck = cx.typeck_results();
let (arg, arg_span) = match expr.kind {
- ExprKind::MethodCall(.., [arg], _)
+ ExprKind::MethodCall(_, arg, [], _)
if typeck
.type_dependent_def_id(expr.hir_id)
.and_then(|id| cx.tcx.trait_of_item(id))
@@ -49,13 +49,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
(arg, arg.span)
},
ExprKind::Call(path, [arg])
- if path_def_id(cx, path)
- .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
- .map_or(false, |idx| match idx {
- 0 => true,
- 1 => !is_copy(cx, typeck.expr_ty(expr)),
- _ => false,
- }) =>
+ if path_def_id(cx, path).map_or(false, |id| {
+ if match_def_path(cx, id, &paths::FROM_STR_METHOD) {
+ true
+ } else if cx.tcx.lang_items().from_fn() == Some(id) {
+ !is_copy(cx, typeck.expr_ty(expr))
+ } else {
+ false
+ }
+ }) =>
{
(arg, arg.span)
},
@@ -99,7 +101,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
let expr_snip;
let eq_impl;
if with_deref.is_implemented() {
- expr_snip = format!("*{}", arg_snip);
+ expr_snip = format!("*{arg_snip}");
eq_impl = with_deref;
} else {
expr_snip = arg_snip.to_string();
@@ -121,17 +123,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
};
if eq_impl.ty_eq_other {
hint = format!(
- "{}{}{}",
- expr_snip,
+ "{expr_snip}{}{}",
snippet(cx, cmp_span, ".."),
snippet(cx, other.span, "..")
);
} else {
hint = format!(
- "{}{}{}",
+ "{}{}{expr_snip}",
snippet(cx, other.span, ".."),
- snippet(cx, cmp_span, ".."),
- expr_snip
+ snippet(cx, cmp_span, "..")
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index 0d067d1e1..49e662cac 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
right: &'tcx Expr<'_>,
) {
if op == BinOpKind::Div
- && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
+ && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
&& let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
{
@@ -31,12 +31,11 @@ pub(crate) fn check<'tcx>(
cx,
DURATION_SUBSEC,
expr.span,
- &format!("calling `{}()` is more concise than this calculation", suggested_fn),
+ &format!("calling `{suggested_fn}()` is more concise than this calculation"),
"try",
format!(
- "{}.{}()",
- snippet_with_applicability(cx, self_arg.span, "_", &mut applicability),
- suggested_fn
+ "{}.{suggested_fn}()",
+ snippet_with_applicability(cx, self_arg.span, "_", &mut applicability)
),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
index 44cf0bb06..67913f739 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -22,7 +22,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
cx,
EQ_OP,
lhs.span.to(rhs.span),
- &format!("identical args used in this `{}!` macro call", macro_name),
+ &format!("identical args used in this `{macro_name}!` macro call"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index 0ef793443..97ddcdb24 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}
if_chain! {
- if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if sym!(signum) == method_name.ident.name;
// Check that the receiver of the signum() is a float (expressions[0] is the receiver of
// the method call)
diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
index 0024384d9..ae805147f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
@@ -47,18 +47,14 @@ fn lint_misrefactored_assign_op(
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));
+ let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
diag.span_suggestion(
expr.span,
&format!(
- "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with",
- snip_a,
- snip_a,
- op.as_str(),
- snip_r,
- long
+ "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
+ op.as_str()
),
- format!("{} {}= {}", snip_a, op.as_str(), snip_r),
+ format!("{snip_a} {}= {snip_r}", op.as_str()),
Applicability::MaybeIncorrect,
);
diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index bb6d99406..b8a20d5eb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -21,7 +21,7 @@ mod ptr_eq;
mod self_assignment;
mod verbose_bit_mask;
-pub(crate) mod arithmetic;
+pub(crate) mod arithmetic_side_effects;
use rustc_hir::{Body, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
@@ -61,25 +61,29 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for any kind of arithmetic operation of any type.
+ /// Checks any kind of arithmetic operation of any type.
///
/// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
/// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
- /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
- /// away.
+ /// or can panic (`/`, `%`).
+ ///
+ /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant
+ /// environments, allowed types and non-constant operations that won't overflow are ignored.
///
/// ### Why is this bad?
- /// Integer overflow will trigger a panic in debug builds or will wrap in
- /// release mode. Division by zero will cause a panic in either mode. In some applications one
- /// wants explicitly checked, wrapping or saturating arithmetic.
+ /// For integers, overflow will trigger a panic in debug builds or wrap the result in
+ /// release mode; division by zero will cause a panic in either mode. As a result, it is
+ /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
///
/// #### Example
/// ```rust
- /// # let a = 0;
- /// a + 1;
+ /// // `n` can be any number, including `i32::MAX`.
+ /// fn foo(n: i32) -> i32 {
+ /// n + 1
+ /// }
/// ```
///
- /// Third-party types also tend to overflow.
+ /// Third-party types can also overflow or present unwanted side-effects.
///
/// #### Example
/// ```ignore,rust
@@ -88,11 +92,11 @@ declare_clippy_lint! {
/// ```
///
/// ### Allowed types
- /// Custom allowed types can be specified through the "arithmetic-allowed" filter.
+ /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
#[clippy::version = "1.64.0"]
- pub ARITHMETIC,
+ pub ARITHMETIC_SIDE_EFFECTS,
restriction,
- "any arithmetic expression that could overflow or panic"
+ "any arithmetic expression that can cause side effects like overflows or panics"
}
declare_clippy_lint! {
@@ -785,7 +789,7 @@ pub struct Operators {
}
impl_lint_pass!(Operators => [
ABSURD_EXTREME_COMPARISONS,
- ARITHMETIC,
+ ARITHMETIC_SIDE_EFFECTS,
INTEGER_ARITHMETIC,
FLOAT_ARITHMETIC,
ASSIGN_OP_PATTERN,
diff --git a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs
index e902235a0..ab5fb1787 100644
--- a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs
@@ -27,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp
if let Some(lhs_snip) = snippet_opt(cx, lhs.span)
&& let Some(rhs_snip) = snippet_opt(cx, rhs.span)
{
- let sugg = format!("{} {} {}", lhs_snip, op_str, rhs_snip);
+ let sugg = format!("{lhs_snip} {op_str} {rhs_snip}");
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index b6097710d..0830a106f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -1,5 +1,6 @@
use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_integer_literal;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
@@ -50,11 +51,9 @@ impl Context {
hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind {
hir::ExprKind::Lit(_lit) => (),
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
- if let hir::ExprKind::Lit(lit) = &expr.kind {
- if let rustc_ast::ast::LitKind::Int(1, _) = lit.node {
- span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
- self.expr_id = Some(expr.hir_id);
- }
+ if is_integer_literal(expr, 1) {
+ span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+ self.expr_id = Some(expr.hir_id);
}
},
_ => {
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 1805672e3..71b31b5e4 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -185,7 +185,7 @@ fn in_impl<'tcx>(
if let ItemKind::Impl(item) = &item.kind;
if let Some(of_trait) = &item.of_trait;
if let Some(seg) = of_trait.path.segments.last();
- if let Some(Res::Def(_, trait_id)) = seg.res;
+ if let Res::Def(_, trait_id) = seg.res;
if trait_id == bin_op;
if let Some(generic_args) = seg.args;
if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
@@ -204,7 +204,7 @@ fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir
if let ty::Adt(adt_def, _) = middle_ty.kind();
if let Some(local_did) = adt_def.did().as_local();
let item = cx.tcx.hir().expect_item(local_did);
- let middle_ty_id = item.def_id.to_def_id();
+ let middle_ty_id = item.owner_id.to_def_id();
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
if let Res::Def(_, hir_ty_id) = path.res;
diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
index 1aefc2741..1229c202f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
expr.span,
LINT_MSG,
"try",
- format!("std::ptr::eq({}, {})", left_snip, right_snip),
+ format!("std::ptr::eq({left_snip}, {right_snip})"),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
index 9d6bec05b..7c9d5320a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx
cx,
SELF_ASSIGNMENT,
e.span,
- &format!("self-assignment of `{}` to `{}`", rhs, lhs),
+ &format!("self-assignment of `{rhs}` to `{lhs}`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
index ff85fd554..fbf65e92b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion(
e.span,
"try",
- format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
+ format!("{sugg}.trailing_zeros() >= {}", n.count_ones()),
Applicability::MaybeIncorrect,
);
},