From 8b679176fade98d8908f3950506f53b3a5b27910 Mon Sep 17 00:00:00 2001 From: Aaron Power Date: Mon, 28 May 2018 09:29:02 +0200 Subject: [PATCH] Added lint for unnecessary references --- clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/reference.rs | 50 +++++++++++++++++++++++++++++++++ tests/ui/unnecessary_ref.rs | 12 ++++++++ tests/ui/unnecessary_ref.stderr | 14 +++++++++ 4 files changed, 78 insertions(+) create mode 100644 tests/ui/unnecessary_ref.rs create mode 100644 tests/ui/unnecessary_ref.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index efba3b695772..c3e9c4bf86f5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -391,6 +391,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box if_let_redundant_pattern_matching::Pass); reg.register_late_lint_pass(box partialeq_ne_impl::Pass); reg.register_early_lint_pass(box reference::Pass); + reg.register_early_lint_pass(box reference::DerefPass); reg.register_early_lint_pass(box double_parens::DoubleParens); reg.register_late_lint_pass(box unused_io_amount::UnusedIoAmount); reg.register_late_lint_pass(box large_enum_variant::LargeEnumVariant::new(conf.enum_variant_size_threshold)); @@ -812,6 +813,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { precedence::PRECEDENCE, ranges::RANGE_ZIP_WITH_LEN, reference::DEREF_ADDROF, + reference::REF_IN_DEREF, swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::CROSSPOINTER_TRANSMUTE, diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 0d4332b4a7de..765be0bdf36e 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -52,3 +52,53 @@ impl EarlyLintPass for Pass { } } } + +/// **What it does:** Checks for references in expressions that use +/// auto dereference. +/// +/// **Why is this bad?** The reference is a no-op and is automatically +/// dereferenced by the compiler and makes the code less clear. +/// +/// **Example:** +/// ```rust +/// struct Point(u32, u32); +/// let point = Foo(30, 20); +/// let x = (&point).x; +/// ``` +declare_clippy_lint! { + pub REF_IN_DEREF, + complexity, + "Use of reference in auto dereference expression." +} + +pub struct DerefPass; + +impl LintPass for DerefPass { + fn get_lints(&self) -> LintArray { + lint_array!(REF_IN_DEREF) + } +} + +impl EarlyLintPass for DerefPass { + fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) { + if_chain! { + if let ExprKind::Field(ref object, ref field_name) = e.node; + if let ExprKind::Paren(ref parened) = object.node; + if let ExprKind::AddrOf(_, ref inner) = parened.node; + then { + span_lint_and_sugg( + cx, + REF_IN_DEREF, + object.span, + "Creating a reference that is immediately dereferenced.", + "try this", + format!( + "{}.{}", + snippet(cx, inner.span, "_"), + snippet(cx, field_name.span, "_") + ) + ); + } + } + } +} diff --git a/tests/ui/unnecessary_ref.rs b/tests/ui/unnecessary_ref.rs new file mode 100644 index 000000000000..53b970dfa72c --- /dev/null +++ b/tests/ui/unnecessary_ref.rs @@ -0,0 +1,12 @@ +#![feature(tool_attributes)] +#![feature(stmt_expr_attributes)] + +struct Outer { + inner: u32, +} + +#[deny(ref_in_deref)] +fn main() { + let outer = Outer { inner: 0 }; + let inner = (&outer).inner; +} diff --git a/tests/ui/unnecessary_ref.stderr b/tests/ui/unnecessary_ref.stderr new file mode 100644 index 000000000000..ffc65084afa6 --- /dev/null +++ b/tests/ui/unnecessary_ref.stderr @@ -0,0 +1,14 @@ +error: Creating a reference that is immediately dereferenced. + --> $DIR/unnecessary_ref.rs:11:17 + | +11 | let inner = (&outer).inner; + | ^^^^^^^^ help: try this: `outer.inner` + | +note: lint level defined here + --> $DIR/unnecessary_ref.rs:8:8 + | +8 | #[deny(ref_in_deref)] + | ^^^^^^^^^^^^ + +error: aborting due to previous error +