Skip to content

Commit 82b2eb1

Browse files
committed
add structured suggestions
1 parent 6a6b4a3 commit 82b2eb1

File tree

4 files changed

+124
-30
lines changed

4 files changed

+124
-30
lines changed

clippy_lints/src/double_parens.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
use clippy_utils::diagnostics::span_lint;
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::{HasSession, snippet_with_applicability};
23
use rustc_ast::ast::{Expr, ExprKind, MethodCall};
4+
use rustc_errors::Applicability;
35
use rustc_lint::{EarlyContext, EarlyLintPass};
46
use rustc_session::declare_lint_pass;
57

@@ -24,7 +26,7 @@ declare_clippy_lint! {
2426
/// Use instead:
2527
/// ```no_run
2628
/// fn simple_no_parens() -> i32 {
27-
/// 0
29+
/// (0)
2830
/// }
2931
///
3032
/// # fn foo(bar: usize) {}
@@ -40,23 +42,51 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]);
4042

4143
impl EarlyLintPass for DoubleParens {
4244
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
43-
let span = match &expr.kind {
44-
ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span,
45+
if expr.span.from_expansion() {
46+
return;
47+
}
48+
49+
match &expr.kind {
50+
// ((..))
51+
// ^^^^^^ expr
52+
// ^^^^ inner
53+
ExprKind::Paren(inner) if matches!(inner.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => {
54+
// suggest removing the outer parens
55+
let mut applicability = Applicability::MachineApplicable;
56+
let sugg = snippet_with_applicability(cx.sess(), inner.span, "_", &mut applicability);
57+
span_lint_and_sugg(
58+
cx,
59+
DOUBLE_PARENS,
60+
expr.span,
61+
"unnecessary parentheses",
62+
"remove them",
63+
sugg.to_string(),
64+
applicability,
65+
);
66+
},
67+
68+
// func((n))
69+
// ^^^^^^^^^ expr
70+
// ^^^ arg
71+
// ^ inner
4572
ExprKind::Call(_, args) | ExprKind::MethodCall(box MethodCall { args, .. })
46-
if let [args] = &**args
47-
&& let ExprKind::Paren(_) = args.kind =>
73+
if let [arg] = &**args
74+
&& let ExprKind::Paren(inner) = &arg.kind =>
4875
{
49-
args.span
76+
// suggest removing the inner parens
77+
let mut applicability = Applicability::MachineApplicable;
78+
let sugg = snippet_with_applicability(cx.sess(), inner.span, "_", &mut applicability);
79+
span_lint_and_sugg(
80+
cx,
81+
DOUBLE_PARENS,
82+
arg.span,
83+
"unnecessary parentheses",
84+
"remove them",
85+
sugg.to_string(),
86+
applicability,
87+
);
5088
},
51-
_ => return,
52-
};
53-
if !expr.span.from_expansion() {
54-
span_lint(
55-
cx,
56-
DOUBLE_PARENS,
57-
span,
58-
"consider removing unnecessary double parentheses",
59-
);
89+
_ => {},
6090
}
6191
}
6292
}

tests/ui/double_parens.fixed

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![warn(clippy::double_parens)]
2+
#![expect(clippy::eq_op)]
3+
#![feature(custom_inner_attributes)]
4+
#![rustfmt::skip]
5+
6+
fn dummy_fn<T>(_: T) {}
7+
8+
struct DummyStruct;
9+
10+
impl DummyStruct {
11+
fn dummy_method<T>(self, _: T) {}
12+
}
13+
14+
fn simple_double_parens() -> i32 {
15+
(0)
16+
//~^ double_parens
17+
}
18+
19+
fn fn_double_parens() {
20+
dummy_fn(0);
21+
//~^ double_parens
22+
}
23+
24+
fn method_double_parens(x: DummyStruct) {
25+
x.dummy_method(0);
26+
//~^ double_parens
27+
}
28+
29+
fn tuple_double_parens() -> (i32, i32) {
30+
(1, 2)
31+
//~^ double_parens
32+
}
33+
34+
#[allow(clippy::unused_unit)]
35+
fn unit_double_parens() {
36+
()
37+
//~^ double_parens
38+
}
39+
40+
fn fn_tuple_ok() {
41+
dummy_fn((1, 2));
42+
}
43+
44+
fn method_tuple_ok(x: DummyStruct) {
45+
x.dummy_method((1, 2));
46+
}
47+
48+
fn fn_unit_ok() {
49+
dummy_fn(());
50+
}
51+
52+
fn method_unit_ok(x: DummyStruct) {
53+
x.dummy_method(());
54+
}
55+
56+
// Issue #3206
57+
fn inside_macro() {
58+
assert_eq!((1, 2), (1, 2), "Error");
59+
assert_eq!((1, 2), (1, 2), "Error");
60+
//~^ double_parens
61+
}
62+
63+
fn main() {}

tests/ui/double_parens.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ fn tuple_double_parens() -> (i32, i32) {
3131
//~^ double_parens
3232
}
3333

34+
#[allow(clippy::unused_unit)]
3435
fn unit_double_parens() {
3536
(())
3637
//~^ double_parens

tests/ui/double_parens.stderr

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
1-
error: consider removing unnecessary double parentheses
1+
error: unnecessary parentheses
22
--> tests/ui/double_parens.rs:15:5
33
|
44
LL | ((0))
5-
| ^^^^^
5+
| ^^^^^ help: remove them: `(0)`
66
|
77
= note: `-D clippy::double-parens` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::double_parens)]`
99

10-
error: consider removing unnecessary double parentheses
10+
error: unnecessary parentheses
1111
--> tests/ui/double_parens.rs:20:14
1212
|
1313
LL | dummy_fn((0));
14-
| ^^^
14+
| ^^^ help: remove them: `0`
1515

16-
error: consider removing unnecessary double parentheses
16+
error: unnecessary parentheses
1717
--> tests/ui/double_parens.rs:25:20
1818
|
1919
LL | x.dummy_method((0));
20-
| ^^^
20+
| ^^^ help: remove them: `0`
2121

22-
error: consider removing unnecessary double parentheses
22+
error: unnecessary parentheses
2323
--> tests/ui/double_parens.rs:30:5
2424
|
2525
LL | ((1, 2))
26-
| ^^^^^^^^
26+
| ^^^^^^^^ help: remove them: `(1, 2)`
2727

28-
error: consider removing unnecessary double parentheses
29-
--> tests/ui/double_parens.rs:35:5
28+
error: unnecessary parentheses
29+
--> tests/ui/double_parens.rs:36:5
3030
|
3131
LL | (())
32-
| ^^^^
32+
| ^^^^ help: remove them: `()`
3333

34-
error: consider removing unnecessary double parentheses
35-
--> tests/ui/double_parens.rs:58:16
34+
error: unnecessary parentheses
35+
--> tests/ui/double_parens.rs:59:16
3636
|
3737
LL | assert_eq!(((1, 2)), (1, 2), "Error");
38-
| ^^^^^^^^
38+
| ^^^^^^^^ help: remove them: `(1, 2)`
3939

4040
error: aborting due to 6 previous errors
4141

0 commit comments

Comments
 (0)