@@ -5,11 +5,13 @@ use rustc_data_structures::fx::FxHashSet;
5
5
use rustc_hir:: def:: { DefKind , Res } ;
6
6
use rustc_hir:: intravisit:: { Visitor , walk_item, walk_trait_item} ;
7
7
use rustc_hir:: {
8
- GenericParamKind , HirId , Impl , ImplItemKind , Item , ItemKind , ItemLocalId , Node , Pat , PatKind , TraitItem , UsePath ,
8
+ GenericParamKind , HirId , Impl , ImplItem , ImplItemKind , Item , ItemKind , ItemLocalId , Node , Pat , PatKind , TraitItem ,
9
+ UsePath ,
9
10
} ;
10
11
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
11
12
use rustc_session:: impl_lint_pass;
12
- use rustc_span:: Span ;
13
+ use rustc_span:: symbol:: Ident ;
14
+ use rustc_span:: { Span , Symbol } ;
13
15
use std:: borrow:: Cow ;
14
16
15
17
declare_clippy_lint ! {
@@ -34,6 +36,10 @@ declare_clippy_lint! {
34
36
/// let title = movie.title;
35
37
/// }
36
38
/// ```
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.
37
43
#[ clippy:: version = "1.72.0" ]
38
44
pub MIN_IDENT_CHARS ,
39
45
restriction,
@@ -78,6 +84,18 @@ impl LateLintPass<'_> for MinIdentChars {
78
84
return ;
79
85
}
80
86
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
+
81
99
walk_trait_item ( & mut IdentVisitor { conf : self , cx } , item) ;
82
100
}
83
101
@@ -86,7 +104,7 @@ impl LateLintPass<'_> for MinIdentChars {
86
104
if let PatKind :: Binding ( _, _, ident, ..) = pat. kind
87
105
&& let str = ident. as_str ( )
88
106
&& self . is_ident_too_short ( cx, str, ident. span )
89
- && is_not_in_trait_impl ( cx, pat)
107
+ && is_not_in_trait_impl ( cx, pat, ident )
90
108
{
91
109
emit_min_ident_chars ( self , cx, str, ident. span ) ;
92
110
}
@@ -121,6 +139,11 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
121
139
122
140
let str = ident. as_str ( ) ;
123
141
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
+
124
147
// Check whether the node is part of a `use` statement. We don't want to emit a warning if the user
125
148
// has no control over the type.
126
149
let usenode = opt_as_use_node ( node) . or_else ( || {
@@ -205,8 +228,9 @@ fn opt_as_use_node(node: Node<'_>) -> Option<&'_ UsePath<'_>> {
205
228
}
206
229
}
207
230
208
- /// Check if a pattern is a function param in an impl block for a trait.
209
- fn is_not_in_trait_impl ( cx : & LateContext < ' _ > , pat : & Pat < ' _ > ) -> bool {
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 {
210
234
let parent_node = cx. tcx . parent_hir_node ( pat. hir_id ) ;
211
235
if !matches ! ( parent_node, Node :: Param ( _) ) {
212
236
return true ;
@@ -219,12 +243,36 @@ fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
219
243
let impl_parent_node = cx. tcx . parent_hir_node ( impl_item. hir_id ( ) ) ;
220
244
if let Node :: Item ( parent_item) = impl_parent_node
221
245
&& let ItemKind :: Impl ( Impl { of_trait : Some ( _) , .. } ) = & parent_item. kind
246
+ && let Some ( name) = get_param_name ( impl_item, cx, ident)
222
247
{
223
- return false ;
248
+ return name != ident . name ;
224
249
}
250
+
225
251
return true ;
226
252
}
227
253
}
228
254
229
255
true
230
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
+ }
0 commit comments