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