Skip to content

Commit 7b50949

Browse files
committed
refactor ptr_offset_with_cast
1 parent 5ac9657 commit 7b50949

File tree

5 files changed

+117
-155
lines changed

5 files changed

+117
-155
lines changed

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
448448
crate::methods::OR_THEN_UNWRAP_INFO,
449449
crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
450450
crate::methods::PATH_ENDS_WITH_EXT_INFO,
451+
crate::methods::PTR_OFFSET_WITH_CAST_INFO,
451452
crate::methods::RANGE_ZIP_WITH_LEN_INFO,
452453
crate::methods::READONLY_WRITE_LOCK_INFO,
453454
crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
@@ -625,7 +626,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
625626
crate::ptr::MUT_FROM_REF_INFO,
626627
crate::ptr::PTR_ARG_INFO,
627628
crate::ptr::PTR_EQ_INFO,
628-
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
629629
crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO,
630630
crate::pub_use::PUB_USE_INFO,
631631
crate::question_mark::QUESTION_MARK_INFO,

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ mod permissions_set_readonly_false;
302302
mod pointers_in_nomem_asm_block;
303303
mod precedence;
304304
mod ptr;
305-
mod ptr_offset_with_cast;
306305
mod pub_underscore_fields;
307306
mod pub_use;
308307
mod question_mark;
@@ -592,7 +591,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
592591
store.register_late_pass(|_| Box::new(unwrap::Unwrap));
593592
store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
594593
store.register_late_pass(move |tcx| Box::new(non_copy_const::NonCopyConst::new(tcx, conf)));
595-
store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
596594
store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
597595
store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
598596
store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(conf)));

clippy_lints/src/methods/mod.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ mod or_fun_call;
9191
mod or_then_unwrap;
9292
mod path_buf_push_overwrite;
9393
mod path_ends_with_ext;
94+
mod ptr_offset_with_cast;
9495
mod range_zip_with_len;
9596
mod read_line_without_trim;
9697
mod readonly_write_lock;
@@ -1725,6 +1726,43 @@ declare_clippy_lint! {
17251726
"Check for offset calculations on raw pointers to zero-sized types"
17261727
}
17271728

1729+
declare_clippy_lint! {
1730+
/// ### What it does
1731+
/// Checks for usage of the `offset` pointer method with a `usize` casted to an
1732+
/// `isize`.
1733+
///
1734+
/// ### Why is this bad?
1735+
/// If we’re always increasing the pointer address, we can avoid the numeric
1736+
/// cast by using the `add` method instead.
1737+
///
1738+
/// ### Example
1739+
/// ```no_run
1740+
/// let vec = vec![b'a', b'b', b'c'];
1741+
/// let ptr = vec.as_ptr();
1742+
/// let offset = 1_usize;
1743+
///
1744+
/// unsafe {
1745+
/// ptr.offset(offset as isize);
1746+
/// }
1747+
/// ```
1748+
///
1749+
/// Could be written:
1750+
///
1751+
/// ```no_run
1752+
/// let vec = vec![b'a', b'b', b'c'];
1753+
/// let ptr = vec.as_ptr();
1754+
/// let offset = 1_usize;
1755+
///
1756+
/// unsafe {
1757+
/// ptr.add(offset);
1758+
/// }
1759+
/// ```
1760+
#[clippy::version = "1.30.0"]
1761+
pub PTR_OFFSET_WITH_CAST,
1762+
complexity,
1763+
"unneeded pointer offset cast"
1764+
}
1765+
17281766
declare_clippy_lint! {
17291767
/// ### What it does
17301768
/// Checks for `FileType::is_file()`.
@@ -4665,6 +4703,7 @@ impl_lint_pass!(Methods => [
46654703
UNINIT_ASSUMED_INIT,
46664704
MANUAL_SATURATING_ARITHMETIC,
46674705
ZST_OFFSET,
4706+
PTR_OFFSET_WITH_CAST,
46684707
FILETYPE_IS_FILE,
46694708
OPTION_AS_REF_DEREF,
46704709
UNNECESSARY_LAZY_EVALUATIONS,
@@ -4962,9 +5001,13 @@ impl Methods {
49625001
match (name, args) {
49635002
(
49645003
sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub,
4965-
[_arg],
5004+
[arg],
49665005
) => {
49675006
zst_offset::check(cx, expr, recv);
5007+
5008+
if matches!(name, sym::offset | sym::wrapping_offset) {
5009+
ptr_offset_with_cast::check(cx, name, expr, recv, arg);
5010+
}
49685011
},
49695012
(sym::all, [arg]) => {
49705013
unused_enumerate_index::check(cx, expr, recv, arg);
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::source::SpanRangeExt;
3+
use clippy_utils::sym;
4+
use rustc_errors::Applicability;
5+
use rustc_hir::{Expr, ExprKind};
6+
use rustc_lint::LateContext;
7+
use rustc_span::Symbol;
8+
use std::fmt;
9+
10+
use super::PTR_OFFSET_WITH_CAST;
11+
12+
pub(super) fn check(cx: &LateContext<'_>, method: Symbol, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
13+
let method = match method {
14+
sym::offset => Method::Offset,
15+
sym::wrapping_offset => Method::WrappingOffset,
16+
_ => return,
17+
};
18+
19+
// Check if the argument to the method call is a cast from usize
20+
let cast_lhs_expr = match arg.kind {
21+
ExprKind::Cast(lhs, _) if is_expr_ty_usize(cx, lhs) => lhs,
22+
_ => return,
23+
};
24+
25+
let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
26+
span_lint_and_then(cx, PTR_OFFSET_WITH_CAST, expr.span, msg, |diag| {
27+
if let Some(sugg) = build_suggestion(cx, method, recv, cast_lhs_expr) {
28+
diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
29+
}
30+
});
31+
}
32+
33+
// Is the type of the expression a usize?
34+
fn is_expr_ty_usize(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
35+
cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize
36+
}
37+
38+
fn build_suggestion(
39+
cx: &LateContext<'_>,
40+
method: Method,
41+
receiver_expr: &Expr<'_>,
42+
cast_lhs_expr: &Expr<'_>,
43+
) -> Option<String> {
44+
let receiver = receiver_expr.span.get_source_text(cx)?;
45+
let cast_lhs = cast_lhs_expr.span.get_source_text(cx)?;
46+
Some(format!("{receiver}.{}({cast_lhs})", method.suggestion()))
47+
}
48+
49+
#[derive(Copy, Clone)]
50+
enum Method {
51+
Offset,
52+
WrappingOffset,
53+
}
54+
55+
impl Method {
56+
#[must_use]
57+
fn suggestion(self) -> &'static str {
58+
match self {
59+
Self::Offset => "add",
60+
Self::WrappingOffset => "wrapping_add",
61+
}
62+
}
63+
}
64+
65+
impl fmt::Display for Method {
66+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67+
match self {
68+
Self::Offset => write!(f, "offset"),
69+
Self::WrappingOffset => write!(f, "wrapping_offset"),
70+
}
71+
}
72+
}

clippy_lints/src/ptr_offset_with_cast.rs

Lines changed: 0 additions & 151 deletions
This file was deleted.

0 commit comments

Comments
 (0)