]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/misc_early/mod.rs
Add tests for `#[no_mangle]` in `impl` blocks that looks like generic `impl` blocks...
[rust.git] / src / tools / clippy / clippy_lints / src / misc_early / mod.rs
1 mod builtin_type_shadow;
2 mod double_neg;
3 mod mixed_case_hex_literals;
4 mod redundant_pattern;
5 mod unneeded_field_pattern;
6 mod unneeded_wildcard_pattern;
7 mod unseparated_literal_suffix;
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, 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, LintContext};
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     ///
119     /// ### Why is this bad?
120     /// It is much less readable.
121     ///
122     /// ### Example
123     /// ```rust
124     /// // Bad
125     /// let y = 123832i32;
126     ///
127     /// // Good
128     /// let y = 123832_i32;
129     /// ```
130     pub UNSEPARATED_LITERAL_SUFFIX,
131     pedantic,
132     "literals whose suffix is not separated by an underscore"
133 }
134
135 declare_clippy_lint! {
136     /// ### What it does
137     /// Warns if an integral constant literal starts with `0`.
138     ///
139     /// ### Why is this bad?
140     /// In some languages (including the infamous C language
141     /// and most of its
142     /// family), this marks an octal constant. In Rust however, this is a decimal
143     /// constant. This could
144     /// be confusing for both the writer and a reader of the constant.
145     ///
146     /// ### Example
147     ///
148     /// In Rust:
149     /// ```rust
150     /// fn main() {
151     ///     let a = 0123;
152     ///     println!("{}", a);
153     /// }
154     /// ```
155     ///
156     /// prints `123`, while in C:
157     ///
158     /// ```c
159     /// #include <stdio.h>
160     ///
161     /// int main() {
162     ///     int a = 0123;
163     ///     printf("%d\n", a);
164     /// }
165     /// ```
166     ///
167     /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
168     pub ZERO_PREFIXED_LITERAL,
169     complexity,
170     "integer literals starting with `0`"
171 }
172
173 declare_clippy_lint! {
174     /// ### What it does
175     /// Warns if a generic shadows a built-in type.
176     ///
177     /// ### Why is this bad?
178     /// This gives surprising type errors.
179     ///
180     /// ### Example
181     ///
182     /// ```ignore
183     /// impl<u32> Foo<u32> {
184     ///     fn impl_func(&self) -> u32 {
185     ///         42
186     ///     }
187     /// }
188     /// ```
189     pub BUILTIN_TYPE_SHADOW,
190     style,
191     "shadowing a builtin type"
192 }
193
194 declare_clippy_lint! {
195     /// ### What it does
196     /// Checks for patterns in the form `name @ _`.
197     ///
198     /// ### Why is this bad?
199     /// It's almost always more readable to just use direct
200     /// bindings.
201     ///
202     /// ### Example
203     /// ```rust
204     /// # let v = Some("abc");
205     ///
206     /// // Bad
207     /// match v {
208     ///     Some(x) => (),
209     ///     y @ _ => (),
210     /// }
211     ///
212     /// // Good
213     /// match v {
214     ///     Some(x) => (),
215     ///     y => (),
216     /// }
217     /// ```
218     pub REDUNDANT_PATTERN,
219     style,
220     "using `name @ _` in a pattern"
221 }
222
223 declare_clippy_lint! {
224     /// ### What it does
225     /// Checks for tuple patterns with a wildcard
226     /// pattern (`_`) is next to a rest pattern (`..`).
227     ///
228     /// _NOTE_: While `_, ..` means there is at least one element left, `..`
229     /// means there are 0 or more elements left. This can make a difference
230     /// when refactoring, but shouldn't result in errors in the refactored code,
231     /// since the wildcard pattern isn't used anyway.
232     /// ### Why is this bad?
233     /// The wildcard pattern is unneeded as the rest pattern
234     /// can match that element as well.
235     ///
236     /// ### Example
237     /// ```rust
238     /// # struct TupleStruct(u32, u32, u32);
239     /// # let t = TupleStruct(1, 2, 3);
240     /// // Bad
241     /// match t {
242     ///     TupleStruct(0, .., _) => (),
243     ///     _ => (),
244     /// }
245     ///
246     /// // Good
247     /// match t {
248     ///     TupleStruct(0, ..) => (),
249     ///     _ => (),
250     /// }
251     /// ```
252     pub UNNEEDED_WILDCARD_PATTERN,
253     complexity,
254     "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
255 }
256
257 declare_lint_pass!(MiscEarlyLints => [
258     UNNEEDED_FIELD_PATTERN,
259     DUPLICATE_UNDERSCORE_ARGUMENT,
260     DOUBLE_NEG,
261     MIXED_CASE_HEX_LITERALS,
262     UNSEPARATED_LITERAL_SUFFIX,
263     ZERO_PREFIXED_LITERAL,
264     BUILTIN_TYPE_SHADOW,
265     REDUNDANT_PATTERN,
266     UNNEEDED_WILDCARD_PATTERN,
267 ]);
268
269 impl EarlyLintPass for MiscEarlyLints {
270     fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
271         for param in &gen.params {
272             builtin_type_shadow::check(cx, param);
273         }
274     }
275
276     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
277         unneeded_field_pattern::check(cx, pat);
278         redundant_pattern::check(cx, pat);
279         unneeded_wildcard_pattern::check(cx, pat);
280     }
281
282     fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
283         let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
284
285         for arg in &fn_kind.decl().inputs {
286             if let PatKind::Ident(_, ident, None) = arg.pat.kind {
287                 let arg_name = ident.to_string();
288
289                 if let Some(arg_name) = arg_name.strip_prefix('_') {
290                     if let Some(correspondence) = registered_names.get(arg_name) {
291                         span_lint(
292                             cx,
293                             DUPLICATE_UNDERSCORE_ARGUMENT,
294                             *correspondence,
295                             &format!(
296                                 "`{}` already exists, having another argument having almost the same \
297                                  name makes code comprehension and documentation more difficult",
298                                 arg_name
299                             ),
300                         );
301                     }
302                 } else {
303                     registered_names.insert(arg_name, arg.pat.span);
304                 }
305             }
306         }
307     }
308
309     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
310         if in_external_macro(cx.sess(), expr.span) {
311             return;
312         }
313         double_neg::check(cx, expr);
314     }
315 }
316
317 impl MiscEarlyLints {
318     fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
319         // We test if first character in snippet is a number, because the snippet could be an expansion
320         // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
321         // Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
322         // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
323         // FIXME: Find a better way to detect those cases.
324         let lit_snip = match snippet_opt(cx, lit.span) {
325             Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
326             _ => return,
327         };
328
329         if let LitKind::Int(value, lit_int_type) = lit.kind {
330             let suffix = match lit_int_type {
331                 LitIntType::Signed(ty) => ty.name_str(),
332                 LitIntType::Unsigned(ty) => ty.name_str(),
333                 LitIntType::Unsuffixed => "",
334             };
335             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
336             if lit_snip.starts_with("0x") {
337                 mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
338             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
339                 // nothing to do
340             } else if value != 0 && lit_snip.starts_with('0') {
341                 zero_prefixed_literal::check(cx, lit, &lit_snip);
342             }
343         } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
344             let suffix = float_ty.name_str();
345             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
346         }
347     }
348 }