diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f97430561..19e1247d6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -747,7 +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_early_pass(|| Box::new(needless_parens_on_range_literal::NeedlessParensOnRangeLiteral)); + store.register_late_pass(|| Box::new(needless_parens_on_range_literal::NeedlessParensOnRangeLiteral)); 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_literal.rs b/clippy_lints/src/needless_parens_on_range_literal.rs index 50a393311..81c7f7127 100644 --- a/clippy_lints/src/needless_parens_on_range_literal.rs +++ b/clippy_lints/src/needless_parens_on_range_literal.rs @@ -17,10 +17,17 @@ //! ``` //! -use clippy_utils::{diagnostics::span_lint_and_then, source::snippet_opt}; -use rustc_ast::ast::{Expr, ExprKind}; +use clippy_utils::{ + diagnostics::span_lint_and_then, + higher, + source::{snippet, snippet_opt}, +}; + +use rustc_ast::ast; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{Expr, ExprKind}; + +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -40,27 +47,47 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessParensOnRangeLiteral => [NEEDLESS_PARENS_ON_RANGE_LITERAL]); -fn check_for_parens(cx: &EarlyContext<'_>, e: &Expr) { - if_chain! { - if let ExprKind::Paren(ref start_statement) = &e.kind; - if let ExprKind::Lit(ref literal) = start_statement.kind; - then { - span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERAL, e.span, - "needless parenthesis on range literal can be removed", - |diag| { - if let Some(suggestion) = snippet_opt(cx, literal.span) { - diag.span_suggestion(e.span, "try", suggestion, Applicability::MachineApplicable); - } - }); - } - } +fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool { + snippet.starts_with('(') && snippet.ends_with(')') } -impl EarlyLintPass for NeedlessParensOnRangeLiteral { - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if let ExprKind::Range(Some(start), Some(end), _) = &e.kind { - check_for_parens(cx, start); - check_for_parens(cx, end); +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 paranthese surround the literal is that 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 { + span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERAL, e.span, + "needless parenthesis on range literal can be removed", + |diag| { + if let Some(suggestion) = snippet_opt(cx, literal.span) { + diag.span_suggestion(e.span, "try", suggestion, Applicability::MachineApplicable); + } + }); + } + } +} + +impl<'tcx> LateLintPass<'tcx> for NeedlessParensOnRangeLiteral { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + // if let higher::Range { start, end, limits } = &e.kind { + if let Some(higher::Range { + start: Some(start), + end: Some(end), + .. + }) = higher::Range::hir(expr) + { + check_for_parens(cx, start, true); + check_for_parens(cx, end, false); } } } diff --git a/tests/ui/needless_parens_on_range_literal.fixed b/tests/ui/needless_parens_on_range_literal.fixed index ba903fd68..7b1d09909 100644 --- a/tests/ui/needless_parens_on_range_literal.fixed +++ b/tests/ui/needless_parens_on_range_literal.fixed @@ -6,4 +6,7 @@ fn main() { let _ = 'a'..='z'; + let _ = 'a'..='z'; + let _ = (1.)..2.; + let _ = (1.)..2.; } diff --git a/tests/ui/needless_parens_on_range_literal.rs b/tests/ui/needless_parens_on_range_literal.rs index 7fddd6bf7..306498c0f 100644 --- a/tests/ui/needless_parens_on_range_literal.rs +++ b/tests/ui/needless_parens_on_range_literal.rs @@ -6,4 +6,7 @@ fn main() { let _ = ('a')..=('z'); + let _ = 'a'..='z'; + let _ = (1.)..2.; + let _ = (1.)..(2.); } diff --git a/tests/ui/needless_parens_on_range_literal.stderr b/tests/ui/needless_parens_on_range_literal.stderr index f9655e894..3a646c6b2 100644 --- a/tests/ui/needless_parens_on_range_literal.stderr +++ b/tests/ui/needless_parens_on_range_literal.stderr @@ -12,5 +12,11 @@ error: needless parenthesis on range literal can be removed LL | let _ = ('a')..=('z'); | ^^^^^ help: try: `'z'` -error: aborting due to 2 previous errors +error: needless parenthesis on range literal can be removed + --> $DIR/needless_parens_on_range_literal.rs:11:19 + | +LL | let _ = (1.)..(2.); + | ^^^^ help: try: `2.` + +error: aborting due to 3 previous errors