-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #6130 - Ambroisie:lint-ptr-eq, r=Manishearth
New lint: Recommend using `ptr::eq` when possible This is based almost entirely on the code available in the previous PR #4596. I merely updated the code to make it compile. Fixes #3661. - [ ] I'm not sure about the lint name, but it was the one used in the original PR. - [X] Added passing UI tests (including committed `.stderr` file) - [X] `cargo test` passes locally - [X] Executed `cargo dev update_lints` - [X] Added lint documentation - [X] Run `cargo dev fmt` --- changelog: none
- Loading branch information
Showing
7 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use crate::utils; | ||
use if_chain::if_chain; | ||
use rustc_errors::Applicability; | ||
use rustc_hir::{BinOpKind, Expr, ExprKind}; | ||
use rustc_lint::{LateContext, LateLintPass}; | ||
use rustc_session::{declare_lint_pass, declare_tool_lint}; | ||
|
||
declare_clippy_lint! { | ||
/// **What it does:** Use `std::ptr::eq` when applicable | ||
/// | ||
/// **Why is this bad?** `ptr::eq` can be used to compare `&T` references | ||
/// (which coerce to `*const T` implicitly) by their address rather than | ||
/// comparing the values they point to. | ||
/// | ||
/// **Known problems:** None. | ||
/// | ||
/// **Example:** | ||
/// | ||
/// ```rust | ||
/// let a = &[1, 2, 3]; | ||
/// let b = &[1, 2, 3]; | ||
/// | ||
/// assert!(a as *const _ as usize == b as *const _ as usize); | ||
/// ``` | ||
/// Use instead: | ||
/// ```rust | ||
/// let a = &[1, 2, 3]; | ||
/// let b = &[1, 2, 3]; | ||
/// | ||
/// assert!(std::ptr::eq(a, b)); | ||
/// ``` | ||
pub PTR_EQ, | ||
style, | ||
"use `std::ptr::eq` when comparing raw pointers" | ||
} | ||
|
||
declare_lint_pass!(PtrEq => [PTR_EQ]); | ||
|
||
static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; | ||
|
||
impl LateLintPass<'_> for PtrEq { | ||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | ||
if utils::in_macro(expr.span) { | ||
return; | ||
} | ||
|
||
if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind { | ||
if BinOpKind::Eq == op.node { | ||
let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { | ||
(Some(lhs), Some(rhs)) => (lhs, rhs), | ||
_ => (&**left, &**right), | ||
}; | ||
|
||
if_chain! { | ||
if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); | ||
if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); | ||
if let Some(left_snip) = utils::snippet_opt(cx, left_var.span); | ||
if let Some(right_snip) = utils::snippet_opt(cx, right_var.span); | ||
then { | ||
utils::span_lint_and_sugg( | ||
cx, | ||
PTR_EQ, | ||
expr.span, | ||
LINT_MSG, | ||
"try", | ||
format!("std::ptr::eq({}, {})", left_snip, right_snip), | ||
Applicability::MachineApplicable, | ||
); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// If the given expression is a cast to an usize, return the lhs of the cast | ||
// E.g., `foo as *const _ as usize` returns `foo as *const _`. | ||
fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { | ||
if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize { | ||
if let ExprKind::Cast(ref expr, _) = cast_expr.kind { | ||
return Some(expr); | ||
} | ||
} | ||
None | ||
} | ||
|
||
// If the given expression is a cast to a `*const` pointer, return the lhs of the cast | ||
// E.g., `foo as *const _` returns `foo`. | ||
fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { | ||
if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() { | ||
if let ExprKind::Cast(ref expr, _) = cast_expr.kind { | ||
return Some(expr); | ||
} | ||
} | ||
None | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// run-rustfix | ||
#![warn(clippy::ptr_eq)] | ||
|
||
macro_rules! mac { | ||
($a:expr, $b:expr) => { | ||
$a as *const _ as usize == $b as *const _ as usize | ||
}; | ||
} | ||
|
||
macro_rules! another_mac { | ||
($a:expr, $b:expr) => { | ||
$a as *const _ == $b as *const _ | ||
}; | ||
} | ||
|
||
fn main() { | ||
let a = &[1, 2, 3]; | ||
let b = &[1, 2, 3]; | ||
|
||
let _ = std::ptr::eq(a, b); | ||
let _ = std::ptr::eq(a, b); | ||
let _ = a.as_ptr() == b as *const _; | ||
let _ = a.as_ptr() == b.as_ptr(); | ||
|
||
// Do not lint | ||
|
||
let _ = mac!(a, b); | ||
let _ = another_mac!(a, b); | ||
|
||
let a = &mut [1, 2, 3]; | ||
let b = &mut [1, 2, 3]; | ||
|
||
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; | ||
let _ = a.as_mut_ptr() == b.as_mut_ptr(); | ||
|
||
let _ = a == b; | ||
let _ = core::ptr::eq(a, b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// run-rustfix | ||
#![warn(clippy::ptr_eq)] | ||
|
||
macro_rules! mac { | ||
($a:expr, $b:expr) => { | ||
$a as *const _ as usize == $b as *const _ as usize | ||
}; | ||
} | ||
|
||
macro_rules! another_mac { | ||
($a:expr, $b:expr) => { | ||
$a as *const _ == $b as *const _ | ||
}; | ||
} | ||
|
||
fn main() { | ||
let a = &[1, 2, 3]; | ||
let b = &[1, 2, 3]; | ||
|
||
let _ = a as *const _ as usize == b as *const _ as usize; | ||
let _ = a as *const _ == b as *const _; | ||
let _ = a.as_ptr() == b as *const _; | ||
let _ = a.as_ptr() == b.as_ptr(); | ||
|
||
// Do not lint | ||
|
||
let _ = mac!(a, b); | ||
let _ = another_mac!(a, b); | ||
|
||
let a = &mut [1, 2, 3]; | ||
let b = &mut [1, 2, 3]; | ||
|
||
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; | ||
let _ = a.as_mut_ptr() == b.as_mut_ptr(); | ||
|
||
let _ = a == b; | ||
let _ = core::ptr::eq(a, b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
error: use `std::ptr::eq` when comparing raw pointers | ||
--> $DIR/ptr_eq.rs:20:13 | ||
| | ||
LL | let _ = a as *const _ as usize == b as *const _ as usize; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` | ||
| | ||
= note: `-D clippy::ptr-eq` implied by `-D warnings` | ||
|
||
error: use `std::ptr::eq` when comparing raw pointers | ||
--> $DIR/ptr_eq.rs:21:13 | ||
| | ||
LL | let _ = a as *const _ == b as *const _; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` | ||
|
||
error: aborting due to 2 previous errors | ||
|