1 mod builtin_type_shadow;
2 mod double_neg;
3 mod literal_suffix;
4 mod mixed_case_hex_literals;
5 mod redundant_pattern;
6 mod unneeded_field_pattern;
7 mod unneeded_wildcard_pattern;
8 mod zero_prefixed_literal;
9 
10 use clippy_utils::diagnostics::span_lint;
11 use clippy_utils::source::snippet_opt;
12 use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
13 use rustc_ast::visit::FnKind;
14 use rustc_data_structures::fx::FxHashMap;
15 use rustc_lint::{EarlyContext, EarlyLintPass};
16 use rustc_middle::lint::in_external_macro;
17 use rustc_session::{declare_lint_pass, declare_tool_lint};
18 use rustc_span::source_map::Span;
19 
20 declare_clippy_lint! {
21     /// ### What it does
22     /// Checks for structure field patterns bound to wildcards.
23     ///
24     /// ### Why is this bad?
25     /// Using `..` instead is shorter and leaves the focus on
26     /// the fields that are actually bound.
27     ///
28     /// ### Example
29     /// ```rust
30     /// # struct Foo {
31     /// #     a: i32,
32     /// #     b: i32,
33     /// #     c: i32,
34     /// # }
35     /// let f = Foo { a: 0, b: 0, c: 0 };
36     ///
37     /// // Bad
38     /// match f {
39     ///     Foo { a: _, b: 0, .. } => {},
40     ///     Foo { a: _, b: _, c: _ } => {},
41     /// }
42     ///
43     /// // Good
44     /// match f {
45     ///     Foo { b: 0, .. } => {},
46     ///     Foo { .. } => {},
47     /// }
48     /// ```
49     pub UNNEEDED_FIELD_PATTERN,
50     restriction,
51     "struct fields bound to a wildcard instead of using `..`"
52 }
53 
54 declare_clippy_lint! {
55     /// ### What it does
56     /// Checks for function arguments having the similar names
57     /// differing by an underscore.
58     ///
59     /// ### Why is this bad?
60     /// It affects code readability.
61     ///
62     /// ### Example
63     /// ```rust
64     /// // Bad
65     /// fn foo(a: i32, _a: i32) {}
66     ///
67     /// // Good
68     /// fn bar(a: i32, _b: i32) {}
69     /// ```
70     pub DUPLICATE_UNDERSCORE_ARGUMENT,
71     style,
72     "function arguments having names which only differ by an underscore"
73 }
74 
75 declare_clippy_lint! {
76     /// ### What it does
77     /// Detects expressions of the form `--x`.
78     ///
79     /// ### Why is this bad?
80     /// It can mislead C/C++ programmers to think `x` was
81     /// decremented.
82     ///
83     /// ### Example
84     /// ```rust
85     /// let mut x = 3;
86     /// --x;
87     /// ```
88     pub DOUBLE_NEG,
89     style,
90     "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
91 }
92 
93 declare_clippy_lint! {
94     /// ### What it does
95     /// Warns on hexadecimal literals with mixed-case letter
96     /// digits.
97     ///
98     /// ### Why is this bad?
99     /// It looks confusing.
100     ///
101     /// ### Example
102     /// ```rust
103     /// // Bad
104     /// let y = 0x1a9BAcD;
105     ///
106     /// // Good
107     /// let y = 0x1A9BACD;
108     /// ```
109     pub MIXED_CASE_HEX_LITERALS,
110     style,
111     "hex literals whose letter digits are not consistently upper- or lowercased"
112 }
113 
114 declare_clippy_lint! {
115     /// ### What it does
116     /// Warns if literal suffixes are not separated by an
117     /// underscore.
118     /// To enforce unseparated literal suffix style,
119     /// see the `separated_literal_suffix` lint.
120     ///
121     /// ### Why is this bad?
122     /// Suffix style should be consistent.
123     ///
124     /// ### Example
125     /// ```rust
126     /// // Bad
127     /// let y = 123832i32;
128     ///
129     /// // Good
130     /// let y = 123832_i32;
131     /// ```
132     pub UNSEPARATED_LITERAL_SUFFIX,
133     restriction,
134     "literals whose suffix is not separated by an underscore"
135 }
136 
137 declare_clippy_lint! {
138     /// ### What it does
139     /// Warns if literal suffixes are separated by an underscore.
140     /// To enforce separated literal suffix style,
141     /// see the `unseparated_literal_suffix` lint.
142     ///
143     /// ### Why is this bad?
144     /// Suffix style should be consistent.
145     ///
146     /// ### Example
147     /// ```rust
148     /// // Bad
149     /// let y = 123832_i32;
150     ///
151     /// // Good
152     /// let y = 123832i32;
153     /// ```
154     pub SEPARATED_LITERAL_SUFFIX,
155     restriction,
156     "literals whose suffix is separated by an underscore"
157 }
158 
159 declare_clippy_lint! {
160     /// ### What it does
161     /// Warns if an integral constant literal starts with `0`.
162     ///
163     /// ### Why is this bad?
164     /// In some languages (including the infamous C language
165     /// and most of its
166     /// family), this marks an octal constant. In Rust however, this is a decimal
167     /// constant. This could
168     /// be confusing for both the writer and a reader of the constant.
169     ///
170     /// ### Example
171     ///
172     /// In Rust:
173     /// ```rust
174     /// fn main() {
175     ///     let a = 0123;
176     ///     println!("{}", a);
177     /// }
178     /// ```
179     ///
180     /// prints `123`, while in C:
181     ///
182     /// ```c
183     /// #include <stdio.h>
184     ///
185     /// int main() {
186     ///     int a = 0123;
187     ///     printf("%d\n", a);
188     /// }
189     /// ```
190     ///
191     /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
192     pub ZERO_PREFIXED_LITERAL,
193     complexity,
194     "integer literals starting with `0`"
195 }
196 
197 declare_clippy_lint! {
198     /// ### What it does
199     /// Warns if a generic shadows a built-in type.
200     ///
201     /// ### Why is this bad?
202     /// This gives surprising type errors.
203     ///
204     /// ### Example
205     ///
206     /// ```ignore
207     /// impl<u32> Foo<u32> {
208     ///     fn impl_func(&self) -> u32 {
209     ///         42
210     ///     }
211     /// }
212     /// ```
213     pub BUILTIN_TYPE_SHADOW,
214     style,
215     "shadowing a builtin type"
216 }
217 
218 declare_clippy_lint! {
219     /// ### What it does
220     /// Checks for patterns in the form `name @ _`.
221     ///
222     /// ### Why is this bad?
223     /// It's almost always more readable to just use direct
224     /// bindings.
225     ///
226     /// ### Example
227     /// ```rust
228     /// # let v = Some("abc");
229     ///
230     /// // Bad
231     /// match v {
232     ///     Some(x) => (),
233     ///     y @ _ => (),
234     /// }
235     ///
236     /// // Good
237     /// match v {
238     ///     Some(x) => (),
239     ///     y => (),
240     /// }
241     /// ```
242     pub REDUNDANT_PATTERN,
243     style,
244     "using `name @ _` in a pattern"
245 }
246 
247 declare_clippy_lint! {
248     /// ### What it does
249     /// Checks for tuple patterns with a wildcard
250     /// pattern (`_`) is next to a rest pattern (`..`).
251     ///
252     /// _NOTE_: While `_, ..` means there is at least one element left, `..`
253     /// means there are 0 or more elements left. This can make a difference
254     /// when refactoring, but shouldn't result in errors in the refactored code,
255     /// since the wildcard pattern isn't used anyway.
256     /// ### Why is this bad?
257     /// The wildcard pattern is unneeded as the rest pattern
258     /// can match that element as well.
259     ///
260     /// ### Example
261     /// ```rust
262     /// # struct TupleStruct(u32, u32, u32);
263     /// # let t = TupleStruct(1, 2, 3);
264     /// // Bad
265     /// match t {
266     ///     TupleStruct(0, .., _) => (),
267     ///     _ => (),
268     /// }
269     ///
270     /// // Good
271     /// match t {
272     ///     TupleStruct(0, ..) => (),
273     ///     _ => (),
274     /// }
275     /// ```
276     pub UNNEEDED_WILDCARD_PATTERN,
277     complexity,
278     "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
279 }
280 
281 declare_lint_pass!(MiscEarlyLints => [
282     UNNEEDED_FIELD_PATTERN,
283     DUPLICATE_UNDERSCORE_ARGUMENT,
284     DOUBLE_NEG,
285     MIXED_CASE_HEX_LITERALS,
286     UNSEPARATED_LITERAL_SUFFIX,
287     SEPARATED_LITERAL_SUFFIX,
288     ZERO_PREFIXED_LITERAL,
289     BUILTIN_TYPE_SHADOW,
290     REDUNDANT_PATTERN,
291     UNNEEDED_WILDCARD_PATTERN,
292 ]);
293 
294 impl EarlyLintPass for MiscEarlyLints {
check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics)295     fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
296         for param in &gen.params {
297             builtin_type_shadow::check(cx, param);
298         }
299     }
300 
check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat)301     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
302         unneeded_field_pattern::check(cx, pat);
303         redundant_pattern::check(cx, pat);
304         unneeded_wildcard_pattern::check(cx, pat);
305     }
306 
check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId)307     fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
308         let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
309 
310         for arg in &fn_kind.decl().inputs {
311             if let PatKind::Ident(_, ident, None) = arg.pat.kind {
312                 let arg_name = ident.to_string();
313 
314                 if let Some(arg_name) = arg_name.strip_prefix('_') {
315                     if let Some(correspondence) = registered_names.get(arg_name) {
316                         span_lint(
317                             cx,
318                             DUPLICATE_UNDERSCORE_ARGUMENT,
319                             *correspondence,
320                             &format!(
321                                 "`{}` already exists, having another argument having almost the same \
322                                  name makes code comprehension and documentation more difficult",
323                                 arg_name
324                             ),
325                         );
326                     }
327                 } else {
328                     registered_names.insert(arg_name, arg.pat.span);
329                 }
330             }
331         }
332     }
333 
check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr)334     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
335         if in_external_macro(cx.sess, expr.span) {
336             return;
337         }
338 
339         if let ExprKind::Lit(ref lit) = expr.kind {
340             MiscEarlyLints::check_lit(cx, lit);
341         }
342         double_neg::check(cx, expr);
343     }
344 }
345 
346 impl MiscEarlyLints {
check_lit(cx: &EarlyContext<'_>, lit: &Lit)347     fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
348         // We test if first character in snippet is a number, because the snippet could be an expansion
349         // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
350         // Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
351         // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
352         // FIXME: Find a better way to detect those cases.
353         let lit_snip = match snippet_opt(cx, lit.span) {
354             Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
355             _ => return,
356         };
357 
358         if let LitKind::Int(value, lit_int_type) = lit.kind {
359             let suffix = match lit_int_type {
360                 LitIntType::Signed(ty) => ty.name_str(),
361                 LitIntType::Unsigned(ty) => ty.name_str(),
362                 LitIntType::Unsuffixed => "",
363             };
364             literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
365             if lit_snip.starts_with("0x") {
366                 mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
367             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
368                 // nothing to do
369             } else if value != 0 && lit_snip.starts_with('0') {
370                 zero_prefixed_literal::check(cx, lit, &lit_snip);
371             }
372         } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
373             let suffix = float_ty.name_str();
374             literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
375         }
376     }
377 }
378