Skip to content

Commit 8188da3

Browse files
committed
Fix suggestion on fully qualified syntax
1 parent 652b4c7 commit 8188da3

File tree

4 files changed

+132
-20
lines changed

4 files changed

+132
-20
lines changed

clippy_lints/src/dereference.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ impl_lint_pass!(Dereferencing<'_> => [
155155

156156
#[derive(Default)]
157157
pub struct Dereferencing<'tcx> {
158-
state: Option<(State, StateData)>,
158+
state: Option<(State<'tcx>, StateData)>,
159159

160160
// While parsing a `deref` method call in ufcs form, the path to the function is itself an
161161
// expression. This is to store the id of that expression so it can be skipped when
@@ -210,12 +210,13 @@ struct DerefedBorrow {
210210
}
211211

212212
#[derive(Debug)]
213-
enum State {
213+
enum State<'tcx> {
214214
// Any number of deref method calls.
215215
DerefMethod {
216216
// The number of calls in a sequence which changed the referenced type
217217
ty_changed_count: usize,
218218
is_final_ufcs: bool,
219+
call_args: Option<&'tcx [Expr<'tcx>]>,
219220
/// The required mutability
220221
target_mut: Mutability,
221222
},
@@ -312,10 +313,16 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
312313
&& position.lint_explicit_deref() =>
313314
{
314315
let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
316+
let (is_final_ufcs, call_args) = if let ExprKind::Call(_, args) = expr.kind {
317+
(true, Some(args))
318+
} else {
319+
(false, None)
320+
};
315321
self.state = Some((
316322
State::DerefMethod {
317323
ty_changed_count,
318-
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
324+
is_final_ufcs,
325+
call_args,
319326
target_mut,
320327
},
321328
StateData {
@@ -438,6 +445,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
438445
ty_changed_count + 1
439446
},
440447
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
448+
call_args: None,
441449
target_mut,
442450
},
443451
data,
@@ -1472,11 +1480,12 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
14721480
}
14731481

14741482
#[expect(clippy::needless_pass_by_value, clippy::too_many_lines)]
1475-
fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
1483+
fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State<'_>, data: StateData) {
14761484
match state {
14771485
State::DerefMethod {
14781486
ty_changed_count,
14791487
is_final_ufcs,
1488+
call_args,
14801489
target_mut,
14811490
} => {
14821491
let mut app = Applicability::MachineApplicable;
@@ -1503,12 +1512,25 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
15031512
"&"
15041513
};
15051514

1506-
let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
1515+
let mut expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
15071516
format!("({expr_str})")
15081517
} else {
15091518
expr_str.into_owned()
15101519
};
15111520

1521+
// Fix #10850, changes suggestion if it's `Foo::deref` instead of `foo.deref`. Since `Foo::deref` is
1522+
// a `Call` instead of a `MethodCall` this should catch all instances of this, even if it's fully
1523+
// qualified or whatnot.
1524+
if is_final_ufcs && let Some(args) = call_args {
1525+
// Remove ref if it's there
1526+
let arg = if let ExprKind::AddrOf(.., arg) = args[0].kind {
1527+
arg
1528+
} else {
1529+
&args[0]
1530+
};
1531+
expr_str = snippet_with_applicability(cx, arg.span, "{ .. }", &mut app).to_string();
1532+
}
1533+
15121534
span_lint_and_sugg(
15131535
cx,
15141536
EXPLICIT_DEREF_METHODS,

tests/ui/explicit_deref_methods.fixed

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
//@run-rustfix
22
#![warn(clippy::explicit_deref_methods)]
3-
#![allow(unused_variables)]
3+
#![allow(unused_variables, unused_must_use)]
44
#![allow(
55
clippy::borrow_deref_ref,
66
suspicious_double_ref_op,
77
clippy::explicit_auto_deref,
88
clippy::needless_borrow,
9+
clippy::no_effect,
910
clippy::uninlined_format_args
1011
)]
1112

@@ -28,6 +29,22 @@ impl Deref for CustomVec {
2829
}
2930
}
3031

32+
struct Aaa;
33+
34+
impl Deref for Aaa {
35+
type Target = ();
36+
37+
fn deref(&self) -> &Self::Target {
38+
todo!();
39+
}
40+
}
41+
42+
impl DerefMut for Aaa {
43+
fn deref_mut(&mut self) -> &mut Self::Target {
44+
todo!();
45+
}
46+
}
47+
3148
fn main() {
3249
let a: &mut String = &mut String::from("foo");
3350

@@ -58,6 +75,16 @@ fn main() {
5875
let opt_a = Some(a.clone());
5976
let b = &*opt_a.unwrap();
6077

78+
// make sure `Aaa::deref` instead of `aaa.deref()` works as well as fully qualified syntax
79+
80+
&*Aaa;
81+
&mut *Aaa;
82+
&*Aaa;
83+
&mut *Aaa;
84+
let mut aaa = Aaa;
85+
&*aaa;
86+
&mut *aaa;
87+
6188
// following should not require linting
6289

6390
let cv = CustomVec(vec![0, 42]);

tests/ui/explicit_deref_methods.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
//@run-rustfix
22
#![warn(clippy::explicit_deref_methods)]
3-
#![allow(unused_variables)]
3+
#![allow(unused_variables, unused_must_use)]
44
#![allow(
55
clippy::borrow_deref_ref,
66
suspicious_double_ref_op,
77
clippy::explicit_auto_deref,
88
clippy::needless_borrow,
9+
clippy::no_effect,
910
clippy::uninlined_format_args
1011
)]
1112

@@ -28,6 +29,22 @@ impl Deref for CustomVec {
2829
}
2930
}
3031

32+
struct Aaa;
33+
34+
impl Deref for Aaa {
35+
type Target = ();
36+
37+
fn deref(&self) -> &Self::Target {
38+
todo!();
39+
}
40+
}
41+
42+
impl DerefMut for Aaa {
43+
fn deref_mut(&mut self) -> &mut Self::Target {
44+
todo!();
45+
}
46+
}
47+
3148
fn main() {
3249
let a: &mut String = &mut String::from("foo");
3350

@@ -58,6 +75,16 @@ fn main() {
5875
let opt_a = Some(a.clone());
5976
let b = opt_a.unwrap().deref();
6077

78+
// make sure `Aaa::deref` instead of `aaa.deref()` works as well as fully qualified syntax
79+
80+
Aaa::deref(&Aaa);
81+
Aaa::deref_mut(&mut Aaa);
82+
<Aaa as Deref>::deref(&Aaa);
83+
<Aaa as DerefMut>::deref_mut(&mut Aaa);
84+
let mut aaa = Aaa;
85+
Aaa::deref(&aaa);
86+
Aaa::deref_mut(&mut aaa);
87+
6188
// following should not require linting
6289

6390
let cv = CustomVec(vec![0, 42]);
Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,112 @@
11
error: explicit `deref` method call
2-
--> $DIR/explicit_deref_methods.rs:36:19
2+
--> $DIR/explicit_deref_methods.rs:53:19
33
|
44
LL | let b: &str = a.deref();
55
| ^^^^^^^^^ help: try this: `&*a`
66
|
77
= note: `-D clippy::explicit-deref-methods` implied by `-D warnings`
88

99
error: explicit `deref_mut` method call
10-
--> $DIR/explicit_deref_methods.rs:38:23
10+
--> $DIR/explicit_deref_methods.rs:55:23
1111
|
1212
LL | let b: &mut str = a.deref_mut();
1313
| ^^^^^^^^^^^^^ help: try this: `&mut **a`
1414

1515
error: explicit `deref` method call
16-
--> $DIR/explicit_deref_methods.rs:41:39
16+
--> $DIR/explicit_deref_methods.rs:58:39
1717
|
1818
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
1919
| ^^^^^^^^^ help: try this: `&*a`
2020

2121
error: explicit `deref` method call
22-
--> $DIR/explicit_deref_methods.rs:41:50
22+
--> $DIR/explicit_deref_methods.rs:58:50
2323
|
2424
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
2525
| ^^^^^^^^^ help: try this: `&*a`
2626

2727
error: explicit `deref` method call
28-
--> $DIR/explicit_deref_methods.rs:43:20
28+
--> $DIR/explicit_deref_methods.rs:60:20
2929
|
3030
LL | println!("{}", a.deref());
3131
| ^^^^^^^^^ help: try this: `&*a`
3232

3333
error: explicit `deref` method call
34-
--> $DIR/explicit_deref_methods.rs:46:11
34+
--> $DIR/explicit_deref_methods.rs:63:11
3535
|
3636
LL | match a.deref() {
3737
| ^^^^^^^^^ help: try this: `&*a`
3838

3939
error: explicit `deref` method call
40-
--> $DIR/explicit_deref_methods.rs:50:28
40+
--> $DIR/explicit_deref_methods.rs:67:28
4141
|
4242
LL | let b: String = concat(a.deref());
4343
| ^^^^^^^^^ help: try this: `&*a`
4444

4545
error: explicit `deref` method call
46-
--> $DIR/explicit_deref_methods.rs:52:13
46+
--> $DIR/explicit_deref_methods.rs:69:13
4747
|
4848
LL | let b = just_return(a).deref();
4949
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`
5050

5151
error: explicit `deref` method call
52-
--> $DIR/explicit_deref_methods.rs:54:28
52+
--> $DIR/explicit_deref_methods.rs:71:28
5353
|
5454
LL | let b: String = concat(just_return(a).deref());
5555
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`
5656

5757
error: explicit `deref` method call
58-
--> $DIR/explicit_deref_methods.rs:56:19
58+
--> $DIR/explicit_deref_methods.rs:73:19
5959
|
6060
LL | let b: &str = a.deref().deref();
6161
| ^^^^^^^^^^^^^^^^^ help: try this: `&**a`
6262

6363
error: explicit `deref` method call
64-
--> $DIR/explicit_deref_methods.rs:59:13
64+
--> $DIR/explicit_deref_methods.rs:76:13
6565
|
6666
LL | let b = opt_a.unwrap().deref();
6767
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()`
6868

6969
error: explicit `deref` method call
70-
--> $DIR/explicit_deref_methods.rs:85:31
70+
--> $DIR/explicit_deref_methods.rs:80:5
71+
|
72+
LL | Aaa::deref(&Aaa);
73+
| ^^^^^^^^^^^^^^^^ help: try this: `&*Aaa`
74+
75+
error: explicit `deref_mut` method call
76+
--> $DIR/explicit_deref_methods.rs:81:5
77+
|
78+
LL | Aaa::deref_mut(&mut Aaa);
79+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut *Aaa`
80+
81+
error: explicit `deref` method call
82+
--> $DIR/explicit_deref_methods.rs:82:5
83+
|
84+
LL | <Aaa as Deref>::deref(&Aaa);
85+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*Aaa`
86+
87+
error: explicit `deref_mut` method call
88+
--> $DIR/explicit_deref_methods.rs:83:5
89+
|
90+
LL | <Aaa as DerefMut>::deref_mut(&mut Aaa);
91+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut *Aaa`
92+
93+
error: explicit `deref` method call
94+
--> $DIR/explicit_deref_methods.rs:85:5
95+
|
96+
LL | Aaa::deref(&aaa);
97+
| ^^^^^^^^^^^^^^^^ help: try this: `&*aaa`
98+
99+
error: explicit `deref_mut` method call
100+
--> $DIR/explicit_deref_methods.rs:86:5
101+
|
102+
LL | Aaa::deref_mut(&mut aaa);
103+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut *aaa`
104+
105+
error: explicit `deref` method call
106+
--> $DIR/explicit_deref_methods.rs:112:31
71107
|
72108
LL | let b: &str = expr_deref!(a.deref());
73109
| ^^^^^^^^^ help: try this: `&*a`
74110

75-
error: aborting due to 12 previous errors
111+
error: aborting due to 18 previous errors
76112

0 commit comments

Comments
 (0)