1 mod builtin_type_shadow;
3 mod mixed_case_hex_literals;
5 mod unneeded_field_pattern;
6 mod unneeded_wildcard_pattern;
7 mod unseparated_literal_suffix;
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, 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
119 /// ### Why is this bad?
120 /// It is much less readable.
125 /// let y = 123832i32;
128 /// let y = 123832_i32;
130 pub UNSEPARATED_LITERAL_SUFFIX,
132 "literals whose suffix is not separated by an underscore"
135 declare_clippy_lint! {
137 /// Warns if an integral constant literal starts with `0`.
139 /// ### Why is this bad?
140 /// In some languages (including the infamous C language
142 /// family), this marks an octal constant. In Rust however, this is a decimal
143 /// constant. This could
144 /// be confusing for both the writer and a reader of the constant.
152 /// println!("{}", a);
156 /// prints `123`, while in C:
159 /// #include <stdio.h>
163 /// printf("%d\n", a);
167 /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
168 pub ZERO_PREFIXED_LITERAL,
170 "integer literals starting with `0`"
173 declare_clippy_lint! {
175 /// Warns if a generic shadows a built-in type.
177 /// ### Why is this bad?
178 /// This gives surprising type errors.
183 /// impl<u32> Foo<u32> {
184 /// fn impl_func(&self) -> u32 {
189 pub BUILTIN_TYPE_SHADOW,
191 "shadowing a builtin type"
194 declare_clippy_lint! {
196 /// Checks for patterns in the form `name @ _`.
198 /// ### Why is this bad?
199 /// It's almost always more readable to just use direct
204 /// # let v = Some("abc");
218 pub REDUNDANT_PATTERN,
220 "using `name @ _` in a pattern"
223 declare_clippy_lint! {
225 /// Checks for tuple patterns with a wildcard
226 /// pattern (`_`) is next to a rest pattern (`..`).
228 /// _NOTE_: While `_, ..` means there is at least one element left, `..`
229 /// means there are 0 or more elements left. This can make a difference
230 /// when refactoring, but shouldn't result in errors in the refactored code,
231 /// since the wildcard pattern isn't used anyway.
232 /// ### Why is this bad?
233 /// The wildcard pattern is unneeded as the rest pattern
234 /// can match that element as well.
238 /// # struct TupleStruct(u32, u32, u32);
239 /// # let t = TupleStruct(1, 2, 3);
242 /// TupleStruct(0, .., _) => (),
248 /// TupleStruct(0, ..) => (),
252 pub UNNEEDED_WILDCARD_PATTERN,
254 "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
257 declare_lint_pass!(MiscEarlyLints => [
258 UNNEEDED_FIELD_PATTERN,
259 DUPLICATE_UNDERSCORE_ARGUMENT,
261 MIXED_CASE_HEX_LITERALS,
262 UNSEPARATED_LITERAL_SUFFIX,
263 ZERO_PREFIXED_LITERAL,
266 UNNEEDED_WILDCARD_PATTERN,
269 impl EarlyLintPass for MiscEarlyLints {
270 fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
271 for param in &gen.params {
272 builtin_type_shadow::check(cx, param);
276 fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
277 unneeded_field_pattern::check(cx, pat);
278 redundant_pattern::check(cx, pat);
279 unneeded_wildcard_pattern::check(cx, pat);
282 fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
283 let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
285 for arg in &fn_kind.decl().inputs {
286 if let PatKind::Ident(_, ident, None) = arg.pat.kind {
287 let arg_name = ident.to_string();
289 if let Some(arg_name) = arg_name.strip_prefix('_') {
290 if let Some(correspondence) = registered_names.get(arg_name) {
293 DUPLICATE_UNDERSCORE_ARGUMENT,
296 "`{}` already exists, having another argument having almost the same \
297 name makes code comprehension and documentation more difficult",
303 registered_names.insert(arg_name, arg.pat.span);
309 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
310 if in_external_macro(cx.sess, expr.span) {
313 double_neg::check(cx, expr);
317 impl MiscEarlyLints {
318 fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
319 // We test if first character in snippet is a number, because the snippet could be an expansion
320 // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
321 // Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
322 // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
323 // FIXME: Find a better way to detect those cases.
324 let lit_snip = match snippet_opt(cx, lit.span) {
325 Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
329 if let LitKind::Int(value, lit_int_type) = lit.kind {
330 let suffix = match lit_int_type {
331 LitIntType::Signed(ty) => ty.name_str(),
332 LitIntType::Unsigned(ty) => ty.name_str(),
333 LitIntType::Unsuffixed => "",
335 unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
336 if lit_snip.starts_with("0x") {
337 mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
338 } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
340 } else if value != 0 && lit_snip.starts_with('0') {
341 zero_prefixed_literal::check(cx, lit, &lit_snip);
343 } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
344 let suffix = float_ty.name_str();
345 unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");