@@ -5,11 +5,13 @@ use rustc_data_structures::fx::FxHashSet;
55use rustc_hir:: def:: { DefKind , Res } ;
66use rustc_hir:: intravisit:: { Visitor , walk_item, walk_trait_item} ;
77use 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 ,
910} ;
1011use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1112use rustc_session:: impl_lint_pass;
12- use rustc_span:: Span ;
13+ use rustc_span:: symbol:: Ident ;
14+ use rustc_span:: { Span , Symbol } ;
1315use std:: borrow:: Cow ;
1416
1517declare_clippy_lint ! {
@@ -34,6 +36,10 @@ declare_clippy_lint! {
3436 /// let title = movie.title;
3537 /// }
3638 /// ```
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.
3743 #[ clippy:: version = "1.72.0" ]
3844 pub MIN_IDENT_CHARS ,
3945 restriction,
@@ -78,6 +84,18 @@ impl LateLintPass<'_> for MinIdentChars {
7884 return ;
7985 }
8086
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+
8199 walk_trait_item ( & mut IdentVisitor { conf : self , cx } , item) ;
82100 }
83101
@@ -86,7 +104,7 @@ impl LateLintPass<'_> for MinIdentChars {
86104 if let PatKind :: Binding ( _, _, ident, ..) = pat. kind
87105 && let str = ident. as_str ( )
88106 && 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 )
90108 {
91109 emit_min_ident_chars ( self , cx, str, ident. span ) ;
92110 }
@@ -121,6 +139,11 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
121139
122140 let str = ident. as_str ( ) ;
123141 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+
124147 // Check whether the node is part of a `use` statement. We don't want to emit a warning if the user
125148 // has no control over the type.
126149 let usenode = opt_as_use_node ( node) . or_else ( || {
@@ -205,8 +228,9 @@ fn opt_as_use_node(node: Node<'_>) -> Option<&'_ UsePath<'_>> {
205228 }
206229}
207230
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 {
210234 let parent_node = cx. tcx . parent_hir_node ( pat. hir_id ) ;
211235 if !matches ! ( parent_node, Node :: Param ( _) ) {
212236 return true ;
@@ -219,12 +243,36 @@ fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
219243 let impl_parent_node = cx. tcx . parent_hir_node ( impl_item. hir_id ( ) ) ;
220244 if let Node :: Item ( parent_item) = impl_parent_node
221245 && let ItemKind :: Impl ( Impl { of_trait : Some ( _) , .. } ) = & parent_item. kind
246+ && let Some ( name) = get_param_name ( impl_item, cx, ident)
222247 {
223- return false ;
248+ return name != ident . name ;
224249 }
250+
225251 return true ;
226252 }
227253 }
228254
229255 true
230256}
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