Skip to content

Commit bca8931

Browse files
authored
Fix coerce_container_to_any false positive on autoderef (#15057)
Fixes the false positive reported in #15045. ~I still need to work out how to fix the suggestion.~ changelog: none
2 parents 936baca + dc1b9ce commit bca8931

File tree

4 files changed

+64
-20
lines changed

4 files changed

+64
-20
lines changed

clippy_lints/src/coerce_container_to_any.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::snippet;
2+
use clippy_utils::sugg::{self, Sugg};
33
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
}
@@ -78,23 +74,37 @@ impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny {
7874
}
7975

8076
// ... that's probably not intended.
81-
let (span, deref_count) = match e.kind {
77+
let (target_expr, deref_count) = match e.kind {
8278
// If `e` was already an `&` expression, skip `*&` in the suggestion
83-
ExprKind::AddrOf(_, _, referent) => (referent.span, depth),
84-
_ => (e.span, depth + 1),
79+
ExprKind::AddrOf(_, _, referent) => (referent, depth),
80+
_ => (e, depth + 1),
8581
};
82+
let ty::Ref(_, _, mutability) = *cx.typeck_results().expr_ty_adjusted(e).kind() else {
83+
return;
84+
};
85+
let sugg = sugg::make_unop(
86+
&format!("{}{}", mutability.ref_prefix_str(), str::repeat("*", deref_count)),
87+
Sugg::hir(cx, target_expr, ".."),
88+
);
8689
span_lint_and_sugg(
8790
cx,
8891
COERCE_CONTAINER_TO_ANY,
8992
e.span,
90-
format!("coercing `{expr_ty}` to `&dyn Any`"),
93+
format!("coercing `{expr_ty}` to `{}dyn Any`", mutability.ref_prefix_str()),
9194
"consider dereferencing",
92-
format!("&{}{}", str::repeat("*", deref_count), snippet(cx, span, "x")),
95+
sugg.to_string(),
9396
Applicability::MaybeIncorrect,
9497
);
9598
}
9699
}
97100

101+
fn is_ref_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
102+
let ty::Ref(_, ref_ty, _) = *ty.kind() else {
103+
return false;
104+
};
105+
is_dyn_any(tcx, ref_ty)
106+
}
107+
98108
fn is_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
99109
let ty::Dynamic(traits, ..) = ty.kind() else {
100110
return false;

tests/ui/coerce_container_to_any.fixed

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::any::Any;
44

55
fn main() {
6-
let x: Box<dyn Any> = Box::new(());
6+
let mut x: Box<dyn Any> = Box::new(());
77
let ref_x = &x;
88

99
f(&*x);
@@ -15,12 +15,23 @@ fn main() {
1515
let _: &dyn Any = &*x;
1616
//~^ coerce_container_to_any
1717

18+
let _: &dyn Any = &*x;
19+
//~^ coerce_container_to_any
20+
21+
let _: &mut dyn Any = &mut *x;
22+
//~^ coerce_container_to_any
23+
1824
f(&42);
1925
f(&Box::new(()));
2026
f(&Box::new(Box::new(())));
27+
let ref_x = &x;
2128
f(&**ref_x);
2229
f(&*x);
2330
let _: &dyn Any = &*x;
31+
32+
// https://github.com/rust-lang/rust-clippy/issues/15045
33+
#[allow(clippy::needless_borrow)]
34+
(&x).downcast_ref::<()>().unwrap();
2435
}
2536

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

tests/ui/coerce_container_to_any.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::any::Any;
44

55
fn main() {
6-
let x: Box<dyn Any> = Box::new(());
6+
let mut x: Box<dyn Any> = Box::new(());
77
let ref_x = &x;
88

99
f(&x);
@@ -15,12 +15,23 @@ fn main() {
1515
let _: &dyn Any = &x;
1616
//~^ coerce_container_to_any
1717

18+
let _: &dyn Any = &mut x;
19+
//~^ coerce_container_to_any
20+
21+
let _: &mut dyn Any = &mut x;
22+
//~^ coerce_container_to_any
23+
1824
f(&42);
1925
f(&Box::new(()));
2026
f(&Box::new(Box::new(())));
27+
let ref_x = &x;
2128
f(&**ref_x);
2229
f(&*x);
2330
let _: &dyn Any = &*x;
31+
32+
// https://github.com/rust-lang/rust-clippy/issues/15045
33+
#[allow(clippy::needless_borrow)]
34+
(&x).downcast_ref::<()>().unwrap();
2435
}
2536

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

tests/ui/coerce_container_to_any.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,17 @@ error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any`
1919
LL | let _: &dyn Any = &x;
2020
| ^^ help: consider dereferencing: `&*x`
2121

22-
error: aborting due to 3 previous errors
22+
error: coercing `&mut std::boxed::Box<dyn std::any::Any>` to `&dyn Any`
23+
--> tests/ui/coerce_container_to_any.rs:18:23
24+
|
25+
LL | let _: &dyn Any = &mut x;
26+
| ^^^^^^ help: consider dereferencing: `&*x`
27+
28+
error: coercing `&mut std::boxed::Box<dyn std::any::Any>` to `&mut dyn Any`
29+
--> tests/ui/coerce_container_to_any.rs:21:27
30+
|
31+
LL | let _: &mut dyn Any = &mut x;
32+
| ^^^^^^ help: consider dereferencing: `&mut *x`
33+
34+
error: aborting due to 5 previous errors
2335

0 commit comments

Comments
 (0)