Lint field accesses in explicit_auto_deref
This commit is contained in:
parent
a187d6412b
commit
20ea26234a
@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::{symbol::sym, Span};
|
use rustc_span::{symbol::sym, Span, Symbol};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
@ -181,6 +181,9 @@ enum State {
|
|||||||
deref_span: Span,
|
deref_span: Span,
|
||||||
deref_hir_id: HirId,
|
deref_hir_id: HirId,
|
||||||
},
|
},
|
||||||
|
ExplicitDerefField {
|
||||||
|
name: Symbol,
|
||||||
|
},
|
||||||
Reborrow {
|
Reborrow {
|
||||||
deref_span: Span,
|
deref_span: Span,
|
||||||
deref_hir_id: HirId,
|
deref_hir_id: HirId,
|
||||||
@ -243,8 +246,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
|||||||
(None, kind) => {
|
(None, kind) => {
|
||||||
let parent = get_parent_node(cx.tcx, expr.hir_id);
|
let parent = get_parent_node(cx.tcx, expr.hir_id);
|
||||||
let expr_ty = typeck.expr_ty(expr);
|
let expr_ty = typeck.expr_ty(expr);
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
|
RefOp::Deref => {
|
||||||
|
if let Some(Node::Expr(e)) = parent
|
||||||
|
&& let ExprKind::Field(_, name) = e.kind
|
||||||
|
&& !ty_contains_field(typeck.expr_ty(sub_expr), name.name)
|
||||||
|
{
|
||||||
|
self.state = Some((
|
||||||
|
State::ExplicitDerefField { name: name.name },
|
||||||
|
StateData { span: expr.span, hir_id: expr.hir_id },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
RefOp::Method(target_mut)
|
RefOp::Method(target_mut)
|
||||||
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
|
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
|
||||||
&& is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) =>
|
&& is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) =>
|
||||||
@ -349,7 +362,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => (),
|
RefOp::Method(..) => (),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
@ -436,6 +449,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
|||||||
(state @ Some((State::ExplicitDeref { .. }, _)), RefOp::Deref) => {
|
(state @ Some((State::ExplicitDeref { .. }, _)), RefOp::Deref) => {
|
||||||
self.state = state;
|
self.state = state;
|
||||||
},
|
},
|
||||||
|
(Some((State::ExplicitDerefField { name }, data)), RefOp::Deref)
|
||||||
|
if !ty_contains_field(typeck.expr_ty(sub_expr), name) =>
|
||||||
|
{
|
||||||
|
self.state = Some((State::ExplicitDerefField { name }, data));
|
||||||
|
},
|
||||||
|
|
||||||
(Some((state, data)), _) => report(cx, expr, state, data),
|
(Some((state, data)), _) => report(cx, expr, state, data),
|
||||||
}
|
}
|
||||||
@ -879,6 +897,14 @@ fn param_auto_deref_stability(ty: Ty<'_>) -> AutoDerefStability {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
|
||||||
|
if let ty::Adt(adt, _) = *ty.kind() {
|
||||||
|
adt.is_struct() && adt.non_enum_variant().fields.iter().any(|f| f.name == name)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[expect(clippy::needless_pass_by_value)]
|
#[expect(clippy::needless_pass_by_value)]
|
||||||
fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
|
fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
|
||||||
match state {
|
match state {
|
||||||
@ -968,6 +994,20 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
State::ExplicitDerefField { .. } => {
|
||||||
|
span_lint_hir_and_then(
|
||||||
|
cx,
|
||||||
|
EXPLICIT_AUTO_DEREF,
|
||||||
|
data.hir_id,
|
||||||
|
data.span,
|
||||||
|
"deref which would be done by auto-deref",
|
||||||
|
|diag| {
|
||||||
|
let mut app = Applicability::MachineApplicable;
|
||||||
|
let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
|
||||||
|
diag.span_suggestion(data.span, "try this", snip.into_owned(), app);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
State::Borrow | State::Reborrow { .. } => (),
|
State::Borrow | State::Reborrow { .. } => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,9 +362,9 @@ fn find_good_method_for_match<'a>(
|
|||||||
.qpath_res(path_right, arms[1].pat.hir_id)
|
.qpath_res(path_right, arms[1].pat.hir_id)
|
||||||
.opt_def_id()?;
|
.opt_def_id()?;
|
||||||
let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
|
let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
|
||||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
(&arms[0].body.kind, &arms[1].body.kind)
|
||||||
} else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
|
} else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
|
||||||
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
(&arms[1].body.kind, &arms[0].body.kind)
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
@ -164,4 +164,24 @@ fn main() {
|
|||||||
let ref_s = &s;
|
let ref_s = &s;
|
||||||
let _: &String = &*ref_s; // Don't lint reborrow.
|
let _: &String = &*ref_s; // Don't lint reborrow.
|
||||||
f_string(&*ref_s); // Don't lint reborrow.
|
f_string(&*ref_s); // Don't lint reborrow.
|
||||||
|
|
||||||
|
struct S5 {
|
||||||
|
foo: u32,
|
||||||
|
}
|
||||||
|
let b = Box::new(Box::new(S5 { foo: 5 }));
|
||||||
|
let _ = b.foo;
|
||||||
|
let _ = b.foo;
|
||||||
|
let _ = b.foo;
|
||||||
|
|
||||||
|
struct S6 {
|
||||||
|
foo: S5,
|
||||||
|
}
|
||||||
|
impl core::ops::Deref for S6 {
|
||||||
|
type Target = S5;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.foo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let s6 = S6 { foo: S5 { foo: 5 } };
|
||||||
|
let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo`
|
||||||
}
|
}
|
||||||
|
@ -164,4 +164,24 @@ fn main() {
|
|||||||
let ref_s = &s;
|
let ref_s = &s;
|
||||||
let _: &String = &*ref_s; // Don't lint reborrow.
|
let _: &String = &*ref_s; // Don't lint reborrow.
|
||||||
f_string(&*ref_s); // Don't lint reborrow.
|
f_string(&*ref_s); // Don't lint reborrow.
|
||||||
|
|
||||||
|
struct S5 {
|
||||||
|
foo: u32,
|
||||||
|
}
|
||||||
|
let b = Box::new(Box::new(S5 { foo: 5 }));
|
||||||
|
let _ = b.foo;
|
||||||
|
let _ = (*b).foo;
|
||||||
|
let _ = (**b).foo;
|
||||||
|
|
||||||
|
struct S6 {
|
||||||
|
foo: S5,
|
||||||
|
}
|
||||||
|
impl core::ops::Deref for S6 {
|
||||||
|
type Target = S5;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.foo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let s6 = S6 { foo: S5 { foo: 5 } };
|
||||||
|
let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo`
|
||||||
}
|
}
|
||||||
|
@ -156,5 +156,17 @@ error: deref which would be done by auto-deref
|
|||||||
LL | let _ = E1::S2 { s: &*s };
|
LL | let _ = E1::S2 { s: &*s };
|
||||||
| ^^ help: try this: `s`
|
| ^^ help: try this: `s`
|
||||||
|
|
||||||
error: aborting due to 26 previous errors
|
error: deref which would be done by auto-deref
|
||||||
|
--> $DIR/explicit_auto_deref.rs:173:13
|
||||||
|
|
|
||||||
|
LL | let _ = (*b).foo;
|
||||||
|
| ^^^^ help: try this: `b`
|
||||||
|
|
||||||
|
error: deref which would be done by auto-deref
|
||||||
|
--> $DIR/explicit_auto_deref.rs:174:13
|
||||||
|
|
|
||||||
|
LL | let _ = (**b).foo;
|
||||||
|
| ^^^^^ help: try this: `b`
|
||||||
|
|
||||||
|
error: aborting due to 28 previous errors
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user