| use clippy_utils::diagnostics::span_lint_and_then; |
| use clippy_utils::msrvs::{self, Msrv}; |
| use clippy_utils::sym; |
| use rustc_errors::Applicability; |
| use rustc_hir::{Expr, ExprKind}; |
| use rustc_lint::LateContext; |
| use rustc_span::Symbol; |
| use std::fmt; |
| |
| use super::PTR_OFFSET_WITH_CAST; |
| |
| pub(super) fn check( |
| cx: &LateContext<'_>, |
| method: Symbol, |
| expr: &Expr<'_>, |
| recv: &Expr<'_>, |
| arg: &Expr<'_>, |
| msrv: Msrv, |
| ) { |
| // `pointer::add` and `pointer::wrapping_add` are only stable since 1.26.0. These functions |
| // became const-stable in 1.61.0, the same version that `pointer::offset` became const-stable. |
| if !msrv.meets(cx, msrvs::POINTER_ADD_SUB_METHODS) { |
| return; |
| } |
| |
| let method = match method { |
| sym::offset => Method::Offset, |
| sym::wrapping_offset => Method::WrappingOffset, |
| _ => return, |
| }; |
| |
| if !cx.typeck_results().expr_ty_adjusted(recv).is_raw_ptr() { |
| return; |
| } |
| |
| // Check if the argument to the method call is a cast from usize. |
| let cast_lhs_expr = match arg.kind { |
| ExprKind::Cast(lhs, _) if cx.typeck_results().expr_ty(lhs).is_usize() => lhs, |
| _ => return, |
| }; |
| |
| let ExprKind::MethodCall(method_name, _, _, _) = expr.kind else { |
| return; |
| }; |
| |
| let msg = format!("use of `{method}` with a `usize` casted to an `isize`"); |
| span_lint_and_then(cx, PTR_OFFSET_WITH_CAST, expr.span, msg, |diag| { |
| diag.multipart_suggestion( |
| format!("use `{}` instead", method.suggestion()), |
| vec![ |
| (method_name.ident.span, method.suggestion().to_string()), |
| (arg.span.with_lo(cast_lhs_expr.span.hi()), String::new()), |
| ], |
| Applicability::MachineApplicable, |
| ); |
| }); |
| } |
| |
| #[derive(Copy, Clone)] |
| enum Method { |
| Offset, |
| WrappingOffset, |
| } |
| |
| impl Method { |
| #[must_use] |
| fn suggestion(self) -> &'static str { |
| match self { |
| Self::Offset => "add", |
| Self::WrappingOffset => "wrapping_add", |
| } |
| } |
| } |
| |
| impl fmt::Display for Method { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self { |
| Self::Offset => write!(f, "offset"), |
| Self::WrappingOffset => write!(f, "wrapping_offset"), |
| } |
| } |
| } |