11use  rustc_abi:: ExternAbi ; 
22use  rustc_attr_data_structures:: { AttributeKind ,  ReprAttr ,  find_attr} ; 
33use  rustc_attr_parsing:: AttributeParser ; 
4+ use  rustc_errors:: Applicability ; 
45use  rustc_hir:: def:: { DefKind ,  Res } ; 
5- use  rustc_hir:: intravisit:: FnKind ; 
6+ use  rustc_hir:: def_id:: DefId ; 
7+ use  rustc_hir:: intravisit:: { FnKind ,  Visitor } ; 
68use  rustc_hir:: { AttrArgs ,  AttrItem ,  Attribute ,  GenericParamKind ,  PatExprKind ,  PatKind } ; 
9+ use  rustc_middle:: hir:: nested_filter:: All ; 
710use  rustc_middle:: ty; 
811use  rustc_session:: config:: CrateType ; 
912use  rustc_session:: { declare_lint,  declare_lint_pass} ; 
@@ -13,7 +16,7 @@ use {rustc_ast as ast, rustc_hir as hir};
1316
1417use  crate :: lints:: { 
1518    NonCamelCaseType ,  NonCamelCaseTypeSub ,  NonSnakeCaseDiag ,  NonSnakeCaseDiagSub , 
16-     NonUpperCaseGlobal ,  NonUpperCaseGlobalSub , 
19+     NonUpperCaseGlobal ,  NonUpperCaseGlobalSub ,   NonUpperCaseGlobalSubTool , 
1720} ; 
1821use  crate :: { EarlyContext ,  EarlyLintPass ,  LateContext ,  LateLintPass ,  LintContext } ; 
1922
@@ -493,22 +496,82 @@ declare_lint! {
493496declare_lint_pass ! ( NonUpperCaseGlobals  => [ NON_UPPER_CASE_GLOBALS ] ) ; 
494497
495498impl  NonUpperCaseGlobals  { 
496-     fn  check_upper_case ( cx :  & LateContext < ' _ > ,  sort :  & str ,  ident :  & Ident )  { 
499+     fn  check_upper_case ( cx :  & LateContext < ' _ > ,  sort :  & str ,  did :   Option < LocalDefId > ,   ident :  & Ident )  { 
497500        let  name = ident. name . as_str ( ) ; 
498501        if  name. chars ( ) . any ( |c| c. is_lowercase ( ) )  { 
499502            let  uc = NonSnakeCase :: to_snake_case ( name) . to_uppercase ( ) ; 
503+ 
504+             // If the item is exported, suggesting changing it's name would be breaking-change 
505+             // and could break users without a "nice" applicable fix, so let's avoid it. 
506+             let  can_change_usages = if  let  Some ( did)  = did { 
507+                 !cx. tcx . effective_visibilities ( ( ) ) . is_exported ( did) 
508+             }  else  { 
509+                 false 
510+             } ; 
511+ 
500512            // We cannot provide meaningful suggestions 
501513            // if the characters are in the category of "Lowercase Letter". 
502514            let  sub = if  * name != uc { 
503-                 NonUpperCaseGlobalSub :: Suggestion  {  span :  ident. span ,  replace :  uc } 
515+                 NonUpperCaseGlobalSub :: Suggestion  { 
516+                     span :  ident. span , 
517+                     replace :  uc. clone ( ) , 
518+                     applicability :  if  can_change_usages { 
519+                         Applicability :: MachineApplicable 
520+                     }  else  { 
521+                         Applicability :: MaybeIncorrect 
522+                     } , 
523+                 } 
504524            }  else  { 
505525                NonUpperCaseGlobalSub :: Label  {  span :  ident. span  } 
506526            } ; 
507-             cx. emit_span_lint ( 
508-                 NON_UPPER_CASE_GLOBALS , 
509-                 ident. span , 
510-                 NonUpperCaseGlobal  {  sort,  name,  sub } , 
511-             ) ; 
527+ 
528+             struct  UsageCollector < ' a ,  ' tcx >  { 
529+                 cx :  & ' tcx  LateContext < ' a > , 
530+                 did :  DefId , 
531+                 collected :  Vec < Span > , 
532+             } 
533+ 
534+             impl < ' v ,  ' tcx >  Visitor < ' v >  for  UsageCollector < ' v ,  ' tcx >  { 
535+                 type  NestedFilter  = All ; 
536+ 
537+                 fn  maybe_tcx ( & mut  self )  -> Self :: MaybeTyCtxt  { 
538+                     self . cx . tcx 
539+                 } 
540+ 
541+                 fn  visit_path ( 
542+                     & mut  self , 
543+                     path :  & rustc_hir:: Path < ' v > , 
544+                     _id :  rustc_hir:: HirId , 
545+                 )  -> Self :: Result  { 
546+                     if  let  Some ( final_seg)  = path. segments . last ( ) 
547+                         && final_seg. res . opt_def_id ( )  == Some ( self . did ) 
548+                     { 
549+                         self . collected . push ( final_seg. ident . span ) ; 
550+                     } 
551+                 } 
552+             } 
553+ 
554+             cx. emit_span_lint_lazy ( NON_UPPER_CASE_GLOBALS ,  ident. span ,  || { 
555+                 // Compute usages lazily as it can expansive and useless when the lint is allowed. 
556+                 // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625 
557+                 let  usages = if  can_change_usages
558+                     && * name != uc
559+                     && let  Some ( did)  = did
560+                 { 
561+                     let  mut  usage_collector =
562+                         UsageCollector  {  cx,  did :  did. to_def_id ( ) ,  collected :  Vec :: new ( )  } ; 
563+                     cx. tcx . hir_walk_toplevel_module ( & mut  usage_collector) ; 
564+                     usage_collector
565+                         . collected 
566+                         . into_iter ( ) 
567+                         . map ( |span| NonUpperCaseGlobalSubTool  {  span,  replace :  uc. clone ( )  } ) 
568+                         . collect ( ) 
569+                 }  else  { 
570+                     vec ! [ ] 
571+                 } ; 
572+ 
573+                 NonUpperCaseGlobal  {  sort,  name,  sub,  usages } 
574+             } ) ; 
512575        } 
513576    } 
514577} 
@@ -520,26 +583,36 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
520583            hir:: ItemKind :: Static ( _,  ident,  ..) 
521584                if  !find_attr ! ( attrs,  AttributeKind :: NoMangle ( ..) )  =>
522585            { 
523-                 NonUpperCaseGlobals :: check_upper_case ( cx,  "static variable" ,  & ident) ; 
586+                 NonUpperCaseGlobals :: check_upper_case ( 
587+                     cx, 
588+                     "static variable" , 
589+                     Some ( it. owner_id . def_id ) , 
590+                     & ident, 
591+                 ) ; 
524592            } 
525593            hir:: ItemKind :: Const ( ident,  ..)  => { 
526-                 NonUpperCaseGlobals :: check_upper_case ( cx,  "constant" ,  & ident) ; 
594+                 NonUpperCaseGlobals :: check_upper_case ( 
595+                     cx, 
596+                     "constant" , 
597+                     Some ( it. owner_id . def_id ) , 
598+                     & ident, 
599+                 ) ; 
527600            } 
528601            _ => { } 
529602        } 
530603    } 
531604
532605    fn  check_trait_item ( & mut  self ,  cx :  & LateContext < ' _ > ,  ti :  & hir:: TraitItem < ' _ > )  { 
533606        if  let  hir:: TraitItemKind :: Const ( ..)  = ti. kind  { 
534-             NonUpperCaseGlobals :: check_upper_case ( cx,  "associated constant" ,  & ti. ident ) ; 
607+             NonUpperCaseGlobals :: check_upper_case ( cx,  "associated constant" ,  None ,   & ti. ident ) ; 
535608        } 
536609    } 
537610
538611    fn  check_impl_item ( & mut  self ,  cx :  & LateContext < ' _ > ,  ii :  & hir:: ImplItem < ' _ > )  { 
539612        if  let  hir:: ImplItemKind :: Const ( ..)  = ii. kind 
540613            && !assoc_item_in_trait_impl ( cx,  ii) 
541614        { 
542-             NonUpperCaseGlobals :: check_upper_case ( cx,  "associated constant" ,  & ii. ident ) ; 
615+             NonUpperCaseGlobals :: check_upper_case ( cx,  "associated constant" ,  None ,   & ii. ident ) ; 
543616        } 
544617    } 
545618
@@ -555,6 +628,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
555628                    NonUpperCaseGlobals :: check_upper_case ( 
556629                        cx, 
557630                        "constant in pattern" , 
631+                         None , 
558632                        & segment. ident , 
559633                    ) ; 
560634                } 
@@ -564,7 +638,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
564638
565639    fn  check_generic_param ( & mut  self ,  cx :  & LateContext < ' _ > ,  param :  & hir:: GenericParam < ' _ > )  { 
566640        if  let  GenericParamKind :: Const  {  .. }  = param. kind  { 
567-             NonUpperCaseGlobals :: check_upper_case ( cx,  "const parameter" ,  & param. name . ident ( ) ) ; 
641+             NonUpperCaseGlobals :: check_upper_case ( 
642+                 cx, 
643+                 "const parameter" , 
644+                 Some ( param. def_id ) , 
645+                 & param. name . ident ( ) , 
646+             ) ; 
568647        } 
569648    } 
570649} 
0 commit comments