diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 4dd8f01ee709..b600e44500d6 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,5 +1,7 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{HasSession, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind}; +use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -40,28 +42,40 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]); impl EarlyLintPass for DoubleParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - let span = match &expr.kind { - ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span, + let (outer_span, inner_span) = match &expr.kind { + ExprKind::Paren(in_paren) => { + let inner_span = match &in_paren.kind { + ExprKind::Paren(inner) => inner.span, + ExprKind::Tup(_) => in_paren.span, + _ => return, + }; + (expr.span, inner_span) + }, ExprKind::Call(_, params) if let [param] = &**params - && let ExprKind::Paren(_) = param.kind => + && let ExprKind::Paren(inner) = ¶m.kind => { - param.span + (param.span, inner.span) }, ExprKind::MethodCall(call) if let [arg] = &*call.args - && let ExprKind::Paren(_) = arg.kind => + && let ExprKind::Paren(inner) = &arg.kind => { - arg.span + (arg.span, inner.span) }, _ => return, }; if !expr.span.from_expansion() { - span_lint( + let mut applicability = Applicability::MachineApplicable; + let sugg = snippet_with_applicability(cx.sess(), inner_span, "_", &mut applicability); + span_lint_and_sugg( cx, DOUBLE_PARENS, - span, - "consider removing unnecessary double parentheses", + outer_span, + "unnecessary parentheses", + "remove them", + sugg.to_string(), + applicability, ); } } diff --git a/tests/ui/double_parens.fixed b/tests/ui/double_parens.fixed new file mode 100644 index 000000000000..dc857c438384 --- /dev/null +++ b/tests/ui/double_parens.fixed @@ -0,0 +1,63 @@ +#![warn(clippy::double_parens)] +#![allow(dead_code, clippy::eq_op)] +#![feature(custom_inner_attributes)] +#![rustfmt::skip] + +fn dummy_fn(_: T) {} + +struct DummyStruct; + +impl DummyStruct { + fn dummy_method(self, _: T) {} +} + +fn simple_double_parens() -> i32 { + 0 + //~^ double_parens +} + +fn fn_double_parens() { + dummy_fn(0); + //~^ double_parens +} + +fn method_double_parens(x: DummyStruct) { + x.dummy_method(0); + //~^ double_parens +} + +fn tuple_double_parens() -> (i32, i32) { + (1, 2) + //~^ double_parens +} + +#[allow(clippy::unused_unit)] +fn unit_double_parens() { + () + //~^ double_parens +} + +fn fn_tuple_ok() { + dummy_fn((1, 2)); +} + +fn method_tuple_ok(x: DummyStruct) { + x.dummy_method((1, 2)); +} + +fn fn_unit_ok() { + dummy_fn(()); +} + +fn method_unit_ok(x: DummyStruct) { + x.dummy_method(()); +} + +// Issue #3206 +fn inside_macro() { + assert_eq!((1, 2), (1, 2), "Error"); + assert_eq!((1, 2), (1, 2), "Error"); + //~^ double_parens +} + +fn main() {} diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 7c976015b4e7..a379ce7ef37e 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -14,32 +14,27 @@ impl DummyStruct { fn simple_double_parens() -> i32 { ((0)) //~^ double_parens - - } fn fn_double_parens() { dummy_fn((0)); //~^ double_parens - } fn method_double_parens(x: DummyStruct) { x.dummy_method((0)); //~^ double_parens - } fn tuple_double_parens() -> (i32, i32) { ((1, 2)) //~^ double_parens - } +#[allow(clippy::unused_unit)] fn unit_double_parens() { (()) //~^ double_parens - } fn fn_tuple_ok() { @@ -63,7 +58,6 @@ fn inside_macro() { assert_eq!((1, 2), (1, 2), "Error"); assert_eq!(((1, 2)), (1, 2), "Error"); //~^ double_parens - } fn main() {} diff --git a/tests/ui/double_parens.stderr b/tests/ui/double_parens.stderr index e119f54949b1..2d26e50abde1 100644 --- a/tests/ui/double_parens.stderr +++ b/tests/ui/double_parens.stderr @@ -1,41 +1,41 @@ -error: consider removing unnecessary double parentheses +error: unnecessary parentheses --> tests/ui/double_parens.rs:15:5 | LL | ((0)) - | ^^^^^ + | ^^^^^ help: remove them: `0` | = note: `-D clippy::double-parens` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::double_parens)]` -error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:22:14 +error: unnecessary parentheses + --> tests/ui/double_parens.rs:20:14 | LL | dummy_fn((0)); - | ^^^ + | ^^^ help: remove them: `0` -error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:28:20 +error: unnecessary parentheses + --> tests/ui/double_parens.rs:25:20 | LL | x.dummy_method((0)); - | ^^^ + | ^^^ help: remove them: `0` -error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:34:5 +error: unnecessary parentheses + --> tests/ui/double_parens.rs:30:5 | LL | ((1, 2)) - | ^^^^^^^^ + | ^^^^^^^^ help: remove them: `(1, 2)` -error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:40:5 +error: unnecessary parentheses + --> tests/ui/double_parens.rs:36:5 | LL | (()) - | ^^^^ + | ^^^^ help: remove them: `()` -error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:64:16 +error: unnecessary parentheses + --> tests/ui/double_parens.rs:59:16 | LL | assert_eq!(((1, 2)), (1, 2), "Error"); - | ^^^^^^^^ + | ^^^^^^^^ help: remove them: `(1, 2)` error: aborting due to 6 previous errors