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

Commit 442a68c

Browse files
committed
Only check parent node once in dereference.rs
1 parent 20ea262 commit 442a68c

File tree

1 file changed

+40
-75
lines changed

1 file changed

+40
-75
lines changed

clippy_lints/src/dereference.rs

Lines changed: 40 additions & 75 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, Symbol};
18+
use rustc_span::{symbol::sym, Span, Symbol, SyntaxContext};
1919

2020
declare_clippy_lint! {
2121
/// ### What it does
@@ -244,23 +244,22 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
244244

245245
match (self.state.take(), kind) {
246246
(None, kind) => {
247-
let parent = get_parent_node(cx.tcx, expr.hir_id);
248247
let expr_ty = typeck.expr_ty(expr);
248+
let (position, parent_ctxt) = get_expr_position(cx, expr);
249249
match kind {
250250
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)
251+
if let Position::FieldAccess(name) = position
252+
&& !ty_contains_field(typeck.expr_ty(sub_expr), name)
254253
{
255254
self.state = Some((
256-
State::ExplicitDerefField { name: name.name },
255+
State::ExplicitDerefField { name },
257256
StateData { span: expr.span, hir_id: expr.hir_id },
258257
));
259258
}
260259
}
261260
RefOp::Method(target_mut)
262261
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
263-
&& is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) =>
262+
&& (position.lint_explicit_deref() || parent_ctxt != expr.span.ctxt()) =>
264263
{
265264
self.state = Some((
266265
State::DerefMethod {
@@ -322,8 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
322321
"this expression creates a reference which is immediately dereferenced by the compiler";
323322
let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
324323

325-
let (required_refs, required_precedence, msg) = if is_auto_borrow_position(parent, expr.hir_id)
326-
{
324+
let (required_refs, required_precedence, msg) = if position.can_auto_borrow() {
327325
(1, PREC_POSTFIX, if deref_count == 1 { borrow_msg } else { deref_msg })
328326
} else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
329327
next_adjust.map(|a| &a.kind)
@@ -573,60 +571,41 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
573571
}
574572
}
575573

576-
// Checks whether the parent node is a suitable context for switching from a deref method to the
577-
// deref operator.
578-
fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId, child_span: Span) -> bool {
579-
let parent = match parent {
580-
Some(Node::Expr(e)) if e.span.ctxt() == child_span.ctxt() => e,
581-
_ => return true,
582-
};
583-
match parent.kind {
584-
// Leave deref calls in the middle of a method chain.
585-
// e.g. x.deref().foo()
586-
ExprKind::MethodCall(_, [self_arg, ..], _) if self_arg.hir_id == child_id => false,
587-
588-
// Leave deref calls resulting in a called function
589-
// e.g. (x.deref())()
590-
ExprKind::Call(func_expr, _) if func_expr.hir_id == child_id => false,
574+
#[derive(Clone, Copy)]
575+
enum Position {
576+
MethodReceiver,
577+
FieldAccess(Symbol),
578+
Callee,
579+
Postfix,
580+
Deref,
581+
Other,
582+
}
583+
impl Position {
584+
fn can_auto_borrow(self) -> bool {
585+
matches!(self, Self::MethodReceiver | Self::FieldAccess(_) | Self::Callee)
586+
}
591587

592-
// Makes an ugly suggestion
593-
// e.g. *x.deref() => *&*x
594-
ExprKind::Unary(UnOp::Deref, _)
595-
// Postfix expressions would require parens
596-
| ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
597-
| ExprKind::Field(..)
598-
| ExprKind::Index(..)
599-
| ExprKind::Err => false,
588+
fn lint_explicit_deref(self) -> bool {
589+
matches!(self, Self::Other)
590+
}
591+
}
600592

601-
ExprKind::Box(..)
602-
| ExprKind::ConstBlock(..)
603-
| ExprKind::Array(_)
604-
| ExprKind::Call(..)
605-
| ExprKind::MethodCall(..)
606-
| ExprKind::Tup(..)
607-
| ExprKind::Binary(..)
608-
| ExprKind::Unary(..)
609-
| ExprKind::Lit(..)
610-
| ExprKind::Cast(..)
611-
| ExprKind::Type(..)
612-
| ExprKind::DropTemps(..)
613-
| ExprKind::If(..)
614-
| ExprKind::Loop(..)
615-
| ExprKind::Match(..)
616-
| ExprKind::Let(..)
617-
| ExprKind::Closure{..}
618-
| ExprKind::Block(..)
619-
| ExprKind::Assign(..)
620-
| ExprKind::AssignOp(..)
621-
| ExprKind::Path(..)
622-
| ExprKind::AddrOf(..)
623-
| ExprKind::Break(..)
624-
| ExprKind::Continue(..)
625-
| ExprKind::Ret(..)
626-
| ExprKind::InlineAsm(..)
627-
| ExprKind::Struct(..)
628-
| ExprKind::Repeat(..)
629-
| ExprKind::Yield(..) => true,
593+
/// Get which position an expression is in relative to it's parent.
594+
fn get_expr_position(cx: &LateContext<'_>, e: &Expr<'_>) -> (Position, SyntaxContext) {
595+
if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, e.hir_id) {
596+
let pos = match parent.kind {
597+
ExprKind::MethodCall(_, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => Position::MethodReceiver,
598+
ExprKind::Field(_, name) => Position::FieldAccess(name.name),
599+
ExprKind::Call(f, _) if f.hir_id == e.hir_id => Position::Callee,
600+
ExprKind::Unary(UnOp::Deref, _) => Position::Deref,
601+
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Index(..) => {
602+
Position::Postfix
603+
},
604+
_ => Position::Other,
605+
};
606+
(pos, parent.span.ctxt())
607+
} else {
608+
(Position::Other, SyntaxContext::root())
630609
}
631610
}
632611

@@ -748,20 +727,6 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (AutoDerefSt
748727
(stability, adjustments)
749728
}
750729

751-
/// Checks if the given expression is a position which can auto-borrow.
752-
fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool {
753-
if let Some(Node::Expr(parent)) = parent {
754-
match parent.kind {
755-
// ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
756-
ExprKind::Field(..) => true,
757-
ExprKind::Call(f, _) => f.hir_id == child_id,
758-
_ => false,
759-
}
760-
} else {
761-
false
762-
}
763-
}
764-
765730
// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
766731
//
767732
// e.g.

0 commit comments

Comments
 (0)