Replace `is_integer_const` with `eval_int`.
diff --git a/clippy_lints/src/operators/modulo_one.rs b/clippy_lints/src/operators/modulo_one.rs index 2e6a071..22ec8b1 100644 --- a/clippy_lints/src/operators/modulo_one.rs +++ b/clippy_lints/src/operators/modulo_one.rs
@@ -1,26 +1,17 @@ +use clippy_utils::consts::{FullInt, eval_int}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_integer_const, unsext}; use rustc_hir::{BinOpKind, Expr}; use rustc_lint::LateContext; -use rustc_middle::ty; use super::MODULO_ONE; pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, right: &Expr<'_>) { if op == BinOpKind::Rem { - if is_integer_const(cx, right, 1) { - span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); - } - - if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() - && is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) - { - span_lint( - cx, - MODULO_ONE, - expr.span, - "any number modulo -1 will panic/overflow or result in 0", - ); - } + let msg = match eval_int(cx, right) { + Some(FullInt::S(-1)) => "any number modulo -1 will panic/overflow or result in 0", + Some(FullInt::U(1)) => "any number modulo 1 will be 0", + _ => return, + }; + span_lint(cx, MODULO_ONE, expr.span, msg); } }
diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index ed8a099..c85a315 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs
@@ -1,7 +1,7 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt, eval_int}; use clippy_utils::diagnostics::span_lint; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::{is_integer_const, sym}; +use clippy_utils::sym; use rustc_hir::{ConstBlock, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; @@ -26,7 +26,7 @@ // Catching: // `std::mem::transmute(0 as *const i32)` if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind - && is_integer_const(cx, inner_expr, 0) + && eval_int(cx, inner_expr).is_some_and(FullInt::is_zero) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; @@ -47,7 +47,7 @@ if let ExprKind::Call(func1, [arg1]) = arg.kind && (func1.basic_res().is_diag_item(cx, sym::ptr_without_provenance) || func1.basic_res().is_diag_item(cx, sym::ptr_without_provenance_mut)) - && is_integer_const(cx, arg1, 0) + && eval_int(cx, arg1).is_some_and(FullInt::is_zero) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true;
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 51db6b6..098be98 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs
@@ -462,6 +462,12 @@ U(u128), } +impl FullInt { + pub fn is_zero(self) -> bool { + matches!(self, Self::S(0) | Self::U(0)) + } +} + impl PartialEq for FullInt { fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal @@ -491,6 +497,25 @@ } } +/// Evaluates an expression if it's a builtin integer type. +pub fn eval_int(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<FullInt> { + match e.kind { + ExprKind::Lit(lit) if let LitKind::Int(val, _) = lit.node => Some(FullInt::U(val.0)), + ExprKind::Unary(UnOp::Neg, e) + if let ExprKind::Lit(lit) = e.kind + && let LitKind::Int(val, _) = lit.node => + { + Some(FullInt::S(val.0.cast_signed().wrapping_neg())) + }, + _ if let ty = cx.typeck_results().expr_ty(e) + && let ty::Int(_) | ty::Uint(_) = *ty.kind() => + { + ConstEvalCtxt::new(cx).eval(e).and_then(|x| x.int_value(cx.tcx, ty)) + }, + _ => None, + } +} + /// The context required to evaluate a constant expression. /// /// This is currently limited to constant folding and reading the value of named constants.
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 717d531..c208b8b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs
@@ -120,7 +120,7 @@ use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::ast_utils::unordered_over; -use crate::consts::{ConstEvalCtxt, Constant}; +use crate::consts::ConstEvalCtxt; use crate::higher::Range; use crate::msrvs::Msrv; use crate::res::{MaybeDef, MaybeQPath, MaybeResPath}; @@ -1384,24 +1384,8 @@ false } -/// Checks whether the given expression is a constant integer of the given value. -/// unlike `is_integer_literal`, this version does const folding -pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool { - if is_integer_literal(e, value) { - return true; - } - let enclosing_body = cx.tcx.hir_enclosing_body_owner(e.hir_id); - if let Some(Constant::Int(v)) = - ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), cx.tcx.typeck(enclosing_body)).eval(e) - { - return value == v; - } - false -} - /// Checks whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { - // FIXME: use constant folding if let ExprKind::Lit(spanned) = expr.kind && let LitKind::Int(v, _) = spanned.node {