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