Skip to content

Commit 9950e08

Browse files
committed
Simple coerce_any_ref_to_any
1 parent 40bead0 commit 9950e08

7 files changed

+132
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5685,6 +5685,7 @@ Released 2018-09-13
56855685
[`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
56865686
[`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
56875687
[`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
5688+
[`coerce_any_ref_to_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#coerce_any_ref_to_any
56885689
[`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
56895690
[`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
56905691
[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::sym;
3+
use rustc_hir::{Expr, LangItem};
4+
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_middle::ty::{self, ExistentialPredicate, Ty};
6+
use rustc_session::declare_lint_pass;
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
///
11+
/// ### Why is this bad?
12+
///
13+
/// ### Example
14+
/// ```no_run
15+
/// // example code where clippy issues a warning
16+
/// ```
17+
/// Use instead:
18+
/// ```no_run
19+
/// // example code which does not raise clippy warning
20+
/// ```
21+
#[clippy::version = "1.88.0"]
22+
pub COERCE_ANY_REF_TO_ANY,
23+
nursery,
24+
"default lint description"
25+
}
26+
declare_lint_pass!(CoerceAnyRefToAny => [COERCE_ANY_REF_TO_ANY]);
27+
28+
impl<'tcx> LateLintPass<'tcx> for CoerceAnyRefToAny {
29+
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
30+
{
31+
let coerced_ty = cx.typeck_results().expr_ty_adjusted(e);
32+
33+
let ty::Ref(_, coerced_ref_ty, _) = *coerced_ty.kind() else {
34+
return;
35+
};
36+
if !is_dyn_any(cx, coerced_ref_ty) {
37+
return;
38+
}
39+
}
40+
41+
let expr_ty = cx.typeck_results().expr_ty(e);
42+
let ty::Ref(_, expr_ref_ty, _) = expr_ty.kind() else {
43+
return;
44+
};
45+
let ty::Adt(adt, ty_params) = expr_ref_ty.kind() else {
46+
return;
47+
};
48+
if !cx.tcx.is_lang_item(adt.did(), LangItem::OwnedBox) {
49+
return;
50+
}
51+
if !is_dyn_any(cx, ty_params.first().unwrap().as_type().unwrap()) {
52+
return;
53+
}
54+
55+
span_lint(
56+
cx,
57+
COERCE_ANY_REF_TO_ANY,
58+
e.span,
59+
"coercing &Box<dyn Any> to &dyn Any rather than dereferencing the Box",
60+
);
61+
}
62+
}
63+
64+
fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
65+
let ty::Dynamic(traits, ..) = ty.kind() else {
66+
return false;
67+
};
68+
if traits.iter().all(|binder| {
69+
let Some(predicate) = binder.no_bound_vars() else {
70+
return false;
71+
};
72+
let ExistentialPredicate::Trait(t) = predicate else {
73+
return false;
74+
};
75+
!cx.tcx.is_diagnostic_item(sym::Any, t.def_id)
76+
}) {
77+
return false;
78+
}
79+
true
80+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
7777
crate::cfg_not_test::CFG_NOT_TEST_INFO,
7878
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
7979
crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO,
80+
crate::coerce_any_ref_to_any::COERCE_ANY_REF_TO_ANY_INFO,
8081
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
8182
crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
8283
crate::collapsible_if::COLLAPSIBLE_IF_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ mod casts;
9595
mod cfg_not_test;
9696
mod checked_conversions;
9797
mod cloned_ref_to_slice_refs;
98+
mod coerce_any_ref_to_any;
9899
mod cognitive_complexity;
99100
mod collapsible_if;
100101
mod collection_is_never_read;
@@ -944,5 +945,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
944945
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
945946
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
946947
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
948+
store.register_late_pass(|_| Box::new(coerce_any_ref_to_any::CoerceAnyRefToAny));
947949
// add lints here, do not remove this comment, it's used in `new_lint`
948950
}

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
# begin autogenerated nightly
33
channel = "nightly-2025-05-01"
44
# end autogenerated nightly
5-
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
5+
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt", "rust-analyzer"]
66
profile = "minimal"

tests/ui/coerce_any_ref_to_any.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![warn(clippy::coerce_any_ref_to_any)]
2+
3+
use std::any::Any;
4+
5+
fn main() {
6+
let x: Box<dyn Any> = Box::new(());
7+
let ref_x = &x;
8+
f(&x);
9+
//~^ coerce_any_ref_to_any
10+
11+
f(ref_x);
12+
//~^ coerce_any_ref_to_any
13+
14+
let _: &dyn Any = &x;
15+
//~^ coerce_any_ref_to_any
16+
17+
f(&42);
18+
f(&Box::new(()));
19+
f(&**ref_x);
20+
f(&*x);
21+
let _: &dyn Any = &*x;
22+
}
23+
24+
fn f(_: &dyn Any) {}

tests/ui/coerce_any_ref_to_any.stderr

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: coercing &Box<dyn Any> to &dyn Any rather than dereferencing the Box
2+
--> tests/ui/coerce_any_ref_to_any.rs:8:7
3+
|
4+
LL | f(&x);
5+
| ^^
6+
|
7+
= note: `-D clippy::coerce-any-ref-to-any` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::coerce_any_ref_to_any)]`
9+
10+
error: coercing &Box<dyn Any> to &dyn Any rather than dereferencing the Box
11+
--> tests/ui/coerce_any_ref_to_any.rs:11:7
12+
|
13+
LL | f(ref_x);
14+
| ^^^^^
15+
16+
error: coercing &Box<dyn Any> to &dyn Any rather than dereferencing the Box
17+
--> tests/ui/coerce_any_ref_to_any.rs:14:23
18+
|
19+
LL | let _: &dyn Any = &x;
20+
| ^^
21+
22+
error: aborting due to 3 previous errors
23+

0 commit comments

Comments
 (0)