@@ -4,10 +4,14 @@ use clippy_utils::is_from_proc_macro;
44use rustc_data_structures:: fx:: FxHashSet ;
55use rustc_hir:: def:: { DefKind , Res } ;
66use 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+ } ;
811use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
912use rustc_session:: impl_lint_pass;
10- use rustc_span:: Span ;
13+ use rustc_span:: symbol:: Ident ;
14+ use rustc_span:: { Span , Symbol } ;
1115use std:: borrow:: Cow ;
1216
1317declare_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+ }
0 commit comments