Skip to content

Commit 763420c

Browse files
authored
extract duplicate_underscore_argument, and move it into functions (#15508)
Basically continuing the work in rust-lang/rust-clippy#6680 Honestly I think the lint could also be run on (trait) impl items, but I didn't implement that because of the feature freeze. If that is deemed okay to add in this PR though, I could happily do so. changelog: none
2 parents 9a2076e + 54c52e2 commit 763420c

File tree

5 files changed

+73
-58
lines changed

5 files changed

+73
-58
lines changed

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
187187
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
188188
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
189189
crate::functions::DOUBLE_MUST_USE_INFO,
190+
crate::functions::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
190191
crate::functions::IMPL_TRAIT_IN_PARAMS_INFO,
191192
crate::functions::MISNAMED_GETTERS_INFO,
192193
crate::functions::MUST_USE_CANDIDATE_INFO,
@@ -505,7 +506,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
505506
crate::misc::USED_UNDERSCORE_BINDING_INFO,
506507
crate::misc::USED_UNDERSCORE_ITEMS_INFO,
507508
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
508-
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
509509
crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
510510
crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO,
511511
crate::misc_early::REDUNDANT_PATTERN_INFO,
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use rustc_ast::PatKind;
3+
use rustc_ast::visit::FnKind;
4+
use rustc_data_structures::fx::FxHashMap;
5+
use rustc_lint::EarlyContext;
6+
use rustc_span::Span;
7+
8+
use super::DUPLICATE_UNDERSCORE_ARGUMENT;
9+
10+
pub(super) fn check(cx: &EarlyContext<'_>, fn_kind: FnKind<'_>) {
11+
let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
12+
13+
for arg in &fn_kind.decl().inputs {
14+
if let PatKind::Ident(_, ident, None) = arg.pat.kind {
15+
let arg_name = ident.to_string();
16+
17+
if let Some(arg_name) = arg_name.strip_prefix('_') {
18+
if let Some(correspondence) = registered_names.get(arg_name) {
19+
span_lint(
20+
cx,
21+
DUPLICATE_UNDERSCORE_ARGUMENT,
22+
*correspondence,
23+
format!(
24+
"`{arg_name}` already exists, having another argument having almost the same \
25+
name makes code comprehension and documentation more difficult"
26+
),
27+
);
28+
}
29+
} else {
30+
registered_names.insert(arg_name, arg.pat.span);
31+
}
32+
}
33+
}
34+
}

clippy_lints/src/functions/mod.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod duplicate_underscore_argument;
12
mod impl_trait_in_params;
23
mod misnamed_getters;
34
mod must_use;
@@ -11,14 +12,38 @@ mod too_many_lines;
1112
use clippy_config::Conf;
1213
use clippy_utils::msrvs::Msrv;
1314
use clippy_utils::paths::{PathNS, lookup_path_str};
15+
use rustc_ast::{self as ast, visit};
1416
use rustc_hir as hir;
1517
use rustc_hir::intravisit;
16-
use rustc_lint::{LateContext, LateLintPass};
18+
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
1719
use rustc_middle::ty::TyCtxt;
18-
use rustc_session::impl_lint_pass;
20+
use rustc_session::{declare_lint_pass, impl_lint_pass};
1921
use rustc_span::Span;
2022
use rustc_span::def_id::{DefIdSet, LocalDefId};
2123

24+
declare_clippy_lint! {
25+
/// ### What it does
26+
/// Checks for function arguments having the similar names
27+
/// differing by an underscore.
28+
///
29+
/// ### Why is this bad?
30+
/// It affects code readability.
31+
///
32+
/// ### Example
33+
/// ```no_run
34+
/// fn foo(a: i32, _a: i32) {}
35+
/// ```
36+
///
37+
/// Use instead:
38+
/// ```no_run
39+
/// fn bar(a: i32, _b: i32) {}
40+
/// ```
41+
#[clippy::version = "pre 1.29.0"]
42+
pub DUPLICATE_UNDERSCORE_ARGUMENT,
43+
style,
44+
"function arguments having names which only differ by an underscore"
45+
}
46+
2247
declare_clippy_lint! {
2348
/// ### What it does
2449
/// Checks for functions with too many parameters.
@@ -448,6 +473,14 @@ declare_clippy_lint! {
448473
"function signature uses `&Option<T>` instead of `Option<&T>`"
449474
}
450475

476+
declare_lint_pass!(EarlyFunctions => [DUPLICATE_UNDERSCORE_ARGUMENT]);
477+
478+
impl EarlyLintPass for EarlyFunctions {
479+
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: visit::FnKind<'_>, _: Span, _: ast::NodeId) {
480+
duplicate_underscore_argument::check(cx, fn_kind);
481+
}
482+
}
483+
451484
pub struct Functions {
452485
too_many_arguments_threshold: u64,
453486
too_many_lines_threshold: u64,

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
556556
store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
557557
store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
558558
store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf)));
559+
store.register_early_pass(|| Box::new(functions::EarlyFunctions));
559560
store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf)));
560561
store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf)));
561562
store.register_early_pass(move || Box::new(doc::Documentation::new(conf)));

clippy_lints/src/misc_early/mod.rs

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@ mod unneeded_field_pattern;
77
mod unneeded_wildcard_pattern;
88
mod zero_prefixed_literal;
99

10-
use clippy_utils::diagnostics::span_lint;
1110
use clippy_utils::source::snippet_opt;
12-
use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
11+
use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, Pat};
1312
use rustc_ast::token;
14-
use rustc_ast::visit::FnKind;
15-
use rustc_data_structures::fx::FxHashMap;
1613
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
1714
use rustc_session::declare_lint_pass;
1815
use rustc_span::Span;
@@ -60,29 +57,6 @@ declare_clippy_lint! {
6057
"struct fields bound to a wildcard instead of using `..`"
6158
}
6259

63-
declare_clippy_lint! {
64-
/// ### What it does
65-
/// Checks for function arguments having the similar names
66-
/// differing by an underscore.
67-
///
68-
/// ### Why is this bad?
69-
/// It affects code readability.
70-
///
71-
/// ### Example
72-
/// ```no_run
73-
/// fn foo(a: i32, _a: i32) {}
74-
/// ```
75-
///
76-
/// Use instead:
77-
/// ```no_run
78-
/// fn bar(a: i32, _b: i32) {}
79-
/// ```
80-
#[clippy::version = "pre 1.29.0"]
81-
pub DUPLICATE_UNDERSCORE_ARGUMENT,
82-
style,
83-
"function arguments having names which only differ by an underscore"
84-
}
85-
8660
declare_clippy_lint! {
8761
/// ### What it does
8862
/// Warns on hexadecimal literals with mixed-case letter
@@ -330,7 +304,6 @@ declare_clippy_lint! {
330304

331305
declare_lint_pass!(MiscEarlyLints => [
332306
UNNEEDED_FIELD_PATTERN,
333-
DUPLICATE_UNDERSCORE_ARGUMENT,
334307
MIXED_CASE_HEX_LITERALS,
335308
UNSEPARATED_LITERAL_SUFFIX,
336309
SEPARATED_LITERAL_SUFFIX,
@@ -359,32 +332,6 @@ impl EarlyLintPass for MiscEarlyLints {
359332
unneeded_wildcard_pattern::check(cx, pat);
360333
}
361334

362-
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
363-
let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
364-
365-
for arg in &fn_kind.decl().inputs {
366-
if let PatKind::Ident(_, ident, None) = arg.pat.kind {
367-
let arg_name = ident.to_string();
368-
369-
if let Some(arg_name) = arg_name.strip_prefix('_') {
370-
if let Some(correspondence) = registered_names.get(arg_name) {
371-
span_lint(
372-
cx,
373-
DUPLICATE_UNDERSCORE_ARGUMENT,
374-
*correspondence,
375-
format!(
376-
"`{arg_name}` already exists, having another argument having almost the same \
377-
name makes code comprehension and documentation more difficult"
378-
),
379-
);
380-
}
381-
} else {
382-
registered_names.insert(arg_name, arg.pat.span);
383-
}
384-
}
385-
}
386-
}
387-
388335
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
389336
if expr.span.in_external_macro(cx.sess().source_map()) {
390337
return;
@@ -404,7 +351,7 @@ impl MiscEarlyLints {
404351
// See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
405352
// FIXME: Find a better way to detect those cases.
406353
let lit_snip = match snippet_opt(cx, span) {
407-
Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip,
354+
Some(snip) if snip.starts_with(|c: char| c.is_ascii_digit()) => snip,
408355
_ => return,
409356
};
410357

0 commit comments

Comments
 (0)