diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.register_all.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.register_lints.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.register_style.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/needless_parens_on_range_literals.rs | 87 | ||||
| -rw-r--r-- | tests/ui/almost_complete_letter_range.fixed | 1 | ||||
| -rw-r--r-- | tests/ui/almost_complete_letter_range.rs | 1 | ||||
| -rw-r--r-- | tests/ui/almost_complete_letter_range.stderr | 24 | ||||
| -rw-r--r-- | tests/ui/needless_parens_on_range_literals.fixed | 14 | ||||
| -rw-r--r-- | tests/ui/needless_parens_on_range_literals.rs | 14 | ||||
| -rw-r--r-- | tests/ui/needless_parens_on_range_literals.stderr | 40 |
12 files changed, 175 insertions, 12 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef338b819d..462e56892fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3605,6 +3605,7 @@ Released 2018-09-13 [`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take +[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index d4ec046d0bb..4691f957cb4 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -242,6 +242,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(needless_bool::NEEDLESS_BOOL), LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), LintId::of(needless_late_init::NEEDLESS_LATE_INIT), + LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS), LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), LintId::of(needless_update::NEEDLESS_UPDATE), LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index b927ba3b17c..efb073af6b6 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -408,6 +408,7 @@ store.register_lints(&[ needless_continue::NEEDLESS_CONTINUE, needless_for_each::NEEDLESS_FOR_EACH, needless_late_init::NEEDLESS_LATE_INIT, + needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS, needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, needless_question_mark::NEEDLESS_QUESTION_MARK, needless_update::NEEDLESS_UPDATE, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 35575351784..b6992ae0ad2 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -91,6 +91,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_late_init::NEEDLESS_LATE_INIT), + LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS), LintId::of(neg_multiply::NEG_MULTIPLY), LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ee0416fc0ff..a0a6bab407c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -315,6 +315,7 @@ mod needless_borrowed_ref; mod needless_continue; mod needless_for_each; mod needless_late_init; +mod needless_parens_on_range_literals; mod needless_pass_by_value; mod needless_question_mark; mod needless_update; @@ -746,6 +747,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf)); store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); + store.register_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue)); store.register_early_pass(|| Box::new(redundant_else::RedundantElse)); store.register_late_pass(|| Box::new(create_dir::CreateDir)); diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs new file mode 100644 index 00000000000..6e54b243c03 --- /dev/null +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -0,0 +1,87 @@ +use clippy_utils::{ + diagnostics::span_lint_and_then, + higher, + source::{snippet, snippet_with_applicability}, +}; + +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; + +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// The lint checks for parenthesis on literals in range statements that are + /// superfluous. + /// + /// ### Why is this bad? + /// Having superfluous parenthesis makes the code less readable + /// overhead when reading. + /// + /// ### Example + /// + /// ```rust + /// for i in (0)..10 { + /// println!("{i}"); + /// } + /// ``` + /// + /// Use instead: + /// + /// ```rust + /// for i in 0..10 { + /// println!("{i}"); + /// } + /// ``` + #[clippy::version = "1.63.0"] + pub NEEDLESS_PARENS_ON_RANGE_LITERALS, + style, + "needless parenthesis on range literals can be removed" +} + +declare_lint_pass!(NeedlessParensOnRangeLiterals => [NEEDLESS_PARENS_ON_RANGE_LITERALS]); + +fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool { + snippet.starts_with('(') && snippet.ends_with(')') +} + +fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { + if is_start && + let ExprKind::Lit(ref literal) = e.kind && + let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node + { + // don't check floating point literals on the start expression of a range + return; + } + if_chain! { + if let ExprKind::Lit(ref literal) = e.kind; + // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ + if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo); + // inspect the source code of the expression for parenthesis + if snippet_enclosed_in_parenthesis(&snippet(cx, e.span, "")); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERALS, e.span, + "needless parenthesis on range literals can be removed", + |diag| { + let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability); + diag.span_suggestion(e.span, "try", suggestion, applicability); + }); + } + } +} + +impl<'tcx> LateLintPass<'tcx> for NeedlessParensOnRangeLiterals { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let Some(higher::Range { start, end, .. }) = higher::Range::hir(expr) { + if let Some(start) = start { + check_for_parens(cx, start, true); + } + if let Some(end) = end { + check_for_parens(cx, end, false); + } + } + } +} diff --git a/tests/ui/almost_complete_letter_range.fixed b/tests/ui/almost_complete_letter_range.fixed index 39f8f0c2949..e69b40f35f4 100644 --- a/tests/ui/almost_complete_letter_range.fixed +++ b/tests/ui/almost_complete_letter_range.fixed @@ -6,6 +6,7 @@ #![feature(stmt_expr_attributes)] #![warn(clippy::almost_complete_letter_range)] #![allow(ellipsis_inclusive_range_patterns)] +#![allow(clippy::needless_parens_on_range_literals)] macro_rules! a { () => { diff --git a/tests/ui/almost_complete_letter_range.rs b/tests/ui/almost_complete_letter_range.rs index 3dc02199257..f2240981d45 100644 --- a/tests/ui/almost_complete_letter_range.rs +++ b/tests/ui/almost_complete_letter_range.rs @@ -6,6 +6,7 @@ #![feature(stmt_expr_attributes)] #![warn(clippy::almost_complete_letter_range)] #![allow(ellipsis_inclusive_range_patterns)] +#![allow(clippy::needless_parens_on_range_literals)] macro_rules! a { () => { diff --git a/tests/ui/almost_complete_letter_range.stderr b/tests/ui/almost_complete_letter_range.stderr index 74980ec1a92..5b5dc40ee54 100644 --- a/tests/ui/almost_complete_letter_range.stderr +++ b/tests/ui/almost_complete_letter_range.stderr @@ -1,5 +1,5 @@ error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:19:17 + --> $DIR/almost_complete_letter_range.rs:20:17 | LL | let _ = ('a') ..'z'; | ^^^^^^--^^^ @@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z'; = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:20:17 + --> $DIR/almost_complete_letter_range.rs:21:17 | LL | let _ = 'A' .. ('Z'); | ^^^^--^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z'); | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:26:13 + --> $DIR/almost_complete_letter_range.rs:27:13 | LL | let _ = (b'a')..(b'z'); | ^^^^^^--^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = (b'a')..(b'z'); | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:27:13 + --> $DIR/almost_complete_letter_range.rs:28:13 | LL | let _ = b'A'..b'Z'; | ^^^^--^^^^ @@ -33,7 +33,7 @@ LL | let _ = b'A'..b'Z'; | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:32:13 + --> $DIR/almost_complete_letter_range.rs:33:13 | LL | let _ = a!()..'z'; | ^^^^--^^^ @@ -41,7 +41,7 @@ LL | let _ = a!()..'z'; | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:35:9 + --> $DIR/almost_complete_letter_range.rs:36:9 | LL | b'a'..b'z' if true => 1, | ^^^^--^^^^ @@ -49,7 +49,7 @@ LL | b'a'..b'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:36:9 + --> $DIR/almost_complete_letter_range.rs:37:9 | LL | b'A'..b'Z' if true => 2, | ^^^^--^^^^ @@ -57,7 +57,7 @@ LL | b'A'..b'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:43:9 + --> $DIR/almost_complete_letter_range.rs:44:9 | LL | 'a'..'z' if true => 1, | ^^^--^^^ @@ -65,7 +65,7 @@ LL | 'a'..'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:44:9 + --> $DIR/almost_complete_letter_range.rs:45:9 | LL | 'A'..'Z' if true => 2, | ^^^--^^^ @@ -73,7 +73,7 @@ LL | 'A'..'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:54:9 + --> $DIR/almost_complete_letter_range.rs:55:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -81,7 +81,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `...` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:61:13 + --> $DIR/almost_complete_letter_range.rs:62:13 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -89,7 +89,7 @@ LL | let _ = 'a'..'z'; | help: use an inclusive range: `..=` error: almost complete ascii letter range - --> $DIR/almost_complete_letter_range.rs:63:9 + --> $DIR/almost_complete_letter_range.rs:64:9 | LL | 'a'..'z' => 1, | ^^^--^^^ diff --git a/tests/ui/needless_parens_on_range_literals.fixed b/tests/ui/needless_parens_on_range_literals.fixed new file mode 100644 index 00000000000..1bd75c806bc --- /dev/null +++ b/tests/ui/needless_parens_on_range_literals.fixed @@ -0,0 +1,14 @@ +// run-rustfix +// edition:2018 + +#![warn(clippy::needless_parens_on_range_literals)] +#![allow(clippy::almost_complete_letter_range)] + +fn main() { + let _ = 'a'..='z'; + let _ = 'a'..'z'; + let _ = (1.)..2.; + let _ = (1.)..2.; + let _ = 'a'..; + let _ = ..'z'; +} diff --git a/tests/ui/needless_parens_on_range_literals.rs b/tests/ui/needless_parens_on_range_literals.rs new file mode 100644 index 00000000000..7abb8a1adc1 --- /dev/null +++ b/tests/ui/needless_parens_on_range_literals.rs @@ -0,0 +1,14 @@ +// run-rustfix +// edition:2018 + +#![warn(clippy::needless_parens_on_range_literals)] +#![allow(clippy::almost_complete_letter_range)] + +fn main() { + let _ = ('a')..=('z'); + let _ = 'a'..('z'); + let _ = (1.)..2.; + let _ = (1.)..(2.); + let _ = ('a')..; + let _ = ..('z'); +} diff --git a/tests/ui/needless_parens_on_range_literals.stderr b/tests/ui/needless_parens_on_range_literals.stderr new file mode 100644 index 00000000000..505f7ac916d --- /dev/null +++ b/tests/ui/needless_parens_on_range_literals.stderr @@ -0,0 +1,40 @@ +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` + +error: needless parenthesis on range literals can be removed + --> $DIR/needless_parens_on_range_literals.rs:8:21 + | +LL | let _ = ('a')..=('z'); + | ^^^^^ help: try: `'z'` + +error: needless parenthesis on range literals can be removed + --> $DIR/needless_parens_on_range_literals.rs:9:18 + | +LL | let _ = 'a'..('z'); + | ^^^^^ help: try: `'z'` + +error: needless parenthesis on range literals can be removed + --> $DIR/needless_parens_on_range_literals.rs:11:19 + | +LL | let _ = (1.)..(2.); + | ^^^^ help: try: `2.` + +error: needless parenthesis on range literals can be removed + --> $DIR/needless_parens_on_range_literals.rs:12:13 + | +LL | let _ = ('a')..; + | ^^^^^ help: try: `'a'` + +error: needless parenthesis on range literals can be removed + --> $DIR/needless_parens_on_range_literals.rs:13:15 + | +LL | let _ = ..('z'); + | ^^^^^ help: try: `'z'` + +error: aborting due to 6 previous errors + |
