@@ -2,8 +2,9 @@ use rustc_abi::ExternAbi;
22use rustc_attr_data_structures:: { AttributeKind , ReprAttr } ;
33use rustc_attr_parsing:: AttributeParser ;
44use rustc_hir:: def:: { DefKind , Res } ;
5- use rustc_hir:: intravisit:: FnKind ;
5+ use rustc_hir:: intravisit:: { FnKind , Visitor } ;
66use rustc_hir:: { AttrArgs , AttrItem , Attribute , GenericParamKind , PatExprKind , PatKind } ;
7+ use rustc_middle:: hir:: nested_filter:: All ;
78use rustc_middle:: ty;
89use rustc_session:: config:: CrateType ;
910use rustc_session:: { declare_lint, declare_lint_pass} ;
@@ -13,7 +14,8 @@ use {rustc_ast as ast, rustc_hir as hir};
1314
1415use crate :: lints:: {
1516 NonCamelCaseType , NonCamelCaseTypeSub , NonSnakeCaseDiag , NonSnakeCaseDiagSub ,
16- NonUpperCaseGlobal , NonUpperCaseGlobalSub ,
17+ NonUpperCaseGlobal , NonUpperCaseGlobalSub , NonUpperCaseGlobalSubTool ,
18+ NonUpperCaseGlobalSubToolsLazy ,
1719} ;
1820use crate :: { EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintContext } ;
1921
@@ -489,21 +491,67 @@ declare_lint! {
489491declare_lint_pass ! ( NonUpperCaseGlobals => [ NON_UPPER_CASE_GLOBALS ] ) ;
490492
491493impl NonUpperCaseGlobals {
492- fn check_upper_case ( cx : & LateContext < ' _ > , sort : & str , ident : & Ident ) {
494+ fn check_upper_case ( cx : & LateContext < ' _ > , sort : & str , did : Option < LocalDefId > , ident : & Ident ) {
493495 let name = ident. name . as_str ( ) ;
494496 if name. chars ( ) . any ( |c| c. is_lowercase ( ) ) {
495497 let uc = NonSnakeCase :: to_snake_case ( name) . to_uppercase ( ) ;
498+
496499 // We cannot provide meaningful suggestions
497500 // if the characters are in the category of "Lowercase Letter".
498501 let sub = if * name != uc {
499- NonUpperCaseGlobalSub :: Suggestion { span : ident. span , replace : uc }
502+ NonUpperCaseGlobalSub :: Suggestion { span : ident. span , replace : uc. clone ( ) }
500503 } else {
501504 NonUpperCaseGlobalSub :: Label { span : ident. span }
502505 } ;
506+
507+ struct UsageCollector < ' a , ' tcx > {
508+ cx : & ' tcx LateContext < ' a > ,
509+ did : LocalDefId ,
510+ collected : Vec < Span > ,
511+ }
512+
513+ impl < ' v , ' tcx > Visitor < ' v > for UsageCollector < ' v , ' tcx > {
514+ type NestedFilter = All ;
515+
516+ fn maybe_tcx ( & mut self ) -> Self :: MaybeTyCtxt {
517+ self . cx . tcx
518+ }
519+
520+ fn visit_path (
521+ & mut self ,
522+ path : & rustc_hir:: Path < ' v > ,
523+ _id : rustc_hir:: HirId ,
524+ ) -> Self :: Result {
525+ for seg in path. segments {
526+ if seg. res . opt_def_id ( ) == Some ( self . did . to_def_id ( ) ) {
527+ self . collected . push ( seg. ident . span ) ;
528+ }
529+ }
530+ }
531+ }
532+
533+ let usages = NonUpperCaseGlobalSubToolsLazy {
534+ usages : & || {
535+ if let Some ( did) = did
536+ && * name != uc
537+ {
538+ let mut usage_collector = UsageCollector { cx, did, collected : Vec :: new ( ) } ;
539+ cx. tcx . hir_walk_toplevel_module ( & mut usage_collector) ;
540+ usage_collector
541+ . collected
542+ . into_iter ( )
543+ . map ( |span| NonUpperCaseGlobalSubTool { span, replace : uc. clone ( ) } )
544+ . collect ( )
545+ } else {
546+ vec ! [ ]
547+ }
548+ } ,
549+ } ;
550+
503551 cx. emit_span_lint (
504552 NON_UPPER_CASE_GLOBALS ,
505553 ident. span ,
506- NonUpperCaseGlobal { sort, name, sub } ,
554+ NonUpperCaseGlobal { sort, name, sub, usages } ,
507555 ) ;
508556 }
509557 }
@@ -516,26 +564,36 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
516564 hir:: ItemKind :: Static ( _, ident, ..)
517565 if !ast:: attr:: contains_name ( attrs, sym:: no_mangle) =>
518566 {
519- NonUpperCaseGlobals :: check_upper_case ( cx, "static variable" , & ident) ;
567+ NonUpperCaseGlobals :: check_upper_case (
568+ cx,
569+ "static variable" ,
570+ Some ( it. owner_id . def_id ) ,
571+ & ident,
572+ ) ;
520573 }
521574 hir:: ItemKind :: Const ( ident, ..) => {
522- NonUpperCaseGlobals :: check_upper_case ( cx, "constant" , & ident) ;
575+ NonUpperCaseGlobals :: check_upper_case (
576+ cx,
577+ "constant" ,
578+ Some ( it. owner_id . def_id ) ,
579+ & ident,
580+ ) ;
523581 }
524582 _ => { }
525583 }
526584 }
527585
528586 fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , ti : & hir:: TraitItem < ' _ > ) {
529587 if let hir:: TraitItemKind :: Const ( ..) = ti. kind {
530- NonUpperCaseGlobals :: check_upper_case ( cx, "associated constant" , & ti. ident ) ;
588+ NonUpperCaseGlobals :: check_upper_case ( cx, "associated constant" , None , & ti. ident ) ;
531589 }
532590 }
533591
534592 fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , ii : & hir:: ImplItem < ' _ > ) {
535593 if let hir:: ImplItemKind :: Const ( ..) = ii. kind
536594 && !assoc_item_in_trait_impl ( cx, ii)
537595 {
538- NonUpperCaseGlobals :: check_upper_case ( cx, "associated constant" , & ii. ident ) ;
596+ NonUpperCaseGlobals :: check_upper_case ( cx, "associated constant" , None , & ii. ident ) ;
539597 }
540598 }
541599
@@ -551,6 +609,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
551609 NonUpperCaseGlobals :: check_upper_case (
552610 cx,
553611 "constant in pattern" ,
612+ None ,
554613 & segment. ident ,
555614 ) ;
556615 }
@@ -560,7 +619,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
560619
561620 fn check_generic_param ( & mut self , cx : & LateContext < ' _ > , param : & hir:: GenericParam < ' _ > ) {
562621 if let GenericParamKind :: Const { .. } = param. kind {
563- NonUpperCaseGlobals :: check_upper_case ( cx, "const parameter" , & param. name . ident ( ) ) ;
622+ NonUpperCaseGlobals :: check_upper_case (
623+ cx,
624+ "const parameter" ,
625+ Some ( param. def_id ) ,
626+ & param. name . ident ( ) ,
627+ ) ;
564628 }
565629 }
566630}
0 commit comments