From 7af47fdb7b1ed9a5f9ca1aae304a2492edc64480 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Tue, 21 Jan 2025 21:10:03 -0600 Subject: [PATCH 1/7] Add deref coercions lint and a test --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/deref_coercions.rs | 55 +++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 2 ++ tests/ui/deref_coercions.fixed | 7 ++++ tests/ui/deref_coercions.rs | 7 ++++ tests/ui/deref_coercions.stderr | 11 ++++++ 7 files changed, 84 insertions(+) create mode 100644 clippy_lints/src/deref_coercions.rs create mode 100644 tests/ui/deref_coercions.fixed create mode 100644 tests/ui/deref_coercions.rs create mode 100644 tests/ui/deref_coercions.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index bc42c07224e1..5f9d7072ba85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5515,6 +5515,7 @@ Released 2018-09-13 [`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof [`deref_by_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_by_slicing +[`deref_coercions`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_coercions [`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index da73ef3ced4c..2d087d0485af 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -122,6 +122,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO, crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO, crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO, + crate::deref_coercions::DEREF_COERCIONS_INFO, crate::dereference::EXPLICIT_AUTO_DEREF_INFO, crate::dereference::EXPLICIT_DEREF_METHODS_INFO, crate::dereference::NEEDLESS_BORROW_INFO, diff --git a/clippy_lints/src/deref_coercions.rs b/clippy_lints/src/deref_coercions.rs new file mode 100644 index 000000000000..8364ff16e972 --- /dev/null +++ b/clippy_lints/src/deref_coercions.rs @@ -0,0 +1,55 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions that use deref coercion. + /// + /// ### Why is this bad? + /// Implicit deref coercion could result in confusing behavior when writing unsafe code. + /// + /// ### Example + /// ```no_run + /// let x = &Box::new(true); + /// let y: &bool = x; + /// ``` + /// Use instead: + /// ```no_run + /// let x = &Box::new(true); + /// let y: &bool = x.deref(); + /// ``` + #[clippy::version = "1.86.0"] + pub DEREF_COERCIONS, + pedantic, + "using deref coercion" +} + +declare_lint_pass!(DerefCoercions => [DEREF_COERCIONS]); + +impl LateLintPass<'_> for DerefCoercions { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, expr.span, "..", &mut applicability); + let source = cx.typeck_results().expr_ty(expr).peel_refs(); + for adjustment in cx.typeck_results().expr_adjustments(expr) { + if let Adjust::Deref(_) = adjustment.kind + && adjustment.target.peel_refs() != source + { + span_lint_and_sugg( + cx, + DEREF_COERCIONS, + expr.span, + "implicit deref coercion", + "consider using `deref()`", + format!("{snippet}.deref()"), + applicability, + ); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4b700673d0f8..c36e9f5b2290 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -111,6 +111,7 @@ mod default_constructed_unit_structs; mod default_instead_of_iter_empty; mod default_numeric_fallback; mod default_union_representation; +mod deref_coercions; mod dereference; mod derivable_impls; mod derive; @@ -976,5 +977,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))); + store.register_late_pass(|_| Box::new(deref_coercions::DerefCoercions)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/deref_coercions.fixed b/tests/ui/deref_coercions.fixed new file mode 100644 index 000000000000..8f28de5c4c4f --- /dev/null +++ b/tests/ui/deref_coercions.fixed @@ -0,0 +1,7 @@ +#![warn(clippy::deref_coercions)] +use std::ops::Deref; + +fn main() { + let x = &Box::new(true); + let _: &bool = x.deref(); +} \ No newline at end of file diff --git a/tests/ui/deref_coercions.rs b/tests/ui/deref_coercions.rs new file mode 100644 index 000000000000..93025e25d603 --- /dev/null +++ b/tests/ui/deref_coercions.rs @@ -0,0 +1,7 @@ +#![warn(clippy::deref_coercions)] +use std::ops::Deref; + +fn main() { + let x = &Box::new(true); + let _: &bool = x; +} \ No newline at end of file diff --git a/tests/ui/deref_coercions.stderr b/tests/ui/deref_coercions.stderr new file mode 100644 index 000000000000..eb6eceb7771b --- /dev/null +++ b/tests/ui/deref_coercions.stderr @@ -0,0 +1,11 @@ +error: implicit deref coercion + --> tests/ui/deref_coercions.rs:6:20 + | +LL | let _: &bool = x; + | ^ help: consider using `deref()`: `x.deref()` + | + = note: `-D clippy::deref-coercions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::deref_coercions)]` + +error: aborting due to 1 previous error + From b6fc5fd15b938888f6b35d0524ac84176d3eadf7 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Tue, 21 Jan 2025 21:15:22 -0600 Subject: [PATCH 2/7] cargo dev fmt --- tests/ui/deref_coercions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/deref_coercions.rs b/tests/ui/deref_coercions.rs index 93025e25d603..ebeb53082a30 100644 --- a/tests/ui/deref_coercions.rs +++ b/tests/ui/deref_coercions.rs @@ -4,4 +4,4 @@ use std::ops::Deref; fn main() { let x = &Box::new(true); let _: &bool = x; -} \ No newline at end of file +} From e651b848d3a9a9380a008f8f11ef4e5e14a8f1d3 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Wed, 22 Jan 2025 10:03:18 -0600 Subject: [PATCH 3/7] Change lint group to Restriction --- clippy_lints/src/deref_coercions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/deref_coercions.rs b/clippy_lints/src/deref_coercions.rs index 8364ff16e972..0871f5fa4ab3 100644 --- a/clippy_lints/src/deref_coercions.rs +++ b/clippy_lints/src/deref_coercions.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.86.0"] pub DEREF_COERCIONS, - pedantic, + restriction, "using deref coercion" } From 85d3dbf6b80a0bdd0651d577bbde157ba6fc2435 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Sun, 26 Jan 2025 03:41:28 -0600 Subject: [PATCH 4/7] change to span_lint_and_help --- clippy_lints/src/deref_coercions.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/deref_coercions.rs b/clippy_lints/src/deref_coercions.rs index 0871f5fa4ab3..ff095b8c5faf 100644 --- a/clippy_lints/src/deref_coercions.rs +++ b/clippy_lints/src/deref_coercions.rs @@ -1,6 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use rustc_errors::Applicability; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::Adjust; @@ -33,21 +31,18 @@ declare_lint_pass!(DerefCoercions => [DEREF_COERCIONS]); impl LateLintPass<'_> for DerefCoercions { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, expr.span, "..", &mut applicability); let source = cx.typeck_results().expr_ty(expr).peel_refs(); for adjustment in cx.typeck_results().expr_adjustments(expr) { if let Adjust::Deref(_) = adjustment.kind && adjustment.target.peel_refs() != source { - span_lint_and_sugg( + span_lint_and_help( cx, DEREF_COERCIONS, expr.span, "implicit deref coercion", - "consider using `deref()`", - format!("{snippet}.deref()"), - applicability, + None, + "consider using `deref() or deref_mut()`", ); } } From e889979b1814d9ce15c1b4ad965bfbd21d8db622 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Tue, 28 Jan 2025 07:47:11 -0600 Subject: [PATCH 5/7] TESTNAME=deref_coercions cargo uibless --- tests/ui/deref_coercions.fixed | 7 ------- tests/ui/deref_coercions.stderr | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 tests/ui/deref_coercions.fixed diff --git a/tests/ui/deref_coercions.fixed b/tests/ui/deref_coercions.fixed deleted file mode 100644 index 8f28de5c4c4f..000000000000 --- a/tests/ui/deref_coercions.fixed +++ /dev/null @@ -1,7 +0,0 @@ -#![warn(clippy::deref_coercions)] -use std::ops::Deref; - -fn main() { - let x = &Box::new(true); - let _: &bool = x.deref(); -} \ No newline at end of file diff --git a/tests/ui/deref_coercions.stderr b/tests/ui/deref_coercions.stderr index eb6eceb7771b..be7570823e38 100644 --- a/tests/ui/deref_coercions.stderr +++ b/tests/ui/deref_coercions.stderr @@ -2,8 +2,9 @@ error: implicit deref coercion --> tests/ui/deref_coercions.rs:6:20 | LL | let _: &bool = x; - | ^ help: consider using `deref()`: `x.deref()` + | ^ | + = help: consider using `deref() or deref_mut()` = note: `-D clippy::deref-coercions` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::deref_coercions)]` From de5fe9b6ae5623e960f8730c2a9fb3044a1ad624 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Tue, 28 Jan 2025 07:57:10 -0600 Subject: [PATCH 6/7] Remove wildcard import --- clippy_lints/src/deref_coercions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/deref_coercions.rs b/clippy_lints/src/deref_coercions.rs index ff095b8c5faf..f4b98df313a4 100644 --- a/clippy_lints/src/deref_coercions.rs +++ b/clippy_lints/src/deref_coercions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::*; +use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::Adjust; use rustc_session::declare_lint_pass; From 07ee9f883dcb1ae604c93de1b7886066d9980487 Mon Sep 17 00:00:00 2001 From: yegeunyang Date: Tue, 28 Jan 2025 08:10:45 -0600 Subject: [PATCH 7/7] Edit test code in declare_clippy_lint --- clippy_lints/src/deref_coercions.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/deref_coercions.rs b/clippy_lints/src/deref_coercions.rs index f4b98df313a4..80e5320ffc66 100644 --- a/clippy_lints/src/deref_coercions.rs +++ b/clippy_lints/src/deref_coercions.rs @@ -18,6 +18,7 @@ declare_clippy_lint! { /// ``` /// Use instead: /// ```no_run + /// use std::ops::Deref; /// let x = &Box::new(true); /// let y: &bool = x.deref(); /// ```