]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/redundant_field_names.rs
Don't lint range syntax with var name `start` and `end`
[rust.git] / clippy_lints / src / redundant_field_names.rs
1 use syntax::ast::Name;
2 use rustc::lint::*;
3 use rustc::hir::*;
4 use utils::{match_qpath, match_var, span_lint_and_sugg};
5 use utils::paths;
6
7 /// **What it does:** Checks for fields in struct literals where shorthands
8 /// could be used.
9 /// 
10 /// **Why is this bad?** If the field and variable names are the same,
11 /// the field name is redundant.
12 /// 
13 /// **Known problems:** None.
14 /// 
15 /// **Example:**
16 /// ```rust
17 /// let bar: u8 = 123;
18 /// 
19 /// struct Foo {
20 ///     bar: u8,
21 /// }
22 /// 
23 /// let foo = Foo{ bar: bar }
24 /// ```
25 declare_lint! {
26     pub REDUNDANT_FIELD_NAMES,
27     Warn,
28     "checks for fields in struct literals where shorthands could be used"
29 }
30
31 pub struct RedundantFieldNames;
32
33 impl LintPass for RedundantFieldNames {
34     fn get_lints(&self) -> LintArray {
35         lint_array!(REDUNDANT_FIELD_NAMES)
36     }
37 }
38
39 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantFieldNames {
40     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
41         if let ExprStruct(ref path, ref fields, _) = expr.node {
42             for field in fields {
43                 let name = field.name.node;
44
45                 if is_range_struct_field(path, &name) {
46                     continue;
47                 }
48
49                 if match_var(&field.expr, name) && !field.is_shorthand {
50                     span_lint_and_sugg (
51                         cx,
52                         REDUNDANT_FIELD_NAMES,
53                         field.span,
54                         "redundant field names in struct initialization",
55                         "replace it with",
56                         name.to_string()
57                     );
58                 }
59             }
60         }
61     }
62 }
63
64 /// ```rust
65 /// let start = 0;
66 /// let _ = start..;
67 ///
68 /// let end = 0;
69 /// let _ = ..end;
70 ///
71 /// let _ = start..end;
72 /// ```
73 fn is_range_struct_field(path: &QPath, name: &Name) -> bool {
74     match name.as_str().as_ref() {
75         "start" => {
76             match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE_FROM_STD)
77                 || match_qpath(path, &paths::RANGE_INCLUSIVE_STD)
78         },
79         "end" => {
80             match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE_TO_STD)
81                 || match_qpath(path, &paths::RANGE_INCLUSIVE_STD)
82                 || match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD)
83         },
84         _ => false,
85     }
86 }