Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 20ea262

Browse files
committed
Lint field accesses in explicit_auto_deref
1 parent a187d64 commit 20ea262

File tree

5 files changed

+98
-6
lines changed

5 files changed

+98
-6
lines changed

clippy_lints/src/dereference.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
1515
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
1616
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
1717
use rustc_session::{declare_tool_lint, impl_lint_pass};
18-
use rustc_span::{symbol::sym, Span};
18+
use rustc_span::{symbol::sym, Span, Symbol};
1919

2020
declare_clippy_lint! {
2121
/// ### What it does
@@ -181,6 +181,9 @@ enum State {
181181
deref_span: Span,
182182
deref_hir_id: HirId,
183183
},
184+
ExplicitDerefField {
185+
name: Symbol,
186+
},
184187
Reborrow {
185188
deref_span: Span,
186189
deref_hir_id: HirId,
@@ -243,8 +246,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
243246
(None, kind) => {
244247
let parent = get_parent_node(cx.tcx, expr.hir_id);
245248
let expr_ty = typeck.expr_ty(expr);
246-
247249
match kind {
250+
RefOp::Deref => {
251+
if let Some(Node::Expr(e)) = parent
252+
&& let ExprKind::Field(_, name) = e.kind
253+
&& !ty_contains_field(typeck.expr_ty(sub_expr), name.name)
254+
{
255+
self.state = Some((
256+
State::ExplicitDerefField { name: name.name },
257+
StateData { span: expr.span, hir_id: expr.hir_id },
258+
));
259+
}
260+
}
248261
RefOp::Method(target_mut)
249262
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
250263
&& is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) =>
@@ -349,7 +362,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
349362
));
350363
}
351364
},
352-
_ => (),
365+
RefOp::Method(..) => (),
353366
}
354367
},
355368
(
@@ -436,6 +449,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
436449
(state @ Some((State::ExplicitDeref { .. }, _)), RefOp::Deref) => {
437450
self.state = state;
438451
},
452+
(Some((State::ExplicitDerefField { name }, data)), RefOp::Deref)
453+
if !ty_contains_field(typeck.expr_ty(sub_expr), name) =>
454+
{
455+
self.state = Some((State::ExplicitDerefField { name }, data));
456+
},
439457

440458
(Some((state, data)), _) => report(cx, expr, state, data),
441459
}
@@ -879,6 +897,14 @@ fn param_auto_deref_stability(ty: Ty<'_>) -> AutoDerefStability {
879897
}
880898
}
881899

900+
fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
901+
if let ty::Adt(adt, _) = *ty.kind() {
902+
adt.is_struct() && adt.non_enum_variant().fields.iter().any(|f| f.name == name)
903+
} else {
904+
false
905+
}
906+
}
907+
882908
#[expect(clippy::needless_pass_by_value)]
883909
fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
884910
match state {
@@ -968,6 +994,20 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
968994
},
969995
);
970996
},
997+
State::ExplicitDerefField { .. } => {
998+
span_lint_hir_and_then(
999+
cx,
1000+
EXPLICIT_AUTO_DEREF,
1001+
data.hir_id,
1002+
data.span,
1003+
"deref which would be done by auto-deref",
1004+
|diag| {
1005+
let mut app = Applicability::MachineApplicable;
1006+
let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
1007+
diag.span_suggestion(data.span, "try this", snip.into_owned(), app);
1008+
},
1009+
);
1010+
},
9711011
State::Borrow | State::Reborrow { .. } => (),
9721012
}
9731013
}

clippy_lints/src/matches/redundant_pattern_match.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,9 @@ fn find_good_method_for_match<'a>(
362362
.qpath_res(path_right, arms[1].pat.hir_id)
363363
.opt_def_id()?;
364364
let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
365-
(&(*arms[0].body).kind, &(*arms[1].body).kind)
365+
(&arms[0].body.kind, &arms[1].body.kind)
366366
} else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
367-
(&(*arms[1].body).kind, &(*arms[0].body).kind)
367+
(&arms[1].body.kind, &arms[0].body.kind)
368368
} else {
369369
return None;
370370
};

tests/ui/explicit_auto_deref.fixed

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,24 @@ fn main() {
164164
let ref_s = &s;
165165
let _: &String = &*ref_s; // Don't lint reborrow.
166166
f_string(&*ref_s); // Don't lint reborrow.
167+
168+
struct S5 {
169+
foo: u32,
170+
}
171+
let b = Box::new(Box::new(S5 { foo: 5 }));
172+
let _ = b.foo;
173+
let _ = b.foo;
174+
let _ = b.foo;
175+
176+
struct S6 {
177+
foo: S5,
178+
}
179+
impl core::ops::Deref for S6 {
180+
type Target = S5;
181+
fn deref(&self) -> &Self::Target {
182+
&self.foo
183+
}
184+
}
185+
let s6 = S6 { foo: S5 { foo: 5 } };
186+
let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo`
167187
}

tests/ui/explicit_auto_deref.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,24 @@ fn main() {
164164
let ref_s = &s;
165165
let _: &String = &*ref_s; // Don't lint reborrow.
166166
f_string(&*ref_s); // Don't lint reborrow.
167+
168+
struct S5 {
169+
foo: u32,
170+
}
171+
let b = Box::new(Box::new(S5 { foo: 5 }));
172+
let _ = b.foo;
173+
let _ = (*b).foo;
174+
let _ = (**b).foo;
175+
176+
struct S6 {
177+
foo: S5,
178+
}
179+
impl core::ops::Deref for S6 {
180+
type Target = S5;
181+
fn deref(&self) -> &Self::Target {
182+
&self.foo
183+
}
184+
}
185+
let s6 = S6 { foo: S5 { foo: 5 } };
186+
let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo`
167187
}

tests/ui/explicit_auto_deref.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,17 @@ error: deref which would be done by auto-deref
156156
LL | let _ = E1::S2 { s: &*s };
157157
| ^^ help: try this: `s`
158158

159-
error: aborting due to 26 previous errors
159+
error: deref which would be done by auto-deref
160+
--> $DIR/explicit_auto_deref.rs:173:13
161+
|
162+
LL | let _ = (*b).foo;
163+
| ^^^^ help: try this: `b`
164+
165+
error: deref which would be done by auto-deref
166+
--> $DIR/explicit_auto_deref.rs:174:13
167+
|
168+
LL | let _ = (**b).foo;
169+
| ^^^^^ help: try this: `b`
170+
171+
error: aborting due to 28 previous errors
160172

0 commit comments

Comments
 (0)