Skip to content

Commit a2b2345

Browse files
committed
Fix coerce_container_to_any false positive on autoderef
1 parent 97815d0 commit a2b2345

File tree

3 files changed

+23
-12
lines changed

3 files changed

+23
-12
lines changed

clippy_lints/src/coerce_container_to_any.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use clippy_utils::sym;
44
use rustc_errors::Applicability;
55
use rustc_hir::{Expr, ExprKind};
66
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
78
use rustc_middle::ty::{self, ExistentialPredicate, Ty, TyCtxt};
89
use rustc_session::declare_lint_pass;
910

@@ -49,23 +50,18 @@ declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]);
4950

5051
impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny {
5152
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
52-
// If this expression has an effective type of `&dyn Any` ...
53-
{
54-
let coerced_ty = cx.typeck_results().expr_ty_adjusted(e);
55-
56-
let ty::Ref(_, coerced_ref_ty, _) = *coerced_ty.kind() else {
57-
return;
58-
};
59-
if !is_dyn_any(cx.tcx, coerced_ref_ty) {
60-
return;
61-
}
53+
// If this expression was coerced to `&dyn Any` ...
54+
if !cx.typeck_results().expr_adjustments(e).last().is_some_and(|adj| {
55+
matches!(adj.kind, Adjust::Pointer(PointerCoercion::Unsize)) && is_ref_dyn_any(cx.tcx, adj.target)
56+
}) {
57+
return;
6258
}
6359

6460
let expr_ty = cx.typeck_results().expr_ty(e);
6561
let ty::Ref(_, expr_ref_ty, _) = *expr_ty.kind() else {
6662
return;
6763
};
68-
// ... but only due to coercion ...
64+
// ... but it's not actually `&dyn Any` ...
6965
if is_dyn_any(cx.tcx, expr_ref_ty) {
7066
return;
7167
}
@@ -89,12 +85,19 @@ impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny {
8985
e.span,
9086
format!("coercing `{expr_ty}` to `&dyn Any`"),
9187
"consider dereferencing",
92-
format!("&{}{}", str::repeat("*", deref_count), snippet(cx, span, "x")),
88+
format!("&{}{}", str::repeat("*", deref_count), snippet(cx, span, "..")),
9389
Applicability::MaybeIncorrect,
9490
);
9591
}
9692
}
9793

94+
fn is_ref_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
95+
let ty::Ref(_, ref_ty, _) = *ty.kind() else {
96+
return false;
97+
};
98+
is_dyn_any(tcx, ref_ty)
99+
}
100+
98101
fn is_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
99102
let ty::Dynamic(traits, ..) = ty.kind() else {
100103
return false;

tests/ui/coerce_container_to_any.fixed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ fn main() {
2121
f(&**ref_x);
2222
f(&*x);
2323
let _: &dyn Any = &*x;
24+
25+
// https://github.com/rust-lang/rust-clippy/issues/15045
26+
#[allow(clippy::needless_borrow)]
27+
(&x).downcast_ref::<()>().unwrap();
2428
}
2529

2630
fn f(_: &dyn Any) {}

tests/ui/coerce_container_to_any.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ fn main() {
2121
f(&**ref_x);
2222
f(&*x);
2323
let _: &dyn Any = &*x;
24+
25+
// https://github.com/rust-lang/rust-clippy/issues/15045
26+
#[allow(clippy::needless_borrow)]
27+
(&x).downcast_ref::<()>().unwrap();
2428
}
2529

2630
fn f(_: &dyn Any) {}

0 commit comments

Comments
 (0)