extract duplicate_underscore_argument, and move it into functions

misc: use `str::starts_with`

extract `duplicate_underscore_argument` into a module

move it to `functions`
This commit is contained in:
Ada Alakbarova
2025-08-17 23:00:32 +02:00
parent 9a2076ed87
commit 54c52e208a
5 changed files with 73 additions and 58 deletions
+1 -1
View File
@@ -187,6 +187,7 @@
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
crate::functions::DOUBLE_MUST_USE_INFO,
crate::functions::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
crate::functions::IMPL_TRAIT_IN_PARAMS_INFO,
crate::functions::MISNAMED_GETTERS_INFO,
crate::functions::MUST_USE_CANDIDATE_INFO,
@@ -505,7 +506,6 @@
crate::misc::USED_UNDERSCORE_BINDING_INFO,
crate::misc::USED_UNDERSCORE_ITEMS_INFO,
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO,
crate::misc_early::REDUNDANT_PATTERN_INFO,
@@ -0,0 +1,34 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::PatKind;
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::EarlyContext;
use rustc_span::Span;
use super::DUPLICATE_UNDERSCORE_ARGUMENT;
pub(super) fn check(cx: &EarlyContext<'_>, fn_kind: FnKind<'_>) {
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);
}
}
}
}
+35 -2
View File
@@ -1,3 +1,4 @@
mod duplicate_underscore_argument;
mod impl_trait_in_params;
mod misnamed_getters;
mod must_use;
@@ -11,14 +12,38 @@
use clippy_config::Conf;
use clippy_utils::msrvs::Msrv;
use clippy_utils::paths::{PathNS, lookup_path_str};
use rustc_ast::{self as ast, visit};
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_lint::{LateContext, LateLintPass};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
use rustc_session::{declare_lint_pass, impl_lint_pass};
use rustc_span::Span;
use rustc_span::def_id::{DefIdSet, LocalDefId};
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
/// Checks for functions with too many parameters.
@@ -448,6 +473,14 @@
"function signature uses `&Option<T>` instead of `Option<&T>`"
}
declare_lint_pass!(EarlyFunctions => [DUPLICATE_UNDERSCORE_ARGUMENT]);
impl EarlyLintPass for EarlyFunctions {
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: visit::FnKind<'_>, _: Span, _: ast::NodeId) {
duplicate_underscore_argument::check(cx, fn_kind);
}
}
pub struct Functions {
too_many_arguments_threshold: u64,
too_many_lines_threshold: u64,
+1
View File
@@ -556,6 +556,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf)));
store.register_early_pass(|| Box::new(functions::EarlyFunctions));
store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf)));
store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf)));
store.register_early_pass(move || Box::new(doc::Documentation::new(conf)));
+2 -55
View File
@@ -7,12 +7,9 @@
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::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, Pat};
use rustc_ast::token;
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
@@ -60,29 +57,6 @@
"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
/// Warns on hexadecimal literals with mixed-case letter
@@ -330,7 +304,6 @@
declare_lint_pass!(MiscEarlyLints => [
UNNEEDED_FIELD_PATTERN,
DUPLICATE_UNDERSCORE_ARGUMENT,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
SEPARATED_LITERAL_SUFFIX,
@@ -359,32 +332,6 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &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 expr.span.in_external_macro(cx.sess().source_map()) {
return;
@@ -404,7 +351,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
// 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().is_some_and(|c| c.is_ascii_digit()) => snip,
Some(snip) if snip.starts_with(|c: char| c.is_ascii_digit()) => snip,
_ => return,
};