]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/misc_early/mod.rs
New upstream version 1.58.1+dfsg1
[rustc.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, 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 {
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
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
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
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 {
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 }