Skip to content

Commit 436efbb

Browse files
Fix min_ident_chars: ignore on trait impl. (#15275)
fixes #13396 changelog: [`min_ident_chars`]: ignore lint when implementing a trait, to respect [`renamed_function_params`]
2 parents c7dd98c + e8db4aa commit 436efbb

File tree

3 files changed

+205
-3
lines changed

3 files changed

+205
-3
lines changed

clippy_lints/src/min_ident_chars.rs

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ use clippy_utils::is_from_proc_macro;
44
use rustc_data_structures::fx::FxHashSet;
55
use rustc_hir::def::{DefKind, Res};
66
use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item};
7-
use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath};
7+
use rustc_hir::{
8+
GenericParamKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem,
9+
UsePath,
10+
};
811
use rustc_lint::{LateContext, LateLintPass, LintContext};
912
use rustc_session::impl_lint_pass;
10-
use rustc_span::Span;
13+
use rustc_span::symbol::Ident;
14+
use rustc_span::{Span, Symbol};
1115
use std::borrow::Cow;
1216

1317
declare_clippy_lint! {
@@ -32,6 +36,10 @@ declare_clippy_lint! {
3236
/// let title = movie.title;
3337
/// }
3438
/// ```
39+
///
40+
/// ### Limitations
41+
/// Trait implementations which use the same function or parameter name as the trait declaration will
42+
/// not be warned about, even if the name is below the configured limit.
3543
#[clippy::version = "1.72.0"]
3644
pub MIN_IDENT_CHARS,
3745
restriction,
@@ -76,6 +84,18 @@ impl LateLintPass<'_> for MinIdentChars {
7684
return;
7785
}
7886

87+
// If the function is declared but not defined in a trait, check_pat isn't called so we need to
88+
// check this explicitly
89+
if matches!(&item.kind, rustc_hir::TraitItemKind::Fn(_, _)) {
90+
let param_names = cx.tcx.fn_arg_idents(item.owner_id.to_def_id());
91+
for ident in param_names.iter().flatten() {
92+
let str = ident.as_str();
93+
if self.is_ident_too_short(cx, str, ident.span) {
94+
emit_min_ident_chars(self, cx, str, ident.span);
95+
}
96+
}
97+
}
98+
7999
walk_trait_item(&mut IdentVisitor { conf: self, cx }, item);
80100
}
81101

@@ -84,6 +104,7 @@ impl LateLintPass<'_> for MinIdentChars {
84104
if let PatKind::Binding(_, _, ident, ..) = pat.kind
85105
&& let str = ident.as_str()
86106
&& self.is_ident_too_short(cx, str, ident.span)
107+
&& is_not_in_trait_impl(cx, pat, ident)
87108
{
88109
emit_min_ident_chars(self, cx, str, ident.span);
89110
}
@@ -118,6 +139,11 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
118139

119140
let str = ident.as_str();
120141
if conf.is_ident_too_short(cx, str, ident.span) {
142+
// Check whether the node is part of a `impl` for a trait.
143+
if matches!(cx.tcx.parent_hir_node(hir_id), Node::TraitRef(_)) {
144+
return;
145+
}
146+
121147
// Check whether the node is part of a `use` statement. We don't want to emit a warning if the user
122148
// has no control over the type.
123149
let usenode = opt_as_use_node(node).or_else(|| {
@@ -201,3 +227,52 @@ fn opt_as_use_node(node: Node<'_>) -> Option<&'_ UsePath<'_>> {
201227
None
202228
}
203229
}
230+
231+
/// Check if a pattern is a function param in an impl block for a trait and that the param name is
232+
/// the same than in the trait definition.
233+
fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>, ident: Ident) -> bool {
234+
let parent_node = cx.tcx.parent_hir_node(pat.hir_id);
235+
if !matches!(parent_node, Node::Param(_)) {
236+
return true;
237+
}
238+
239+
for (_, parent_node) in cx.tcx.hir_parent_iter(pat.hir_id) {
240+
if let Node::ImplItem(impl_item) = parent_node
241+
&& matches!(impl_item.kind, ImplItemKind::Fn(_, _))
242+
{
243+
let impl_parent_node = cx.tcx.parent_hir_node(impl_item.hir_id());
244+
if let Node::Item(parent_item) = impl_parent_node
245+
&& let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = &parent_item.kind
246+
&& let Some(name) = get_param_name(impl_item, cx, ident)
247+
{
248+
return name != ident.name;
249+
}
250+
251+
return true;
252+
}
253+
}
254+
255+
true
256+
}
257+
258+
fn get_param_name(impl_item: &ImplItem<'_>, cx: &LateContext<'_>, ident: Ident) -> Option<Symbol> {
259+
if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
260+
let trait_param_names = cx.tcx.fn_arg_idents(trait_item_def_id);
261+
262+
let ImplItemKind::Fn(_, body_id) = impl_item.kind else {
263+
return None;
264+
};
265+
266+
if let Some(param_index) = cx
267+
.tcx
268+
.hir_body_param_idents(body_id)
269+
.position(|param_ident| param_ident.is_some_and(|param_ident| param_ident.span == ident.span))
270+
&& let Some(trait_param_name) = trait_param_names.get(param_index)
271+
&& let Some(trait_param_ident) = trait_param_name
272+
{
273+
return Some(trait_param_ident.name);
274+
}
275+
}
276+
277+
None
278+
}

tests/ui/min_ident_chars.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,52 @@ fn wrong_pythagoras(a: f32, b: f32) -> f32 {
124124
mod issue_11163 {
125125
struct Array<T, const N: usize>([T; N]);
126126
}
127+
128+
struct Issue13396;
129+
130+
impl core::fmt::Display for Issue13396 {
131+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
132+
write!(f, "Issue13396")
133+
}
134+
}
135+
136+
impl core::fmt::Debug for Issue13396 {
137+
fn fmt(&self, g: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
138+
//~^ min_ident_chars
139+
write!(g, "Issue13396")
140+
}
141+
}
142+
143+
fn issue13396() {
144+
let a = |f: i8| f;
145+
//~^ min_ident_chars
146+
//~| min_ident_chars
147+
}
148+
149+
trait D {
150+
//~^ min_ident_chars
151+
fn f(g: i32);
152+
//~^ min_ident_chars
153+
//~| min_ident_chars
154+
fn long(long: i32);
155+
156+
fn g(arg: i8) {
157+
//~^ min_ident_chars
158+
fn c(d: u8) {}
159+
//~^ min_ident_chars
160+
//~| min_ident_chars
161+
}
162+
}
163+
164+
impl D for Issue13396 {
165+
fn f(g: i32) {
166+
fn h() {}
167+
//~^ min_ident_chars
168+
fn inner(a: i32) {}
169+
//~^ min_ident_chars
170+
let a = |f: String| f;
171+
//~^ min_ident_chars
172+
//~| min_ident_chars
173+
}
174+
fn long(long: i32) {}
175+
}

tests/ui/min_ident_chars.stderr

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,83 @@ error: this ident consists of a single char
193193
LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
194194
| ^
195195

196-
error: aborting due to 32 previous errors
196+
error: this ident consists of a single char
197+
--> tests/ui/min_ident_chars.rs:137:19
198+
|
199+
LL | fn fmt(&self, g: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200+
| ^
201+
202+
error: this ident consists of a single char
203+
--> tests/ui/min_ident_chars.rs:144:14
204+
|
205+
LL | let a = |f: i8| f;
206+
| ^
207+
208+
error: this ident consists of a single char
209+
--> tests/ui/min_ident_chars.rs:144:9
210+
|
211+
LL | let a = |f: i8| f;
212+
| ^
213+
214+
error: this ident consists of a single char
215+
--> tests/ui/min_ident_chars.rs:149:7
216+
|
217+
LL | trait D {
218+
| ^
219+
220+
error: this ident consists of a single char
221+
--> tests/ui/min_ident_chars.rs:151:10
222+
|
223+
LL | fn f(g: i32);
224+
| ^
225+
226+
error: this ident consists of a single char
227+
--> tests/ui/min_ident_chars.rs:151:8
228+
|
229+
LL | fn f(g: i32);
230+
| ^
231+
232+
error: this ident consists of a single char
233+
--> tests/ui/min_ident_chars.rs:156:8
234+
|
235+
LL | fn g(arg: i8) {
236+
| ^
237+
238+
error: this ident consists of a single char
239+
--> tests/ui/min_ident_chars.rs:158:12
240+
|
241+
LL | fn c(d: u8) {}
242+
| ^
243+
244+
error: this ident consists of a single char
245+
--> tests/ui/min_ident_chars.rs:158:14
246+
|
247+
LL | fn c(d: u8) {}
248+
| ^
249+
250+
error: this ident consists of a single char
251+
--> tests/ui/min_ident_chars.rs:166:12
252+
|
253+
LL | fn h() {}
254+
| ^
255+
256+
error: this ident consists of a single char
257+
--> tests/ui/min_ident_chars.rs:168:18
258+
|
259+
LL | fn inner(a: i32) {}
260+
| ^
261+
262+
error: this ident consists of a single char
263+
--> tests/ui/min_ident_chars.rs:170:18
264+
|
265+
LL | let a = |f: String| f;
266+
| ^
267+
268+
error: this ident consists of a single char
269+
--> tests/ui/min_ident_chars.rs:170:13
270+
|
271+
LL | let a = |f: String| f;
272+
| ^
273+
274+
error: aborting due to 45 previous errors
197275

0 commit comments

Comments
 (0)