@@ -4,10 +4,14 @@ use clippy_utils::is_from_proc_macro;
4
4
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
- 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
+ } ;
8
11
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
9
12
use rustc_session:: impl_lint_pass;
10
- use rustc_span:: Span ;
13
+ use rustc_span:: symbol:: Ident ;
14
+ use rustc_span:: { Span , Symbol } ;
11
15
use std:: borrow:: Cow ;
12
16
13
17
declare_clippy_lint ! {
@@ -32,6 +36,10 @@ declare_clippy_lint! {
32
36
/// let title = movie.title;
33
37
/// }
34
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.
35
43
#[ clippy:: version = "1.72.0" ]
36
44
pub MIN_IDENT_CHARS ,
37
45
restriction,
@@ -76,6 +84,18 @@ impl LateLintPass<'_> for MinIdentChars {
76
84
return ;
77
85
}
78
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
+
79
99
walk_trait_item ( & mut IdentVisitor { conf : self , cx } , item) ;
80
100
}
81
101
@@ -84,6 +104,7 @@ impl LateLintPass<'_> for MinIdentChars {
84
104
if let PatKind :: Binding ( _, _, ident, ..) = pat. kind
85
105
&& let str = ident. as_str ( )
86
106
&& self . is_ident_too_short ( cx, str, ident. span )
107
+ && is_not_in_trait_impl ( cx, pat, ident)
87
108
{
88
109
emit_min_ident_chars ( self , cx, str, ident. span ) ;
89
110
}
@@ -118,6 +139,11 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
118
139
119
140
let str = ident. as_str ( ) ;
120
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
+
121
147
// Check whether the node is part of a `use` statement. We don't want to emit a warning if the user
122
148
// has no control over the type.
123
149
let usenode = opt_as_use_node ( node) . or_else ( || {
@@ -201,3 +227,52 @@ fn opt_as_use_node(node: Node<'_>) -> Option<&'_ UsePath<'_>> {
201
227
None
202
228
}
203
229
}
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
+ }
0 commit comments