| mod builtin_type_shadow; |
| mod double_neg; |
| mod literal_suffix; |
| mod mixed_case_hex_literals; |
| mod redundant_at_rest_pattern; |
| mod redundant_pattern; |
| mod unneeded_field_pattern; |
| mod unneeded_wildcard_pattern; |
| mod zero_prefixed_literal; |
| |
| use clippy_utils::diagnostics::span_lint; |
| use clippy_utils::source::snippet_opt; |
| use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; |
| use rustc_ast::token; |
| use rustc_ast::visit::FnKind; |
| use rustc_data_structures::fx::FxHashMap; |
| use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; |
| use rustc_middle::lint::in_external_macro; |
| use rustc_session::{declare_lint_pass, declare_tool_lint}; |
| use rustc_span::Span; |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for structure field patterns bound to wildcards. |
| /// |
| /// ### Why is this bad? |
| /// Using `..` instead is shorter and leaves the focus on |
| /// the fields that are actually bound. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # struct Foo { |
| /// # a: i32, |
| /// # b: i32, |
| /// # c: i32, |
| /// # } |
| /// let f = Foo { a: 0, b: 0, c: 0 }; |
| /// |
| /// match f { |
| /// Foo { a: _, b: 0, .. } => {}, |
| /// Foo { a: _, b: _, c: _ } => {}, |
| /// } |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # struct Foo { |
| /// # a: i32, |
| /// # b: i32, |
| /// # c: i32, |
| /// # } |
| /// let f = Foo { a: 0, b: 0, c: 0 }; |
| /// |
| /// match f { |
| /// Foo { b: 0, .. } => {}, |
| /// Foo { .. } => {}, |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub UNNEEDED_FIELD_PATTERN, |
| restriction, |
| "struct fields bound to a wildcard instead of using `..`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for function arguments having the similar names |
| /// differing by an underscore. |
| /// |
| /// ### Why is this bad? |
| /// It affects code readability. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn foo(a: i32, _a: i32) {} |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// fn bar(a: i32, _b: i32) {} |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub DUPLICATE_UNDERSCORE_ARGUMENT, |
| style, |
| "function arguments having names which only differ by an underscore" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Detects expressions of the form `--x`. |
| /// |
| /// ### Why is this bad? |
| /// It can mislead C/C++ programmers to think `x` was |
| /// decremented. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let mut x = 3; |
| /// --x; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub DOUBLE_NEG, |
| style, |
| "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Warns on hexadecimal literals with mixed-case letter |
| /// digits. |
| /// |
| /// ### Why is this bad? |
| /// It looks confusing. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let _ = |
| /// 0x1a9BAcD |
| /// # ; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # let _ = |
| /// 0x1A9BACD |
| /// # ; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub MIXED_CASE_HEX_LITERALS, |
| style, |
| "hex literals whose letter digits are not consistently upper- or lowercased" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Warns if literal suffixes are not separated by an |
| /// underscore. |
| /// To enforce unseparated literal suffix style, |
| /// see the `separated_literal_suffix` lint. |
| /// |
| /// ### Why is this bad? |
| /// Suffix style should be consistent. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let _ = |
| /// 123832i32 |
| /// # ; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # let _ = |
| /// 123832_i32 |
| /// # ; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub UNSEPARATED_LITERAL_SUFFIX, |
| restriction, |
| "literals whose suffix is not separated by an underscore" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Warns if literal suffixes are separated by an underscore. |
| /// To enforce separated literal suffix style, |
| /// see the `unseparated_literal_suffix` lint. |
| /// |
| /// ### Why is this bad? |
| /// Suffix style should be consistent. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let _ = |
| /// 123832_i32 |
| /// # ; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # let _ = |
| /// 123832i32 |
| /// # ; |
| /// ``` |
| #[clippy::version = "1.58.0"] |
| pub SEPARATED_LITERAL_SUFFIX, |
| restriction, |
| "literals whose suffix is separated by an underscore" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Warns if an integral constant literal starts with `0`. |
| /// |
| /// ### Why is this bad? |
| /// In some languages (including the infamous C language |
| /// and most of its |
| /// family), this marks an octal constant. In Rust however, this is a decimal |
| /// constant. This could |
| /// be confusing for both the writer and a reader of the constant. |
| /// |
| /// ### Example |
| /// |
| /// In Rust: |
| /// ```no_run |
| /// fn main() { |
| /// let a = 0123; |
| /// println!("{}", a); |
| /// } |
| /// ``` |
| /// |
| /// prints `123`, while in C: |
| /// |
| /// ```c |
| /// #include <stdio.h> |
| /// |
| /// int main() { |
| /// int a = 0123; |
| /// printf("%d\n", a); |
| /// } |
| /// ``` |
| /// |
| /// prints `83` (as `83 == 0o123` while `123 == 0o173`). |
| #[clippy::version = "pre 1.29.0"] |
| pub ZERO_PREFIXED_LITERAL, |
| complexity, |
| "integer literals starting with `0`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Warns if a generic shadows a built-in type. |
| /// |
| /// ### Why is this bad? |
| /// This gives surprising type errors. |
| /// |
| /// ### Example |
| /// |
| /// ```ignore |
| /// impl<u32> Foo<u32> { |
| /// fn impl_func(&self) -> u32 { |
| /// 42 |
| /// } |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub BUILTIN_TYPE_SHADOW, |
| style, |
| "shadowing a builtin type" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for patterns in the form `name @ _`. |
| /// |
| /// ### Why is this bad? |
| /// It's almost always more readable to just use direct |
| /// bindings. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let v = Some("abc"); |
| /// match v { |
| /// Some(x) => (), |
| /// y @ _ => (), |
| /// } |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # let v = Some("abc"); |
| /// match v { |
| /// Some(x) => (), |
| /// y => (), |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub REDUNDANT_PATTERN, |
| style, |
| "using `name @ _` in a pattern" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for tuple patterns with a wildcard |
| /// pattern (`_`) is next to a rest pattern (`..`). |
| /// |
| /// _NOTE_: While `_, ..` means there is at least one element left, `..` |
| /// means there are 0 or more elements left. This can make a difference |
| /// when refactoring, but shouldn't result in errors in the refactored code, |
| /// since the wildcard pattern isn't used anyway. |
| /// |
| /// ### Why is this bad? |
| /// The wildcard pattern is unneeded as the rest pattern |
| /// can match that element as well. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # struct TupleStruct(u32, u32, u32); |
| /// # let t = TupleStruct(1, 2, 3); |
| /// match t { |
| /// TupleStruct(0, .., _) => (), |
| /// _ => (), |
| /// } |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # struct TupleStruct(u32, u32, u32); |
| /// # let t = TupleStruct(1, 2, 3); |
| /// match t { |
| /// TupleStruct(0, ..) => (), |
| /// _ => (), |
| /// } |
| /// ``` |
| #[clippy::version = "1.40.0"] |
| pub UNNEEDED_WILDCARD_PATTERN, |
| complexity, |
| "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `[all @ ..]` patterns. |
| /// |
| /// ### Why is this bad? |
| /// In all cases, `all` works fine and can often make code simpler, as you possibly won't need |
| /// to convert from say a `Vec` to a slice by dereferencing. |
| /// |
| /// ### Example |
| /// ```rust,ignore |
| /// if let [all @ ..] = &*v { |
| /// // NOTE: Type is a slice here |
| /// println!("all elements: {all:#?}"); |
| /// } |
| /// ``` |
| /// Use instead: |
| /// ```rust,ignore |
| /// if let all = v { |
| /// // NOTE: Type is a `Vec` here |
| /// println!("all elements: {all:#?}"); |
| /// } |
| /// // or |
| /// println!("all elements: {v:#?}"); |
| /// ``` |
| #[clippy::version = "1.72.0"] |
| pub REDUNDANT_AT_REST_PATTERN, |
| complexity, |
| "checks for `[all @ ..]` where `all` would suffice" |
| } |
| |
| declare_lint_pass!(MiscEarlyLints => [ |
| UNNEEDED_FIELD_PATTERN, |
| DUPLICATE_UNDERSCORE_ARGUMENT, |
| DOUBLE_NEG, |
| MIXED_CASE_HEX_LITERALS, |
| UNSEPARATED_LITERAL_SUFFIX, |
| SEPARATED_LITERAL_SUFFIX, |
| ZERO_PREFIXED_LITERAL, |
| BUILTIN_TYPE_SHADOW, |
| REDUNDANT_PATTERN, |
| UNNEEDED_WILDCARD_PATTERN, |
| REDUNDANT_AT_REST_PATTERN, |
| ]); |
| |
| impl EarlyLintPass for MiscEarlyLints { |
| fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { |
| for param in &gen.params { |
| builtin_type_shadow::check(cx, param); |
| } |
| } |
| |
| fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { |
| if in_external_macro(cx.sess(), pat.span) { |
| return; |
| } |
| |
| unneeded_field_pattern::check(cx, pat); |
| redundant_pattern::check(cx, pat); |
| redundant_at_rest_pattern::check(cx, pat); |
| unneeded_wildcard_pattern::check(cx, pat); |
| } |
| |
| fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) { |
| let mut registered_names: FxHashMap<String, Span> = FxHashMap::default(); |
| |
| for arg in &fn_kind.decl().inputs { |
| if let PatKind::Ident(_, ident, None) = arg.pat.kind { |
| let arg_name = ident.to_string(); |
| |
| if let Some(arg_name) = arg_name.strip_prefix('_') { |
| if let Some(correspondence) = registered_names.get(arg_name) { |
| span_lint( |
| cx, |
| DUPLICATE_UNDERSCORE_ARGUMENT, |
| *correspondence, |
| &format!( |
| "`{arg_name}` already exists, having another argument having almost the same \ |
| name makes code comprehension and documentation more difficult" |
| ), |
| ); |
| } |
| } else { |
| registered_names.insert(arg_name, arg.pat.span); |
| } |
| } |
| } |
| } |
| |
| fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| if in_external_macro(cx.sess(), expr.span) { |
| return; |
| } |
| |
| if let ExprKind::Lit(lit) = expr.kind { |
| MiscEarlyLints::check_lit(cx, lit, expr.span); |
| } |
| double_neg::check(cx, expr); |
| } |
| } |
| |
| impl MiscEarlyLints { |
| fn check_lit(cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { |
| // We test if first character in snippet is a number, because the snippet could be an expansion |
| // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`. |
| // Note that this check also covers special case that `line!()` is eagerly expanded by compiler. |
| // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression. |
| // FIXME: Find a better way to detect those cases. |
| let lit_snip = match snippet_opt(cx, span) { |
| Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip, |
| _ => return, |
| }; |
| |
| let lit_kind = LitKind::from_token_lit(lit); |
| if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind { |
| let suffix = match lit_int_type { |
| LitIntType::Signed(ty) => ty.name_str(), |
| LitIntType::Unsigned(ty) => ty.name_str(), |
| LitIntType::Unsuffixed => "", |
| }; |
| literal_suffix::check(cx, span, &lit_snip, suffix, "integer"); |
| if lit_snip.starts_with("0x") { |
| mixed_case_hex_literals::check(cx, span, suffix, &lit_snip); |
| } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { |
| // nothing to do |
| } else if value != 0 && lit_snip.starts_with('0') { |
| zero_prefixed_literal::check(cx, span, &lit_snip); |
| } |
| } else if let Ok(LitKind::Float(_, LitFloatType::Suffixed(float_ty))) = lit_kind { |
| let suffix = float_ty.name_str(); |
| literal_suffix::check(cx, span, &lit_snip, suffix, "float"); |
| } |
| } |
| } |