Skip to content

Commit 24dd8a0

Browse files
committed
Do not lint data coming from macro
Suggesting to remove `*&` or `*&mut` in a macro may be incorrect, as it would require tracking all possible macro usages. In some cases, it is not possible to remove the dereference or the reference. For example, in the following code, the `drmut!()` macro will be linted against while called as `drmut!(d)`, and the suggestion would be to remove the `*&mut`. That would make `drmut!(u.data).num = 1` invalid, as a `ManuallyDrop` object coming through a union cannot be implicitely dereferenced through `DerefMut`. ```rust use std::mem::ManuallyDrop; #[derive(Copy, Clone)] struct Data { num: u64, } union Union { data: ManuallyDrop<Data>, } macro_rules! drmut { ($e:expr) => { *&mut $e }; } fn f(mut u: Union, mut d: Data) { unsafe { drmut!(u.data).num = 1; } drmut!(d).num = 1; } ```
1 parent 9b2e423 commit 24dd8a0

File tree

4 files changed

+73
-133
lines changed

4 files changed

+73
-133
lines changed

clippy_lints/src/reference.rs

+26-62
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
2+
use clippy_utils::source::snippet;
3+
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
34
use clippy_utils::ty::adjust_derefs_manually_drop;
45
use rustc_errors::Applicability;
5-
use rustc_hir::{Expr, ExprKind, HirId, Mutability, Node, UnOp};
6+
use rustc_hir::{Expr, ExprKind, HirId, Node, UnOp};
67
use rustc_lint::{LateContext, LateLintPass};
78
use rustc_session::declare_lint_pass;
8-
use rustc_span::{BytePos, Span};
99

1010
declare_clippy_lint! {
1111
/// ### What it does
@@ -40,79 +40,43 @@ declare_lint_pass!(DerefAddrOf => [DEREF_ADDROF]);
4040

4141
impl LateLintPass<'_> for DerefAddrOf {
4242
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
43-
if let ExprKind::Unary(UnOp::Deref, deref_target) = e.kind
44-
&& let ExprKind::AddrOf(_, mutability, addrof_target) = deref_target.kind
43+
if !e.span.from_expansion()
44+
&& let ExprKind::Unary(UnOp::Deref, deref_target) = e.kind
45+
&& !deref_target.span.from_expansion()
46+
&& let ExprKind::AddrOf(_, _, addrof_target) = deref_target.kind
4547
// NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section.
4648
// See #12854 for details.
4749
&& !matches!(addrof_target.kind, ExprKind::Array(_))
4850
&& deref_target.span.eq_ctxt(e.span)
4951
&& !addrof_target.span.from_expansion()
5052
{
53+
let mut applicability = Applicability::MachineApplicable;
54+
let sugg = Sugg::hir_with_applicability(cx, addrof_target, "_", &mut applicability);
55+
5156
// If this expression is an explicit `DerefMut` of a `ManuallyDrop` reached through a
5257
// union, we may remove the reference if we are at the point where the implicit
5358
// dereference would take place. Otherwise, we should not lint.
54-
let keep_deref = match is_manually_drop_through_union(cx, e.hir_id, addrof_target) {
55-
ManuallyDropThroughUnion::Directly => true,
59+
let sugg = match is_manually_drop_through_union(cx, e.hir_id, addrof_target) {
60+
ManuallyDropThroughUnion::Directly => sugg.deref(),
5661
ManuallyDropThroughUnion::Indirect => return,
57-
ManuallyDropThroughUnion::No => false,
62+
ManuallyDropThroughUnion::No => sugg,
5863
};
5964

60-
let mut applicability = Applicability::MachineApplicable;
61-
let sugg = if e.span.from_expansion() {
62-
if let Some(macro_source) = e.span.get_source_text(cx) {
63-
// Remove leading whitespace from the given span
64-
// e.g: ` $visitor` turns into `$visitor`
65-
let trim_leading_whitespaces = |span: Span| {
66-
span.get_source_text(cx)
67-
.and_then(|snip| {
68-
#[expect(clippy::cast_possible_truncation)]
69-
snip.find(|c: char| !c.is_whitespace())
70-
.map(|pos| span.lo() + BytePos(pos as u32))
71-
})
72-
.map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace))
73-
};
74-
75-
let mut generate_snippet = |pattern: &str| {
76-
#[expect(clippy::cast_possible_truncation)]
77-
macro_source.rfind(pattern).map(|pattern_pos| {
78-
let rpos = pattern_pos + pattern.len();
79-
let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
80-
let span = trim_leading_whitespaces(span_after_ref);
81-
snippet_with_applicability(cx, span, "_", &mut applicability)
82-
})
83-
};
84-
85-
if mutability == Mutability::Mut {
86-
generate_snippet("mut")
87-
} else {
88-
generate_snippet("&")
89-
}
90-
} else {
91-
Some(snippet_with_applicability(cx, e.span, "_", &mut applicability))
92-
}
65+
let sugg = if has_enclosing_paren(snippet(cx, e.span, "")) {
66+
sugg.maybe_paren()
9367
} else {
94-
Some(snippet_with_applicability(
95-
cx,
96-
addrof_target.span,
97-
"_",
98-
&mut applicability,
99-
))
68+
sugg
10069
};
101-
if let Some(sugg) = sugg {
102-
span_lint_and_sugg(
103-
cx,
104-
DEREF_ADDROF,
105-
e.span,
106-
"immediately dereferencing a reference",
107-
"try",
108-
if keep_deref {
109-
format!("(*{sugg})")
110-
} else {
111-
sugg.to_string()
112-
},
113-
applicability,
114-
);
115-
}
70+
71+
span_lint_and_sugg(
72+
cx,
73+
DEREF_ADDROF,
74+
e.span,
75+
"immediately dereferencing a reference",
76+
"try",
77+
sugg.to_string(),
78+
applicability,
79+
);
11680
}
11781
}
11882
}

tests/ui/deref_addrof.fixed

+14-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//@aux-build:proc_macros.rs
2-
31
#![allow(
42
dangerous_implicit_autorefs,
53
clippy::explicit_auto_deref,
@@ -8,9 +6,6 @@
86
)]
97
#![warn(clippy::deref_addrof)]
108

11-
extern crate proc_macros;
12-
use proc_macros::inline_macros;
13-
149
fn get_number() -> usize {
1510
10
1611
}
@@ -61,21 +56,22 @@ fn main() {
6156
//~^ deref_addrof
6257
// do NOT lint for array as semantic differences with/out `*&`.
6358
let _arr = *&[0, 1, 2, 3, 4];
64-
}
6559

66-
#[derive(Copy, Clone)]
67-
pub struct S;
68-
#[inline_macros]
69-
impl S {
70-
pub fn f(&self) -> &Self {
71-
inline!($(@expr self))
72-
//~^ deref_addrof
73-
}
74-
#[allow(unused_mut)] // mut will be unused, once the macro is fixed
75-
pub fn f_mut(mut self) -> Self {
76-
inline!($(@expr self))
77-
//~^ deref_addrof
60+
// Do not lint when text comes from macro
61+
macro_rules! mac {
62+
(dr) => {
63+
*&0
64+
};
65+
(dr $e:expr) => {
66+
*&$e
67+
};
68+
(r $e:expr) => {
69+
&$e
70+
};
7871
}
72+
let b = mac!(dr);
73+
let b = mac!(dr a);
74+
let b = *mac!(r a);
7975
}
8076

8177
fn issue14386() {

tests/ui/deref_addrof.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//@aux-build:proc_macros.rs
2-
31
#![allow(
42
dangerous_implicit_autorefs,
53
clippy::explicit_auto_deref,
@@ -8,9 +6,6 @@
86
)]
97
#![warn(clippy::deref_addrof)]
108

11-
extern crate proc_macros;
12-
use proc_macros::inline_macros;
13-
149
fn get_number() -> usize {
1510
10
1611
}
@@ -61,21 +56,22 @@ fn main() {
6156
//~^ deref_addrof
6257
// do NOT lint for array as semantic differences with/out `*&`.
6358
let _arr = *&[0, 1, 2, 3, 4];
64-
}
6559

66-
#[derive(Copy, Clone)]
67-
pub struct S;
68-
#[inline_macros]
69-
impl S {
70-
pub fn f(&self) -> &Self {
71-
inline!(*& $(@expr self))
72-
//~^ deref_addrof
73-
}
74-
#[allow(unused_mut)] // mut will be unused, once the macro is fixed
75-
pub fn f_mut(mut self) -> Self {
76-
inline!(*&mut $(@expr self))
77-
//~^ deref_addrof
60+
// Do not lint when text comes from macro
61+
macro_rules! mac {
62+
(dr) => {
63+
*&0
64+
};
65+
(dr $e:expr) => {
66+
*&$e
67+
};
68+
(r $e:expr) => {
69+
&$e
70+
};
7871
}
72+
let b = mac!(dr);
73+
let b = mac!(dr a);
74+
let b = *mac!(r a);
7975
}
8076

8177
fn issue14386() {

tests/ui/deref_addrof.stderr

+19-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: immediately dereferencing a reference
2-
--> tests/ui/deref_addrof.rs:28:13
2+
--> tests/ui/deref_addrof.rs:23:13
33
|
44
LL | let b = *&a;
55
| ^^^ help: try: `a`
@@ -8,122 +8,106 @@ LL | let b = *&a;
88
= help: to override `-D warnings` add `#[allow(clippy::deref_addrof)]`
99

1010
error: immediately dereferencing a reference
11-
--> tests/ui/deref_addrof.rs:31:13
11+
--> tests/ui/deref_addrof.rs:26:13
1212
|
1313
LL | let b = *&get_number();
1414
| ^^^^^^^^^^^^^^ help: try: `get_number()`
1515

1616
error: immediately dereferencing a reference
17-
--> tests/ui/deref_addrof.rs:37:13
17+
--> tests/ui/deref_addrof.rs:32:13
1818
|
1919
LL | let b = *&bytes[1..2][0];
2020
| ^^^^^^^^^^^^^^^^ help: try: `bytes[1..2][0]`
2121

2222
error: immediately dereferencing a reference
23-
--> tests/ui/deref_addrof.rs:42:13
23+
--> tests/ui/deref_addrof.rs:37:13
2424
|
2525
LL | let b = *&(a);
2626
| ^^^^^ help: try: `(a)`
2727

2828
error: immediately dereferencing a reference
29-
--> tests/ui/deref_addrof.rs:45:13
29+
--> tests/ui/deref_addrof.rs:40:13
3030
|
3131
LL | let b = *(&a);
3232
| ^^^^^ help: try: `a`
3333

3434
error: immediately dereferencing a reference
35-
--> tests/ui/deref_addrof.rs:49:13
35+
--> tests/ui/deref_addrof.rs:44:13
3636
|
3737
LL | let b = *((&a));
3838
| ^^^^^^^ help: try: `a`
3939

4040
error: immediately dereferencing a reference
41-
--> tests/ui/deref_addrof.rs:52:13
41+
--> tests/ui/deref_addrof.rs:47:13
4242
|
4343
LL | let b = *&&a;
4444
| ^^^^ help: try: `&a`
4545

4646
error: immediately dereferencing a reference
47-
--> tests/ui/deref_addrof.rs:55:14
47+
--> tests/ui/deref_addrof.rs:50:14
4848
|
4949
LL | let b = **&aref;
5050
| ^^^^^^ help: try: `aref`
5151

5252
error: immediately dereferencing a reference
53-
--> tests/ui/deref_addrof.rs:60:19
53+
--> tests/ui/deref_addrof.rs:55:19
5454
|
5555
LL | let _repeat = *&[0; 64];
5656
| ^^^^^^^^^ help: try: `[0; 64]`
5757

5858
error: immediately dereferencing a reference
59-
--> tests/ui/deref_addrof.rs:71:17
60-
|
61-
LL | inline!(*& $(@expr self))
62-
| ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
63-
|
64-
= note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
65-
66-
error: immediately dereferencing a reference
67-
--> tests/ui/deref_addrof.rs:76:17
68-
|
69-
LL | inline!(*&mut $(@expr self))
70-
| ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
71-
|
72-
= note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
73-
74-
error: immediately dereferencing a reference
75-
--> tests/ui/deref_addrof.rs:108:9
59+
--> tests/ui/deref_addrof.rs:104:9
7660
|
7761
LL | (*&mut a.padding) = [1; size_of::<DataWithPadding>()];
7862
| ^^^^^^^^^^^^^^^^^ help: try: `a.padding`
7963

8064
error: immediately dereferencing a reference
81-
--> tests/ui/deref_addrof.rs:110:9
65+
--> tests/ui/deref_addrof.rs:106:9
8266
|
8367
LL | (*&mut a.tup).1 = ();
8468
| ^^^^^^^^^^^^^ help: try: `a.tup`
8569

8670
error: immediately dereferencing a reference
87-
--> tests/ui/deref_addrof.rs:112:10
71+
--> tests/ui/deref_addrof.rs:108:10
8872
|
8973
LL | **&mut a.prim = 0;
9074
| ^^^^^^^^^^^^ help: try: `a.prim`
9175

9276
error: immediately dereferencing a reference
93-
--> tests/ui/deref_addrof.rs:115:9
77+
--> tests/ui/deref_addrof.rs:111:9
9478
|
9579
LL | (*&mut a.data).num = 42;
9680
| ^^^^^^^^^^^^^^ help: try: `(*a.data)`
9781

9882
error: immediately dereferencing a reference
99-
--> tests/ui/deref_addrof.rs:117:9
83+
--> tests/ui/deref_addrof.rs:113:9
10084
|
10185
LL | (*&mut a.indirect.md)[3] = 1;
10286
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect.md)`
10387

10488
error: immediately dereferencing a reference
105-
--> tests/ui/deref_addrof.rs:119:9
89+
--> tests/ui/deref_addrof.rs:115:9
10690
|
10791
LL | (*&mut a.indirect_arr[1].md)[3] = 1;
10892
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_arr[1].md)`
10993

11094
error: immediately dereferencing a reference
111-
--> tests/ui/deref_addrof.rs:121:9
95+
--> tests/ui/deref_addrof.rs:117:9
11296
|
11397
LL | (*&mut a.indirect_ref.md)[3] = 1;
11498
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_ref.md)`
11599

116100
error: immediately dereferencing a reference
117-
--> tests/ui/deref_addrof.rs:125:10
101+
--> tests/ui/deref_addrof.rs:121:10
118102
|
119103
LL | **&raw mut a.prim = 0;
120104
| ^^^^^^^^^^^^^^^^ help: try: `a.prim`
121105

122106
error: immediately dereferencing a reference
123-
--> tests/ui/deref_addrof.rs:127:9
107+
--> tests/ui/deref_addrof.rs:123:9
124108
|
125109
LL | (*&raw mut a.data).num = 42;
126110
| ^^^^^^^^^^^^^^^^^^ help: try: `(*a.data)`
127111

128-
error: aborting due to 20 previous errors
112+
error: aborting due to 18 previous errors
129113

0 commit comments

Comments
 (0)