Skip to content

Commit 0f6e50f

Browse files
committed
Auto merge of #8933 - DennisOSRM:needless_braces_range_literal, r=dswij
Add new lint [`needless_parens_on_range_literals`] changelog: Adds a new lint [`needless_parens_on_range_literals`] to warn on needless braces on literals in a range statement For example, the lint would catch ```log error: needless parenthesis on range literals can be removed --> $DIR/needless_parens_on_range_literals.rs:8:13 | LL | let _ = ('a')..=('z'); | ^^^^^ help: try: `'a'` | = note: `-D clippy::needless-parens-on-range-literals` implied by `-D warnings` ```
2 parents 3e77162 + 61d7dd2 commit 0f6e50f

12 files changed

+175
-12
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3605,6 +3605,7 @@ Released 2018-09-13
36053605
[`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match
36063606
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
36073607
[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take
3608+
[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals
36083609
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
36093610
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
36103611
[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop

clippy_lints/src/lib.register_all.rs

+1
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
242242
LintId::of(needless_bool::NEEDLESS_BOOL),
243243
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
244244
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
245+
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
245246
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
246247
LintId::of(needless_update::NEEDLESS_UPDATE),
247248
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ store.register_lints(&[
408408
needless_continue::NEEDLESS_CONTINUE,
409409
needless_for_each::NEEDLESS_FOR_EACH,
410410
needless_late_init::NEEDLESS_LATE_INIT,
411+
needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS,
411412
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
412413
needless_question_mark::NEEDLESS_QUESTION_MARK,
413414
needless_update::NEEDLESS_UPDATE,

clippy_lints/src/lib.register_style.rs

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
9191
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
9292
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
9393
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
94+
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
9495
LintId::of(neg_multiply::NEG_MULTIPLY),
9596
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
9697
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ mod needless_borrowed_ref;
315315
mod needless_continue;
316316
mod needless_for_each;
317317
mod needless_late_init;
318+
mod needless_parens_on_range_literals;
318319
mod needless_pass_by_value;
319320
mod needless_question_mark;
320321
mod needless_update;
@@ -746,6 +747,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
746747
store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
747748
store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
748749
store.register_early_pass(|| Box::new(precedence::Precedence));
750+
store.register_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
749751
store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
750752
store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
751753
store.register_late_pass(|| Box::new(create_dir::CreateDir));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use clippy_utils::{
2+
diagnostics::span_lint_and_then,
3+
higher,
4+
source::{snippet, snippet_with_applicability},
5+
};
6+
7+
use rustc_ast::ast;
8+
use rustc_errors::Applicability;
9+
use rustc_hir::{Expr, ExprKind};
10+
11+
use rustc_lint::{LateContext, LateLintPass};
12+
use rustc_session::{declare_lint_pass, declare_tool_lint};
13+
14+
declare_clippy_lint! {
15+
/// ### What it does
16+
/// The lint checks for parenthesis on literals in range statements that are
17+
/// superfluous.
18+
///
19+
/// ### Why is this bad?
20+
/// Having superfluous parenthesis makes the code less readable
21+
/// overhead when reading.
22+
///
23+
/// ### Example
24+
///
25+
/// ```rust
26+
/// for i in (0)..10 {
27+
/// println!("{i}");
28+
/// }
29+
/// ```
30+
///
31+
/// Use instead:
32+
///
33+
/// ```rust
34+
/// for i in 0..10 {
35+
/// println!("{i}");
36+
/// }
37+
/// ```
38+
#[clippy::version = "1.63.0"]
39+
pub NEEDLESS_PARENS_ON_RANGE_LITERALS,
40+
style,
41+
"needless parenthesis on range literals can be removed"
42+
}
43+
44+
declare_lint_pass!(NeedlessParensOnRangeLiterals => [NEEDLESS_PARENS_ON_RANGE_LITERALS]);
45+
46+
fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
47+
snippet.starts_with('(') && snippet.ends_with(')')
48+
}
49+
50+
fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
51+
if is_start &&
52+
let ExprKind::Lit(ref literal) = e.kind &&
53+
let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
54+
{
55+
// don't check floating point literals on the start expression of a range
56+
return;
57+
}
58+
if_chain! {
59+
if let ExprKind::Lit(ref literal) = e.kind;
60+
// the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
61+
if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
62+
// inspect the source code of the expression for parenthesis
63+
if snippet_enclosed_in_parenthesis(&snippet(cx, e.span, ""));
64+
then {
65+
let mut applicability = Applicability::MachineApplicable;
66+
span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERALS, e.span,
67+
"needless parenthesis on range literals can be removed",
68+
|diag| {
69+
let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability);
70+
diag.span_suggestion(e.span, "try", suggestion, applicability);
71+
});
72+
}
73+
}
74+
}
75+
76+
impl<'tcx> LateLintPass<'tcx> for NeedlessParensOnRangeLiterals {
77+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
78+
if let Some(higher::Range { start, end, .. }) = higher::Range::hir(expr) {
79+
if let Some(start) = start {
80+
check_for_parens(cx, start, true);
81+
}
82+
if let Some(end) = end {
83+
check_for_parens(cx, end, false);
84+
}
85+
}
86+
}
87+
}

tests/ui/almost_complete_letter_range.fixed

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(stmt_expr_attributes)]
77
#![warn(clippy::almost_complete_letter_range)]
88
#![allow(ellipsis_inclusive_range_patterns)]
9+
#![allow(clippy::needless_parens_on_range_literals)]
910

1011
macro_rules! a {
1112
() => {

tests/ui/almost_complete_letter_range.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(stmt_expr_attributes)]
77
#![warn(clippy::almost_complete_letter_range)]
88
#![allow(ellipsis_inclusive_range_patterns)]
9+
#![allow(clippy::needless_parens_on_range_literals)]
910

1011
macro_rules! a {
1112
() => {

tests/ui/almost_complete_letter_range.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: almost complete ascii letter range
2-
--> $DIR/almost_complete_letter_range.rs:19:17
2+
--> $DIR/almost_complete_letter_range.rs:20:17
33
|
44
LL | let _ = ('a') ..'z';
55
| ^^^^^^--^^^
@@ -9,87 +9,87 @@ LL | let _ = ('a') ..'z';
99
= note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
1010

1111
error: almost complete ascii letter range
12-
--> $DIR/almost_complete_letter_range.rs:20:17
12+
--> $DIR/almost_complete_letter_range.rs:21:17
1313
|
1414
LL | let _ = 'A' .. ('Z');
1515
| ^^^^--^^^^^^
1616
| |
1717
| help: use an inclusive range: `..=`
1818

1919
error: almost complete ascii letter range
20-
--> $DIR/almost_complete_letter_range.rs:26:13
20+
--> $DIR/almost_complete_letter_range.rs:27:13
2121
|
2222
LL | let _ = (b'a')..(b'z');
2323
| ^^^^^^--^^^^^^
2424
| |
2525
| help: use an inclusive range: `..=`
2626

2727
error: almost complete ascii letter range
28-
--> $DIR/almost_complete_letter_range.rs:27:13
28+
--> $DIR/almost_complete_letter_range.rs:28:13
2929
|
3030
LL | let _ = b'A'..b'Z';
3131
| ^^^^--^^^^
3232
| |
3333
| help: use an inclusive range: `..=`
3434

3535
error: almost complete ascii letter range
36-
--> $DIR/almost_complete_letter_range.rs:32:13
36+
--> $DIR/almost_complete_letter_range.rs:33:13
3737
|
3838
LL | let _ = a!()..'z';
3939
| ^^^^--^^^
4040
| |
4141
| help: use an inclusive range: `..=`
4242

4343
error: almost complete ascii letter range
44-
--> $DIR/almost_complete_letter_range.rs:35:9
44+
--> $DIR/almost_complete_letter_range.rs:36:9
4545
|
4646
LL | b'a'..b'z' if true => 1,
4747
| ^^^^--^^^^
4848
| |
4949
| help: use an inclusive range: `..=`
5050

5151
error: almost complete ascii letter range
52-
--> $DIR/almost_complete_letter_range.rs:36:9
52+
--> $DIR/almost_complete_letter_range.rs:37:9
5353
|
5454
LL | b'A'..b'Z' if true => 2,
5555
| ^^^^--^^^^
5656
| |
5757
| help: use an inclusive range: `..=`
5858

5959
error: almost complete ascii letter range
60-
--> $DIR/almost_complete_letter_range.rs:43:9
60+
--> $DIR/almost_complete_letter_range.rs:44:9
6161
|
6262
LL | 'a'..'z' if true => 1,
6363
| ^^^--^^^
6464
| |
6565
| help: use an inclusive range: `..=`
6666

6767
error: almost complete ascii letter range
68-
--> $DIR/almost_complete_letter_range.rs:44:9
68+
--> $DIR/almost_complete_letter_range.rs:45:9
6969
|
7070
LL | 'A'..'Z' if true => 2,
7171
| ^^^--^^^
7272
| |
7373
| help: use an inclusive range: `..=`
7474

7575
error: almost complete ascii letter range
76-
--> $DIR/almost_complete_letter_range.rs:54:9
76+
--> $DIR/almost_complete_letter_range.rs:55:9
7777
|
7878
LL | 'a'..'z' => 1,
7979
| ^^^--^^^
8080
| |
8181
| help: use an inclusive range: `...`
8282

8383
error: almost complete ascii letter range
84-
--> $DIR/almost_complete_letter_range.rs:61:13
84+
--> $DIR/almost_complete_letter_range.rs:62:13
8585
|
8686
LL | let _ = 'a'..'z';
8787
| ^^^--^^^
8888
| |
8989
| help: use an inclusive range: `..=`
9090

9191
error: almost complete ascii letter range
92-
--> $DIR/almost_complete_letter_range.rs:63:9
92+
--> $DIR/almost_complete_letter_range.rs:64:9
9393
|
9494
LL | 'a'..'z' => 1,
9595
| ^^^--^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
// edition:2018
3+
4+
#![warn(clippy::needless_parens_on_range_literals)]
5+
#![allow(clippy::almost_complete_letter_range)]
6+
7+
fn main() {
8+
let _ = 'a'..='z';
9+
let _ = 'a'..'z';
10+
let _ = (1.)..2.;
11+
let _ = (1.)..2.;
12+
let _ = 'a'..;
13+
let _ = ..'z';
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
// edition:2018
3+
4+
#![warn(clippy::needless_parens_on_range_literals)]
5+
#![allow(clippy::almost_complete_letter_range)]
6+
7+
fn main() {
8+
let _ = ('a')..=('z');
9+
let _ = 'a'..('z');
10+
let _ = (1.)..2.;
11+
let _ = (1.)..(2.);
12+
let _ = ('a')..;
13+
let _ = ..('z');
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: needless parenthesis on range literals can be removed
2+
--> $DIR/needless_parens_on_range_literals.rs:8:13
3+
|
4+
LL | let _ = ('a')..=('z');
5+
| ^^^^^ help: try: `'a'`
6+
|
7+
= note: `-D clippy::needless-parens-on-range-literals` implied by `-D warnings`
8+
9+
error: needless parenthesis on range literals can be removed
10+
--> $DIR/needless_parens_on_range_literals.rs:8:21
11+
|
12+
LL | let _ = ('a')..=('z');
13+
| ^^^^^ help: try: `'z'`
14+
15+
error: needless parenthesis on range literals can be removed
16+
--> $DIR/needless_parens_on_range_literals.rs:9:18
17+
|
18+
LL | let _ = 'a'..('z');
19+
| ^^^^^ help: try: `'z'`
20+
21+
error: needless parenthesis on range literals can be removed
22+
--> $DIR/needless_parens_on_range_literals.rs:11:19
23+
|
24+
LL | let _ = (1.)..(2.);
25+
| ^^^^ help: try: `2.`
26+
27+
error: needless parenthesis on range literals can be removed
28+
--> $DIR/needless_parens_on_range_literals.rs:12:13
29+
|
30+
LL | let _ = ('a')..;
31+
| ^^^^^ help: try: `'a'`
32+
33+
error: needless parenthesis on range literals can be removed
34+
--> $DIR/needless_parens_on_range_literals.rs:13:15
35+
|
36+
LL | let _ = ..('z');
37+
| ^^^^^ help: try: `'z'`
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)