1 mod builtin_type_shadow
;
4 mod mixed_case_hex_literals
;
6 mod unneeded_field_pattern
;
7 mod unneeded_wildcard_pattern
;
8 mod zero_prefixed_literal
;
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
;
20 declare_clippy_lint
! {
22 /// Checks for structure field patterns bound to wildcards.
24 /// ### Why is this bad?
25 /// Using `..` instead is shorter and leaves the focus on
26 /// the fields that are actually bound.
35 /// let f = Foo { a: 0, b: 0, c: 0 };
39 /// Foo { a: _, b: 0, .. } => {},
40 /// Foo { a: _, b: _, c: _ } => {},
45 /// Foo { b: 0, .. } => {},
49 pub UNNEEDED_FIELD_PATTERN
,
51 "struct fields bound to a wildcard instead of using `..`"
54 declare_clippy_lint
! {
56 /// Checks for function arguments having the similar names
57 /// differing by an underscore.
59 /// ### Why is this bad?
60 /// It affects code readability.
65 /// fn foo(a: i32, _a: i32) {}
68 /// fn bar(a: i32, _b: i32) {}
70 pub DUPLICATE_UNDERSCORE_ARGUMENT
,
72 "function arguments having names which only differ by an underscore"
75 declare_clippy_lint
! {
77 /// Detects expressions of the form `--x`.
79 /// ### Why is this bad?
80 /// It can mislead C/C++ programmers to think `x` was
90 "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
93 declare_clippy_lint
! {
95 /// Warns on hexadecimal literals with mixed-case letter
98 /// ### Why is this bad?
99 /// It looks confusing.
104 /// let y = 0x1a9BAcD;
107 /// let y = 0x1A9BACD;
109 pub MIXED_CASE_HEX_LITERALS
,
111 "hex literals whose letter digits are not consistently upper- or lowercased"
114 declare_clippy_lint
! {
116 /// Warns if literal suffixes are not separated by an
118 /// To enforce unseparated literal suffix style,
119 /// see the `separated_literal_suffix` lint.
121 /// ### Why is this bad?
122 /// Suffix style should be consistent.
127 /// let y = 123832i32;
130 /// let y = 123832_i32;
132 pub UNSEPARATED_LITERAL_SUFFIX
,
134 "literals whose suffix is not separated by an underscore"
137 declare_clippy_lint
! {
139 /// Warns if literal suffixes are separated by an underscore.
140 /// To enforce separated literal suffix style,
141 /// see the `unseparated_literal_suffix` lint.
143 /// ### Why is this bad?
144 /// Suffix style should be consistent.
149 /// let y = 123832_i32;
152 /// let y = 123832i32;
154 pub SEPARATED_LITERAL_SUFFIX
,
156 "literals whose suffix is separated by an underscore"
159 declare_clippy_lint
! {
161 /// Warns if an integral constant literal starts with `0`.
163 /// ### Why is this bad?
164 /// In some languages (including the infamous C language
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.
176 /// println!("{}", a);
180 /// prints `123`, while in C:
183 /// #include <stdio.h>
187 /// printf("%d\n", a);
191 /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
192 pub ZERO_PREFIXED_LITERAL
,
194 "integer literals starting with `0`"
197 declare_clippy_lint
! {
199 /// Warns if a generic shadows a built-in type.
201 /// ### Why is this bad?
202 /// This gives surprising type errors.
207 /// impl<u32> Foo<u32> {
208 /// fn impl_func(&self) -> u32 {
213 pub BUILTIN_TYPE_SHADOW
,
215 "shadowing a builtin type"
218 declare_clippy_lint
! {
220 /// Checks for patterns in the form `name @ _`.
222 /// ### Why is this bad?
223 /// It's almost always more readable to just use direct
228 /// # let v = Some("abc");
242 pub REDUNDANT_PATTERN
,
244 "using `name @ _` in a pattern"
247 declare_clippy_lint
! {
249 /// Checks for tuple patterns with a wildcard
250 /// pattern (`_`) is next to a rest pattern (`..`).
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.
262 /// # struct TupleStruct(u32, u32, u32);
263 /// # let t = TupleStruct(1, 2, 3);
266 /// TupleStruct(0, .., _) => (),
272 /// TupleStruct(0, ..) => (),
276 pub UNNEEDED_WILDCARD_PATTERN
,
278 "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
281 declare_lint_pass
!(MiscEarlyLints
=> [
282 UNNEEDED_FIELD_PATTERN
,
283 DUPLICATE_UNDERSCORE_ARGUMENT
,
285 MIXED_CASE_HEX_LITERALS
,
286 UNSEPARATED_LITERAL_SUFFIX
,
287 SEPARATED_LITERAL_SUFFIX
,
288 ZERO_PREFIXED_LITERAL
,
291 UNNEEDED_WILDCARD_PATTERN
,
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
);
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
);
307 fn check_fn(&mut self, cx
: &EarlyContext
<'_
>, fn_kind
: FnKind
<'_
>, _
: Span
, _
: NodeId
) {
308 let mut registered_names
: FxHashMap
<String
, Span
> = FxHashMap
::default();
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();
314 if let Some(arg_name
) = arg_name
.strip_prefix('_'
) {
315 if let Some(correspondence
) = registered_names
.get(arg_name
) {
318 DUPLICATE_UNDERSCORE_ARGUMENT
,
321 "`{}` already exists, having another argument having almost the same \
322 name makes code comprehension and documentation more difficult",
328 registered_names
.insert(arg_name
, arg
.pat
.span
);
334 fn check_expr(&mut self, cx
: &EarlyContext
<'_
>, expr
: &Expr
) {
335 if in_external_macro(cx
.sess
, expr
.span
) {
339 if let ExprKind
::Lit(ref lit
) = expr
.kind
{
340 MiscEarlyLints
::check_lit(cx
, lit
);
342 double_neg
::check(cx
, expr
);
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
,
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
=> "",
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") {
369 } else if value
!= 0 && lit_snip
.starts_with('
0'
) {
370 zero_prefixed_literal
::check(cx
, lit
, &lit_snip
);
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");