about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-05-06 07:46:52 +0000
committerbors <bors@rust-lang.org>2021-05-06 07:46:52 +0000
commit7191675ab15950ed6a1bad5047f6bbc5faa5b319 (patch)
tree3cd3c2b5f3bc2f340ee69b4bab9631147a3026ce
parent9dd87051c79d593301864087657a09bf8837e57b (diff)
parent3fbb060379485605fc8649ba5e749b141fbb9335 (diff)
downloadrust-7191675ab15950ed6a1bad5047f6bbc5faa5b319.tar.gz
rust-7191675ab15950ed6a1bad5047f6bbc5faa5b319.zip
Auto merge of #7166 - TaKO8Ki:refactor_misc_early_module, r=llogiq
Refactor: arrange lints in misc_early module

This PR arranges misc_early lints so that they can be accessed more easily.
Basically, I refactored them following the instruction described in #6680.

cc: `@Y-Nak,` `@flip1995,` `@magurotuna`

changelog: Move lints in misc_early module into their own modules.
-rw-r--r--clippy_lints/src/misc_early.rs569
-rw-r--r--clippy_lints/src/misc_early/builtin_type_shadow.rs19
-rw-r--r--clippy_lints/src/misc_early/double_neg.rs23
-rw-r--r--clippy_lints/src/misc_early/mixed_case_hex_literals.rs34
-rw-r--r--clippy_lints/src/misc_early/mod.rs348
-rw-r--r--clippy_lints/src/misc_early/redundant_pattern.rs31
-rw-r--r--clippy_lints/src/misc_early/unneeded_field_pattern.rs72
-rw-r--r--clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs52
-rw-r--r--clippy_lints/src/misc_early/unseparated_literal_suffix.rs26
-rw-r--r--clippy_lints/src/misc_early/zero_prefixed_literal.rs29
-rw-r--r--tests/ui/builtin_type_shadow.rs (renamed from tests/ui/builtin-type-shadow.rs)0
-rw-r--r--tests/ui/builtin_type_shadow.stderr (renamed from tests/ui/builtin-type-shadow.stderr)4
12 files changed, 636 insertions, 571 deletions
diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs
deleted file mode 100644
index 3c6a7071c24..00000000000
--- a/clippy_lints/src/misc_early.rs
+++ /dev/null
@@ -1,569 +0,0 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{
-    BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability,
-    NodeId, Pat, PatKind, UnOp,
-};
-use rustc_ast::visit::FnKind;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::Applicability;
-use rustc_hir::PrimTy;
-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::source_map::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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # struct Foo {
-    /// #     a: i32,
-    /// #     b: i32,
-    /// #     c: i32,
-    /// # }
-    /// let f = Foo { a: 0, b: 0, c: 0 };
-    ///
-    /// // Bad
-    /// match f {
-    ///     Foo { a: _, b: 0, .. } => {},
-    ///     Foo { a: _, b: _, c: _ } => {},
-    /// }
-    ///
-    /// // Good
-    /// match f {
-    ///     Foo { b: 0, .. } => {},
-    ///     Foo { .. } => {},
-    /// }
-    /// ```
-    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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// // Bad
-    /// fn foo(a: i32, _a: i32) {}
-    ///
-    /// // Good
-    /// fn bar(a: i32, _b: i32) {}
-    /// ```
-    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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// let mut x = 3;
-    /// --x;
-    /// ```
-    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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// // Bad
-    /// let y = 0x1a9BAcD;
-    ///
-    /// // Good
-    /// let y = 0x1A9BACD;
-    /// ```
-    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.
-    ///
-    /// **Why is this bad?** It is much less readable.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// // Bad
-    /// let y = 123832i32;
-    ///
-    /// // Good
-    /// let y = 123832_i32;
-    /// ```
-    pub UNSEPARATED_LITERAL_SUFFIX,
-    pedantic,
-    "literals whose suffix is not 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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    ///
-    /// In Rust:
-    /// ```rust
-    /// 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`).
-    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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    ///
-    /// ```ignore
-    /// impl<u32> Foo<u32> {
-    ///     fn impl_func(&self) -> u32 {
-    ///         42
-    ///     }
-    /// }
-    /// ```
-    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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # let v = Some("abc");
-    ///
-    /// // Bad
-    /// match v {
-    ///     Some(x) => (),
-    ///     y @ _ => (),
-    /// }
-    ///
-    /// // Good
-    /// match v {
-    ///     Some(x) => (),
-    ///     y => (),
-    /// }
-    /// ```
-    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.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # struct TupleStruct(u32, u32, u32);
-    /// # let t = TupleStruct(1, 2, 3);
-    /// // Bad
-    /// match t {
-    ///     TupleStruct(0, .., _) => (),
-    ///     _ => (),
-    /// }
-    ///
-    /// // Good
-    /// match t {
-    ///     TupleStruct(0, ..) => (),
-    ///     _ => (),
-    /// }
-    /// ```
-    pub UNNEEDED_WILDCARD_PATTERN,
-    complexity,
-    "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
-}
-
-declare_lint_pass!(MiscEarlyLints => [
-    UNNEEDED_FIELD_PATTERN,
-    DUPLICATE_UNDERSCORE_ARGUMENT,
-    DOUBLE_NEG,
-    MIXED_CASE_HEX_LITERALS,
-    UNSEPARATED_LITERAL_SUFFIX,
-    ZERO_PREFIXED_LITERAL,
-    BUILTIN_TYPE_SHADOW,
-    REDUNDANT_PATTERN,
-    UNNEEDED_WILDCARD_PATTERN,
-]);
-
-impl EarlyLintPass for MiscEarlyLints {
-    fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
-        for param in &gen.params {
-            if let GenericParamKind::Type { .. } = param.kind {
-                if let Some(prim_ty) = PrimTy::from_name(param.ident.name) {
-                    span_lint(
-                        cx,
-                        BUILTIN_TYPE_SHADOW,
-                        param.ident.span,
-                        &format!("this generic shadows the built-in type `{}`", prim_ty.name()),
-                    );
-                }
-            }
-        }
-    }
-
-    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
-        if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind {
-            let mut wilds = 0;
-            let type_name = npat
-                .segments
-                .last()
-                .expect("A path must have at least one segment")
-                .ident
-                .name;
-
-            for field in pfields {
-                if let PatKind::Wild = field.pat.kind {
-                    wilds += 1;
-                }
-            }
-            if !pfields.is_empty() && wilds == pfields.len() {
-                span_lint_and_help(
-                    cx,
-                    UNNEEDED_FIELD_PATTERN,
-                    pat.span,
-                    "all the struct fields are matched to a wildcard pattern, consider using `..`",
-                    None,
-                    &format!("try with `{} {{ .. }}` instead", type_name),
-                );
-                return;
-            }
-            if wilds > 0 {
-                for field in pfields {
-                    if let PatKind::Wild = field.pat.kind {
-                        wilds -= 1;
-                        if wilds > 0 {
-                            span_lint(
-                                cx,
-                                UNNEEDED_FIELD_PATTERN,
-                                field.span,
-                                "you matched a field with a wildcard pattern, consider using `..` instead",
-                            );
-                        } else {
-                            let mut normal = vec![];
-
-                            for field in pfields {
-                                match field.pat.kind {
-                                    PatKind::Wild => {},
-                                    _ => {
-                                        if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
-                                            normal.push(n);
-                                        }
-                                    },
-                                }
-                            }
-
-                            span_lint_and_help(
-                                cx,
-                                UNNEEDED_FIELD_PATTERN,
-                                field.span,
-                                "you matched a field with a wildcard pattern, consider using `..` \
-                                 instead",
-                                None,
-                                &format!("try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
-                            );
-                        }
-                    }
-                }
-            }
-        }
-
-        if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
-            let left_binding = match left {
-                BindingMode::ByRef(Mutability::Mut) => "ref mut ",
-                BindingMode::ByRef(Mutability::Not) => "ref ",
-                BindingMode::ByValue(..) => "",
-            };
-
-            if let PatKind::Wild = right.kind {
-                span_lint_and_sugg(
-                    cx,
-                    REDUNDANT_PATTERN,
-                    pat.span,
-                    &format!(
-                        "the `{} @ _` pattern can be written as just `{}`",
-                        ident.name, ident.name,
-                    ),
-                    "try",
-                    format!("{}{}", left_binding, ident.name),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-
-        check_unneeded_wildcard_pattern(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!(
-                                "`{}` already exists, having another argument having almost the same \
-                                 name makes code comprehension and documentation more difficult",
-                                arg_name
-                            ),
-                        );
-                    }
-                } 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;
-        }
-        match expr.kind {
-            ExprKind::Unary(UnOp::Neg, ref inner) => {
-                if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
-                    span_lint(
-                        cx,
-                        DOUBLE_NEG,
-                        expr.span,
-                        "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
-                    );
-                }
-            },
-            ExprKind::Lit(ref lit) => Self::check_lit(cx, lit),
-            _ => (),
-        }
-    }
-}
-
-impl MiscEarlyLints {
-    fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
-        // 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, lit.span) {
-            Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
-            _ => return,
-        };
-
-        if let 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 => "",
-            };
-
-            let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
-                val
-            } else {
-                return; // It's useless so shouldn't lint.
-            };
-            // Do not lint when literal is unsuffixed.
-            if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
-                span_lint_and_sugg(
-                    cx,
-                    UNSEPARATED_LITERAL_SUFFIX,
-                    lit.span,
-                    "integer type suffix should be separated by an underscore",
-                    "add an underscore",
-                    format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
-                    Applicability::MachineApplicable,
-                );
-            }
-
-            if lit_snip.starts_with("0x") {
-                if maybe_last_sep_idx <= 2 {
-                    // It's meaningless or causes range error.
-                    return;
-                }
-                let mut seen = (false, false);
-                for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() {
-                    match ch {
-                        b'a'..=b'f' => seen.0 = true,
-                        b'A'..=b'F' => seen.1 = true,
-                        _ => {},
-                    }
-                    if seen.0 && seen.1 {
-                        span_lint(
-                            cx,
-                            MIXED_CASE_HEX_LITERALS,
-                            lit.span,
-                            "inconsistent casing in hexadecimal literal",
-                        );
-                        break;
-                    }
-                }
-            } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
-                /* nothing to do */
-            } else if value != 0 && lit_snip.starts_with('0') {
-                span_lint_and_then(
-                    cx,
-                    ZERO_PREFIXED_LITERAL,
-                    lit.span,
-                    "this is a decimal constant",
-                    |diag| {
-                        diag.span_suggestion(
-                            lit.span,
-                            "if you mean to use a decimal constant, remove the `0` to avoid confusion",
-                            lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
-                            Applicability::MaybeIncorrect,
-                        );
-                        diag.span_suggestion(
-                            lit.span,
-                            "if you mean to use an octal constant, use `0o`",
-                            format!("0o{}", lit_snip.trim_start_matches(|c| c == '_' || c == '0')),
-                            Applicability::MaybeIncorrect,
-                        );
-                    },
-                );
-            }
-        } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
-            let suffix = float_ty.name_str();
-            let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
-                val
-            } else {
-                return; // It's useless so shouldn't lint.
-            };
-            if lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
-                span_lint_and_sugg(
-                    cx,
-                    UNSEPARATED_LITERAL_SUFFIX,
-                    lit.span,
-                    "float type suffix should be separated by an underscore",
-                    "add an underscore",
-                    format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
-
-fn check_unneeded_wildcard_pattern(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
-        fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
-            span_lint_and_sugg(
-                cx,
-                UNNEEDED_WILDCARD_PATTERN,
-                span,
-                if only_one {
-                    "this pattern is unneeded as the `..` pattern can match that element"
-                } else {
-                    "these patterns are unneeded as the `..` pattern can match those elements"
-                },
-                if only_one { "remove it" } else { "remove them" },
-                "".to_string(),
-                Applicability::MachineApplicable,
-            );
-        }
-
-        if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
-            if let Some((left_index, left_pat)) = patterns[..rest_index]
-                .iter()
-                .rev()
-                .take_while(|pat| matches!(pat.kind, PatKind::Wild))
-                .enumerate()
-                .last()
-            {
-                span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
-            }
-
-            if let Some((right_index, right_pat)) = patterns[rest_index + 1..]
-                .iter()
-                .take_while(|pat| matches!(pat.kind, PatKind::Wild))
-                .enumerate()
-                .last()
-            {
-                span_lint(
-                    cx,
-                    patterns[rest_index].span.shrink_to_hi().to(right_pat.span),
-                    right_index == 0,
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/misc_early/builtin_type_shadow.rs b/clippy_lints/src/misc_early/builtin_type_shadow.rs
new file mode 100644
index 00000000000..9f6b0bdc7a4
--- /dev/null
+++ b/clippy_lints/src/misc_early/builtin_type_shadow.rs
@@ -0,0 +1,19 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{GenericParam, GenericParamKind};
+use rustc_hir::PrimTy;
+use rustc_lint::EarlyContext;
+
+use super::BUILTIN_TYPE_SHADOW;
+
+pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) {
+    if let GenericParamKind::Type { .. } = param.kind {
+        if let Some(prim_ty) = PrimTy::from_name(param.ident.name) {
+            span_lint(
+                cx,
+                BUILTIN_TYPE_SHADOW,
+                param.ident.span,
+                &format!("this generic shadows the built-in type `{}`", prim_ty.name()),
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/misc_early/double_neg.rs b/clippy_lints/src/misc_early/double_neg.rs
new file mode 100644
index 00000000000..6f65778e119
--- /dev/null
+++ b/clippy_lints/src/misc_early/double_neg.rs
@@ -0,0 +1,23 @@
+use super::MiscEarlyLints;
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Expr, ExprKind, UnOp};
+use rustc_lint::EarlyContext;
+
+use super::DOUBLE_NEG;
+
+pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
+    match expr.kind {
+        ExprKind::Unary(UnOp::Neg, ref inner) => {
+            if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
+                span_lint(
+                    cx,
+                    DOUBLE_NEG,
+                    expr.span,
+                    "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
+                );
+            }
+        },
+        ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
+        _ => (),
+    }
+}
diff --git a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
new file mode 100644
index 00000000000..80e24213100
--- /dev/null
+++ b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::Lit;
+use rustc_lint::EarlyContext;
+
+use super::MIXED_CASE_HEX_LITERALS;
+
+pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) {
+    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
+        val
+    } else {
+        return; // It's useless so shouldn't lint.
+    };
+    if maybe_last_sep_idx <= 2 {
+        // It's meaningless or causes range error.
+        return;
+    }
+    let mut seen = (false, false);
+    for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() {
+        match ch {
+            b'a'..=b'f' => seen.0 = true,
+            b'A'..=b'F' => seen.1 = true,
+            _ => {},
+        }
+        if seen.0 && seen.1 {
+            span_lint(
+                cx,
+                MIXED_CASE_HEX_LITERALS,
+                lit.span,
+                "inconsistent casing in hexadecimal literal",
+            );
+            break;
+        }
+    }
+}
diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs
new file mode 100644
index 00000000000..dd38316fa25
--- /dev/null
+++ b/clippy_lints/src/misc_early/mod.rs
@@ -0,0 +1,348 @@
+mod builtin_type_shadow;
+mod double_neg;
+mod mixed_case_hex_literals;
+mod redundant_pattern;
+mod unneeded_field_pattern;
+mod unneeded_wildcard_pattern;
+mod unseparated_literal_suffix;
+mod zero_prefixed_literal;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet_opt;
+use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+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::source_map::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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # struct Foo {
+    /// #     a: i32,
+    /// #     b: i32,
+    /// #     c: i32,
+    /// # }
+    /// let f = Foo { a: 0, b: 0, c: 0 };
+    ///
+    /// // Bad
+    /// match f {
+    ///     Foo { a: _, b: 0, .. } => {},
+    ///     Foo { a: _, b: _, c: _ } => {},
+    /// }
+    ///
+    /// // Good
+    /// match f {
+    ///     Foo { b: 0, .. } => {},
+    ///     Foo { .. } => {},
+    /// }
+    /// ```
+    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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// fn foo(a: i32, _a: i32) {}
+    ///
+    /// // Good
+    /// fn bar(a: i32, _b: i32) {}
+    /// ```
+    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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut x = 3;
+    /// --x;
+    /// ```
+    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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// let y = 0x1a9BAcD;
+    ///
+    /// // Good
+    /// let y = 0x1A9BACD;
+    /// ```
+    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.
+    ///
+    /// **Why is this bad?** It is much less readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// let y = 123832i32;
+    ///
+    /// // Good
+    /// let y = 123832_i32;
+    /// ```
+    pub UNSEPARATED_LITERAL_SUFFIX,
+    pedantic,
+    "literals whose suffix is not 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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// In Rust:
+    /// ```rust
+    /// 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`).
+    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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```ignore
+    /// impl<u32> Foo<u32> {
+    ///     fn impl_func(&self) -> u32 {
+    ///         42
+    ///     }
+    /// }
+    /// ```
+    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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let v = Some("abc");
+    ///
+    /// // Bad
+    /// match v {
+    ///     Some(x) => (),
+    ///     y @ _ => (),
+    /// }
+    ///
+    /// // Good
+    /// match v {
+    ///     Some(x) => (),
+    ///     y => (),
+    /// }
+    /// ```
+    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.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # struct TupleStruct(u32, u32, u32);
+    /// # let t = TupleStruct(1, 2, 3);
+    /// // Bad
+    /// match t {
+    ///     TupleStruct(0, .., _) => (),
+    ///     _ => (),
+    /// }
+    ///
+    /// // Good
+    /// match t {
+    ///     TupleStruct(0, ..) => (),
+    ///     _ => (),
+    /// }
+    /// ```
+    pub UNNEEDED_WILDCARD_PATTERN,
+    complexity,
+    "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
+}
+
+declare_lint_pass!(MiscEarlyLints => [
+    UNNEEDED_FIELD_PATTERN,
+    DUPLICATE_UNDERSCORE_ARGUMENT,
+    DOUBLE_NEG,
+    MIXED_CASE_HEX_LITERALS,
+    UNSEPARATED_LITERAL_SUFFIX,
+    ZERO_PREFIXED_LITERAL,
+    BUILTIN_TYPE_SHADOW,
+    REDUNDANT_PATTERN,
+    UNNEEDED_WILDCARD_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) {
+        unneeded_field_pattern::check(cx, pat);
+        redundant_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!(
+                                "`{}` already exists, having another argument having almost the same \
+                                 name makes code comprehension and documentation more difficult",
+                                arg_name
+                            ),
+                        );
+                    }
+                } 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;
+        }
+        double_neg::check(cx, expr)
+    }
+}
+
+impl MiscEarlyLints {
+    fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
+        // 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, lit.span) {
+            Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
+            _ => return,
+        };
+
+        if let 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 => "",
+            };
+            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
+            if lit_snip.starts_with("0x") {
+                mixed_case_hex_literals::check(cx, lit, 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, lit, &lit_snip)
+            }
+        } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
+            let suffix = float_ty.name_str();
+            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float")
+        }
+    }
+}
diff --git a/clippy_lints/src/misc_early/redundant_pattern.rs b/clippy_lints/src/misc_early/redundant_pattern.rs
new file mode 100644
index 00000000000..525dbf7757c
--- /dev/null
+++ b/clippy_lints/src/misc_early/redundant_pattern.rs
@@ -0,0 +1,31 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind};
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+
+use super::REDUNDANT_PATTERN;
+
+pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
+    if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
+        let left_binding = match left {
+            BindingMode::ByRef(Mutability::Mut) => "ref mut ",
+            BindingMode::ByRef(Mutability::Not) => "ref ",
+            BindingMode::ByValue(..) => "",
+        };
+
+        if let PatKind::Wild = right.kind {
+            span_lint_and_sugg(
+                cx,
+                REDUNDANT_PATTERN,
+                pat.span,
+                &format!(
+                    "the `{} @ _` pattern can be written as just `{}`",
+                    ident.name, ident.name,
+                ),
+                "try",
+                format!("{}{}", left_binding, ident.name),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs
new file mode 100644
index 00000000000..329a0009a3e
--- /dev/null
+++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs
@@ -0,0 +1,72 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use rustc_ast::ast::{Pat, PatKind};
+use rustc_lint::{EarlyContext, LintContext};
+
+use super::UNNEEDED_FIELD_PATTERN;
+
+pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
+    if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind {
+        let mut wilds = 0;
+        let type_name = npat
+            .segments
+            .last()
+            .expect("A path must have at least one segment")
+            .ident
+            .name;
+
+        for field in pfields {
+            if let PatKind::Wild = field.pat.kind {
+                wilds += 1;
+            }
+        }
+        if !pfields.is_empty() && wilds == pfields.len() {
+            span_lint_and_help(
+                cx,
+                UNNEEDED_FIELD_PATTERN,
+                pat.span,
+                "all the struct fields are matched to a wildcard pattern, consider using `..`",
+                None,
+                &format!("try with `{} {{ .. }}` instead", type_name),
+            );
+            return;
+        }
+        if wilds > 0 {
+            for field in pfields {
+                if let PatKind::Wild = field.pat.kind {
+                    wilds -= 1;
+                    if wilds > 0 {
+                        span_lint(
+                            cx,
+                            UNNEEDED_FIELD_PATTERN,
+                            field.span,
+                            "you matched a field with a wildcard pattern, consider using `..` instead",
+                        );
+                    } else {
+                        let mut normal = vec![];
+
+                        for field in pfields {
+                            match field.pat.kind {
+                                PatKind::Wild => {},
+                                _ => {
+                                    if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
+                                        normal.push(n);
+                                    }
+                                },
+                            }
+                        }
+
+                        span_lint_and_help(
+                            cx,
+                            UNNEEDED_FIELD_PATTERN,
+                            field.span,
+                            "you matched a field with a wildcard pattern, consider using `..` \
+                             instead",
+                            None,
+                            &format!("try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
new file mode 100644
index 00000000000..4dd032d78f1
--- /dev/null
+++ b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::{Pat, PatKind};
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+use rustc_span::source_map::Span;
+
+use super::UNNEEDED_WILDCARD_PATTERN;
+
+pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
+    if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
+        if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
+            if let Some((left_index, left_pat)) = patterns[..rest_index]
+                .iter()
+                .rev()
+                .take_while(|pat| matches!(pat.kind, PatKind::Wild))
+                .enumerate()
+                .last()
+            {
+                span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
+            }
+
+            if let Some((right_index, right_pat)) = patterns[rest_index + 1..]
+                .iter()
+                .take_while(|pat| matches!(pat.kind, PatKind::Wild))
+                .enumerate()
+                .last()
+            {
+                span_lint(
+                    cx,
+                    patterns[rest_index].span.shrink_to_hi().to(right_pat.span),
+                    right_index == 0,
+                );
+            }
+        }
+    }
+}
+
+fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
+    span_lint_and_sugg(
+        cx,
+        UNNEEDED_WILDCARD_PATTERN,
+        span,
+        if only_one {
+            "this pattern is unneeded as the `..` pattern can match that element"
+        } else {
+            "these patterns are unneeded as the `..` pattern can match those elements"
+        },
+        if only_one { "remove it" } else { "remove them" },
+        "".to_string(),
+        Applicability::MachineApplicable,
+    );
+}
diff --git a/clippy_lints/src/misc_early/unseparated_literal_suffix.rs b/clippy_lints/src/misc_early/unseparated_literal_suffix.rs
new file mode 100644
index 00000000000..2018aa6184a
--- /dev/null
+++ b/clippy_lints/src/misc_early/unseparated_literal_suffix.rs
@@ -0,0 +1,26 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::Lit;
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+
+use super::UNSEPARATED_LITERAL_SUFFIX;
+
+pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
+    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
+        val
+    } else {
+        return; // It's useless so shouldn't lint.
+    };
+    // Do not lint when literal is unsuffixed.
+    if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
+        span_lint_and_sugg(
+            cx,
+            UNSEPARATED_LITERAL_SUFFIX,
+            lit.span,
+            &format!("{} type suffix should be separated by an underscore", sugg_type),
+            "add an underscore",
+            format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/clippy_lints/src/misc_early/zero_prefixed_literal.rs
new file mode 100644
index 00000000000..4963bba82f2
--- /dev/null
+++ b/clippy_lints/src/misc_early/zero_prefixed_literal.rs
@@ -0,0 +1,29 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::ast::Lit;
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+
+use super::ZERO_PREFIXED_LITERAL;
+
+pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
+    span_lint_and_then(
+        cx,
+        ZERO_PREFIXED_LITERAL,
+        lit.span,
+        "this is a decimal constant",
+        |diag| {
+            diag.span_suggestion(
+                lit.span,
+                "if you mean to use a decimal constant, remove the `0` to avoid confusion",
+                lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
+                Applicability::MaybeIncorrect,
+            );
+            diag.span_suggestion(
+                lit.span,
+                "if you mean to use an octal constant, use `0o`",
+                format!("0o{}", lit_snip.trim_start_matches(|c| c == '_' || c == '0')),
+                Applicability::MaybeIncorrect,
+            );
+        },
+    );
+}
diff --git a/tests/ui/builtin-type-shadow.rs b/tests/ui/builtin_type_shadow.rs
index 69b8b6a0e68..69b8b6a0e68 100644
--- a/tests/ui/builtin-type-shadow.rs
+++ b/tests/ui/builtin_type_shadow.rs
diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin_type_shadow.stderr
index f42b246afd2..47a8a1e623e 100644
--- a/tests/ui/builtin-type-shadow.stderr
+++ b/tests/ui/builtin_type_shadow.stderr
@@ -1,5 +1,5 @@
 error: this generic shadows the built-in type `u32`
-  --> $DIR/builtin-type-shadow.rs:4:8
+  --> $DIR/builtin_type_shadow.rs:4:8
    |
 LL | fn foo<u32>(a: u32) -> u32 {
    |        ^^^
@@ -7,7 +7,7 @@ LL | fn foo<u32>(a: u32) -> u32 {
    = note: `-D clippy::builtin-type-shadow` implied by `-D warnings`
 
 error[E0308]: mismatched types
-  --> $DIR/builtin-type-shadow.rs:5:5
+  --> $DIR/builtin_type_shadow.rs:5:5
    |
 LL | fn foo<u32>(a: u32) -> u32 {
    |        ---             --- expected `u32` because of return type