]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_parens_on_range_literals.rs
Auto merge of #102068 - cjgillot:erased-lifetime-print, r=eholk
[rust.git] / clippy_lints / src / needless_parens_on_range_literals.rs
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 }