11use  clippy_config:: Conf ; 
22use  clippy_utils:: diagnostics:: { span_lint,  span_lint_and_help,  span_lint_hir} ; 
3- use  clippy_utils:: is_bool; 
4- use  clippy_utils:: macros:: span_is_local; 
5- use  clippy_utils:: source:: is_present_in_source; 
63use  clippy_utils:: str_utils:: { camel_case_split,  count_match_end,  count_match_start,  to_camel_case,  to_snake_case} ; 
4+ use  clippy_utils:: { is_bool,  is_from_proc_macro} ; 
75use  rustc_data_structures:: fx:: FxHashSet ; 
8- use  rustc_hir:: { EnumDef ,  FieldDef ,  Item ,  ItemKind ,  OwnerId ,   QPath ,  TyKind ,  Variant ,  VariantData } ; 
6+ use  rustc_hir:: { Body ,   EnumDef ,  FieldDef ,  Item ,  ItemKind ,  QPath ,  TyKind ,   UseKind ,  Variant ,  VariantData } ; 
97use  rustc_lint:: { LateContext ,  LateLintPass } ; 
108use  rustc_session:: impl_lint_pass; 
119use  rustc_span:: symbol:: Symbol ; 
@@ -158,7 +156,8 @@ declare_clippy_lint! {
158156} 
159157
160158pub  struct  ItemNameRepetitions  { 
161-     modules :  Vec < ( Symbol ,  String ,  OwnerId ) > , 
159+     /// The module path the lint pass is in. 
160+ modules :  Vec < ModInfo > , 
162161    enum_threshold :  u64 , 
163162    struct_threshold :  u64 , 
164163    avoid_breaking_exported_api :  bool , 
@@ -167,6 +166,17 @@ pub struct ItemNameRepetitions {
167166    allowed_prefixes :  FxHashSet < String > , 
168167} 
169168
169+ struct  ModInfo  { 
170+     name :  Symbol , 
171+     name_camel :  String , 
172+     /// Does this module have the `pub` visibility modifier. 
173+ is_public :  bool , 
174+     /// How many bodies are between this module and the current lint pass position. 
175+ /// 
176+ /// Only the most recently seen module is updated when entering/exiting a body. 
177+ in_body_count :  u32 , 
178+ } 
179+ 
170180impl  ItemNameRepetitions  { 
171181    pub  fn  new ( conf :  & ' static  Conf )  -> Self  { 
172182        Self  { 
@@ -458,71 +468,109 @@ fn check_enum_tuple_path_match(variant_name: &str, variant_data: VariantData<'_>
458468} 
459469
460470impl  LateLintPass < ' _ >  for  ItemNameRepetitions  { 
461-     fn  check_item_post ( & mut  self ,  _cx :  & LateContext < ' _ > ,  item :  & Item < ' _ > )  { 
462-         let   Some ( _ident )  =  item. kind . ident ( )   else   {   return   } ; 
463- 
464-         let  last =  self . modules . pop ( ) ; 
465-         assert ! ( last . is_some ( ) ) ; 
471+     fn  check_item_post ( & mut  self ,  _ :  & LateContext < ' _ > ,  item :  & Item < ' _ > )  { 
472+         if   matches ! ( item. kind,   ItemKind :: Mod ( .. ) )   { 
473+              let  prev =  self . modules . pop ( ) ; 
474+              debug_assert ! ( prev . is_some ( ) ) ; 
475+         } 
466476    } 
467477
468-     fn  check_item ( & mut  self ,  cx :  & LateContext < ' _ > ,  item :  & Item < ' _ > )  { 
469-         let  Some ( ident)  = item. kind . ident ( )  else  {  return  } ; 
470- 
471-         let  item_name = ident. name . as_str ( ) ; 
472-         let  item_camel = to_camel_case ( item_name) ; 
473-         if  !item. span . from_expansion ( )  && is_present_in_source ( cx,  item. span ) 
474-             && let  [ ..,  ( mod_name,  mod_camel,  mod_owner_id) ]  = & * self . modules 
475-             // constants don't have surrounding modules 
476-             && !mod_camel. is_empty ( ) 
477-         { 
478-             if  mod_name == & ident. name 
479-                 && let  ItemKind :: Mod ( ..)  = item. kind 
480-                 && ( !self . allow_private_module_inception  || cx. tcx . visibility ( mod_owner_id. def_id ) . is_public ( ) ) 
481-             { 
482-                 span_lint ( 
483-                     cx, 
484-                     MODULE_INCEPTION , 
485-                     item. span , 
486-                     "module has the same name as its containing module" , 
487-                 ) ; 
488-             } 
478+     fn  check_body ( & mut  self ,  _:  & LateContext < ' _ > ,  _:  & Body < ' _ > )  { 
479+         if  let  [ ..,  last]  = & mut  * self . modules  { 
480+             last. in_body_count  += 1 ; 
481+         } 
482+     } 
489483
490-             // The `module_name_repetitions` lint should only trigger if the item has the module in its 
491-             // name. Having the same name is only accepted if `allow_exact_repetition` is set to `true`. 
484+     fn  check_body_post ( & mut  self ,  _:  & LateContext < ' _ > ,  _:  & Body < ' _ > )  { 
485+         if  let  [ ..,  last]  = & mut  * self . modules  { 
486+             last. in_body_count  -= 1 ; 
487+         } 
488+     } 
492489
493-             let  both_are_public =
494-                 cx. tcx . visibility ( item. owner_id ) . is_public ( )  && cx. tcx . visibility ( mod_owner_id. def_id ) . is_public ( ) ; 
490+     fn  check_item ( & mut  self ,  cx :  & LateContext < ' _ > ,  item :  & Item < ' _ > )  { 
491+         let  ident = match  item. kind  { 
492+             ItemKind :: Mod ( ident,  _)  => { 
493+                 if  let  [ ..,  prev]  = & * self . modules 
494+                     && prev. name  == ident. name 
495+                     && prev. in_body_count  == 0 
496+                     && ( !self . allow_private_module_inception  || prev. is_public ) 
497+                     && !item. span . from_expansion ( ) 
498+                     && !is_from_proc_macro ( cx,  item) 
499+                 { 
500+                     span_lint ( 
501+                         cx, 
502+                         MODULE_INCEPTION , 
503+                         item. span , 
504+                         "module has the same name as its containing module" , 
505+                     ) ; 
506+                 } 
507+                 ident
508+             } , 
495509
496-             if  both_are_public && !self . allow_exact_repetitions  && item_camel == * mod_camel { 
497-                 span_lint ( 
498-                     cx, 
499-                     MODULE_NAME_REPETITIONS , 
500-                     ident. span , 
501-                     "item name is the same as its containing module's name" , 
502-                 ) ; 
503-             } 
510+             ItemKind :: Enum ( ident,  _,  def)  => { 
511+                 if  !ident. span . in_external_macro ( cx. tcx . sess . source_map ( ) )  { 
512+                     self . check_variants ( cx,  item,  & def) ; 
513+                 } 
514+                 ident
515+             } , 
516+             ItemKind :: Struct ( ident,  _,  data)  => { 
517+                 if  let  VariantData :: Struct  {  fields,  .. }  = data
518+                     && !ident. span . in_external_macro ( cx. tcx . sess . source_map ( ) ) 
519+                 { 
520+                     self . check_fields ( cx,  item,  fields) ; 
521+                 } 
522+                 ident
523+             } , 
504524
505-             let  is_macro = matches ! ( item. kind,  ItemKind :: Macro ( _,  _,  _) ) ; 
506-             if  both_are_public && item_camel. len ( )  > mod_camel. len ( )  && !is_macro { 
507-                 let  matching = count_match_start ( mod_camel,  & item_camel) ; 
508-                 let  rmatching = count_match_end ( mod_camel,  & item_camel) ; 
509-                 let  nchars = mod_camel. chars ( ) . count ( ) ; 
525+             ItemKind :: Const ( ident,  ..) 
526+             | ItemKind :: ExternCrate ( _,  ident) 
527+             | ItemKind :: Fn  {  ident,  .. } 
528+             | ItemKind :: Macro ( ident,  ..) 
529+             | ItemKind :: Static ( _,  ident,  ..) 
530+             | ItemKind :: Trait ( _,  _,  _,  ident,  ..) 
531+             | ItemKind :: TraitAlias ( ident,  ..) 
532+             | ItemKind :: TyAlias ( ident,  ..) 
533+             | ItemKind :: Union ( ident,  ..) 
534+             | ItemKind :: Use ( _,  UseKind :: Single ( ident) )  => ident, 
535+ 
536+             ItemKind :: ForeignMod  {  .. }  | ItemKind :: GlobalAsm  {  .. }  | ItemKind :: Impl ( _)  | ItemKind :: Use ( ..)  => return , 
537+         } ; 
510538
511-                 let  is_word_beginning = |c :  char | c == '_'  || c. is_uppercase ( )  || c. is_numeric ( ) ; 
539+         let  item_name = ident. name . as_str ( ) ; 
540+         let  item_camel = to_camel_case ( item_name) ; 
512541
513-                 if  matching. char_count  == nchars { 
514-                     match  item_camel. chars ( ) . nth ( nchars)  { 
515-                         Some ( c)  if  is_word_beginning ( c)  => span_lint ( 
542+         if  let  [ ..,  prev]  = & * self . modules 
543+             && prev. is_public 
544+             && prev. in_body_count  == 0 
545+             && !item. span . from_expansion ( ) 
546+             && !matches ! ( item. kind,  ItemKind :: Macro ( ..) ) 
547+             && cx. tcx . visibility ( item. owner_id ) . is_public ( ) 
548+         { 
549+             if  !self . allow_exact_repetitions  && item_camel == prev. name_camel  { 
550+                 if  !is_from_proc_macro ( cx,  item)  { 
551+                     span_lint ( 
552+                         cx, 
553+                         MODULE_NAME_REPETITIONS , 
554+                         ident. span , 
555+                         "item name is the same as its containing module's name" , 
556+                     ) ; 
557+                 } 
558+             }  else  if  item_camel. len ( )  > prev. name_camel . len ( )  { 
559+                 if  let  Some ( s)  = item_camel. strip_prefix ( & prev. name_camel ) 
560+                     && let  Some ( c)  = s. chars ( ) . next ( ) 
561+                     && ( c == '_'  || c. is_uppercase ( )  || c. is_numeric ( ) ) 
562+                 { 
563+                     if  !is_from_proc_macro ( cx,  item)  { 
564+                         span_lint ( 
516565                            cx, 
517566                            MODULE_NAME_REPETITIONS , 
518567                            ident. span , 
519568                            "item name starts with its containing module's name" , 
520-                         ) , 
521-                         _ => ( ) , 
569+                         ) ; 
522570                    } 
523-                 } 
524-                 if  rmatching . char_count  == nchars 
525-                     && !self . is_allowed_prefix ( & item_camel [ ..item_camel . len ( )  - rmatching . byte_count ] ) 
571+                 }   else   if   let   Some ( s )  = item_camel . strip_suffix ( & prev . name_camel ) 
572+                     && ! self . is_allowed_prefix ( s ) 
573+                     && !is_from_proc_macro ( cx ,  item ) 
526574                { 
527575                    span_lint ( 
528576                        cx, 
@@ -534,17 +582,13 @@ impl LateLintPass<'_> for ItemNameRepetitions {
534582            } 
535583        } 
536584
537-         if  span_is_local ( item. span )  { 
538-             match  item. kind  { 
539-                 ItemKind :: Enum ( _,  _,  def)  => { 
540-                     self . check_variants ( cx,  item,  & def) ; 
541-                 } , 
542-                 ItemKind :: Struct ( _,  _,  VariantData :: Struct  {  fields,  .. } )  => { 
543-                     self . check_fields ( cx,  item,  fields) ; 
544-                 } , 
545-                 _ => ( ) , 
546-             } 
585+         if  matches ! ( item. kind,  ItemKind :: Mod ( ..) )  { 
586+             self . modules . push ( ModInfo  { 
587+                 name :  ident. name , 
588+                 name_camel :  item_camel, 
589+                 is_public :  cx. tcx . visibility ( item. owner_id ) . is_public ( ) , 
590+                 in_body_count :  0 , 
591+             } ) ; 
547592        } 
548-         self . modules . push ( ( ident. name ,  item_camel,  item. owner_id ) ) ; 
549593    } 
550594} 
0 commit comments