about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUrgau <urgau@numericable.fr>2025-06-17 23:27:06 +0200
committerUrgau <urgau@numericable.fr>2025-06-18 00:06:37 +0200
commit42bb66add31d196bb8d0f0bfb79a00dfd2cad55b (patch)
tree3e9ed8a4221ed03888393ac9b2448acf5c2eeb34
parent994794a50bd4adfd7f0351872206e170c1bc8d58 (diff)
downloadrust-42bb66add31d196bb8d0f0bfb79a00dfd2cad55b.tar.gz
rust-42bb66add31d196bb8d0f0bfb79a00dfd2cad55b.zip
Also emit suggestions for usages in the `non_upper_case_globals` lint
-rw-r--r--compiler/rustc_lint/src/lints.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs77
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.fixed39
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.rs39
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.stderr64
5 files changed, 210 insertions, 11 deletions
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 3d17dfbc451..d157bf6986c 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1348,6 +1348,8 @@ pub(crate) struct NonUpperCaseGlobal<'a> {
     pub name: &'a str,
     #[subdiagnostic]
     pub sub: NonUpperCaseGlobalSub,
+    #[subdiagnostic]
+    pub usages: Vec<NonUpperCaseGlobalSub>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 1b60466a589..a5b3eb3f0ff 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -2,8 +2,9 @@ use rustc_abi::ExternAbi;
 use rustc_attr_data_structures::{AttributeKind, ReprAttr};
 use rustc_attr_parsing::AttributeParser;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::intravisit::{FnKind, Visitor};
 use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind};
+use rustc_middle::hir::nested_filter::All;
 use rustc_middle::ty;
 use rustc_session::config::CrateType;
 use rustc_session::{declare_lint, declare_lint_pass};
@@ -489,21 +490,59 @@ declare_lint! {
 declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]);
 
 impl NonUpperCaseGlobals {
-    fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
+    fn check_upper_case(cx: &LateContext<'_>, sort: &str, did: Option<LocalDefId>, ident: &Ident) {
         let name = ident.name.as_str();
         if name.chars().any(|c| c.is_lowercase()) {
             let uc = NonSnakeCase::to_snake_case(name).to_uppercase();
+
             // We cannot provide meaningful suggestions
             // if the characters are in the category of "Lowercase Letter".
-            let sub = if *name != uc {
-                NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc }
+            let sub = |span| {
+                if *name != uc {
+                    NonUpperCaseGlobalSub::Suggestion { span, replace: uc.clone() }
+                } else {
+                    NonUpperCaseGlobalSub::Label { span }
+                }
+            };
+
+            struct UsageCollector<'a, 'tcx> {
+                cx: &'tcx LateContext<'a>,
+                did: LocalDefId,
+                collected: Vec<Span>,
+            }
+
+            impl<'v, 'tcx> Visitor<'v> for UsageCollector<'v, 'tcx> {
+                type NestedFilter = All;
+
+                fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                    self.cx.tcx
+                }
+
+                fn visit_path(
+                    &mut self,
+                    path: &rustc_hir::Path<'v>,
+                    _id: rustc_hir::HirId,
+                ) -> Self::Result {
+                    for seg in path.segments {
+                        if seg.res.opt_def_id() == Some(self.did.to_def_id()) {
+                            self.collected.push(seg.ident.span);
+                        }
+                    }
+                }
+            }
+
+            let usages = if let Some(did) = did {
+                let mut usage_collector = UsageCollector { cx, did, collected: Vec::new() };
+                cx.tcx.hir_walk_toplevel_module(&mut usage_collector);
+                usage_collector.collected.into_iter().map(|span| sub(span)).collect()
             } else {
-                NonUpperCaseGlobalSub::Label { span: ident.span }
+                vec![]
             };
+
             cx.emit_span_lint(
                 NON_UPPER_CASE_GLOBALS,
                 ident.span,
-                NonUpperCaseGlobal { sort, name, sub },
+                NonUpperCaseGlobal { sort, name, sub: sub(ident.span), usages },
             );
         }
     }
@@ -516,10 +555,20 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
             hir::ItemKind::Static(_, ident, ..)
                 if !ast::attr::contains_name(attrs, sym::no_mangle) =>
             {
-                NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident);
+                NonUpperCaseGlobals::check_upper_case(
+                    cx,
+                    "static variable",
+                    Some(it.owner_id.def_id),
+                    &ident,
+                );
             }
             hir::ItemKind::Const(ident, ..) => {
-                NonUpperCaseGlobals::check_upper_case(cx, "constant", &ident);
+                NonUpperCaseGlobals::check_upper_case(
+                    cx,
+                    "constant",
+                    Some(it.owner_id.def_id),
+                    &ident,
+                );
             }
             _ => {}
         }
@@ -527,7 +576,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, ti: &hir::TraitItem<'_>) {
         if let hir::TraitItemKind::Const(..) = ti.kind {
-            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ti.ident);
+            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ti.ident);
         }
     }
 
@@ -535,7 +584,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
         if let hir::ImplItemKind::Const(..) = ii.kind
             && !assoc_item_in_trait_impl(cx, ii)
         {
-            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident);
+            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ii.ident);
         }
     }
 
@@ -551,6 +600,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
                     NonUpperCaseGlobals::check_upper_case(
                         cx,
                         "constant in pattern",
+                        None,
                         &segment.ident,
                     );
                 }
@@ -560,7 +610,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
         if let GenericParamKind::Const { .. } = param.kind {
-            NonUpperCaseGlobals::check_upper_case(cx, "const parameter", &param.name.ident());
+            NonUpperCaseGlobals::check_upper_case(
+                cx,
+                "const parameter",
+                Some(param.def_id),
+                &param.name.ident(),
+            );
         }
     }
 }
diff --git a/tests/ui/lint/lint-non-uppercase-usages.fixed b/tests/ui/lint/lint-non-uppercase-usages.fixed
new file mode 100644
index 00000000000..048a936ff27
--- /dev/null
+++ b/tests/ui/lint/lint-non-uppercase-usages.fixed
@@ -0,0 +1,39 @@
+// Checks that the `non_upper_case_globals` emits suggestions for usages as well
+// <https://github.com/rust-lang/rust/issues/124061>
+
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)]
+
+use std::cell::Cell;
+
+const MY_STATIC: u32 = 0;
+//~^ WARN constant `my_static` should have an upper case name
+//~| SUGGESTION MY_STATIC
+
+const LOL: u32 = MY_STATIC + 0;
+//~^ SUGGESTION MY_STATIC
+
+thread_local! {
+    static FOO_FOO: Cell<usize> = unreachable!();
+    //~^ WARN constant `fooFOO` should have an upper case name
+    //~| SUGGESTION FOO_FOO
+}
+
+fn foo<const FOO: u32>() {
+    //~^ WARN const parameter `foo` should have an upper case name
+    //~| SUGGESTION FOO
+    let _a = FOO + 1;
+    //~^ SUGGESTION FOO
+}
+
+fn main() {
+    let _a = crate::MY_STATIC;
+    //~^ SUGGESTION MY_STATIC
+
+    FOO_FOO.set(9);
+    //~^ SUGGESTION FOO_FOO
+    println!("{}", FOO_FOO.get());
+    //~^ SUGGESTION FOO_FOO
+}
diff --git a/tests/ui/lint/lint-non-uppercase-usages.rs b/tests/ui/lint/lint-non-uppercase-usages.rs
new file mode 100644
index 00000000000..b5b9ffac6bc
--- /dev/null
+++ b/tests/ui/lint/lint-non-uppercase-usages.rs
@@ -0,0 +1,39 @@
+// Checks that the `non_upper_case_globals` emits suggestions for usages as well
+// <https://github.com/rust-lang/rust/issues/124061>
+
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)]
+
+use std::cell::Cell;
+
+const my_static: u32 = 0;
+//~^ WARN constant `my_static` should have an upper case name
+//~| SUGGESTION MY_STATIC
+
+const LOL: u32 = my_static + 0;
+//~^ SUGGESTION MY_STATIC
+
+thread_local! {
+    static fooFOO: Cell<usize> = unreachable!();
+    //~^ WARN constant `fooFOO` should have an upper case name
+    //~| SUGGESTION FOO_FOO
+}
+
+fn foo<const foo: u32>() {
+    //~^ WARN const parameter `foo` should have an upper case name
+    //~| SUGGESTION FOO
+    let _a = foo + 1;
+    //~^ SUGGESTION FOO
+}
+
+fn main() {
+    let _a = crate::my_static;
+    //~^ SUGGESTION MY_STATIC
+
+    fooFOO.set(9);
+    //~^ SUGGESTION FOO_FOO
+    println!("{}", fooFOO.get());
+    //~^ SUGGESTION FOO_FOO
+}
diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr
new file mode 100644
index 00000000000..fa47b4ba6a8
--- /dev/null
+++ b/tests/ui/lint/lint-non-uppercase-usages.stderr
@@ -0,0 +1,64 @@
+warning: constant `my_static` should have an upper case name
+  --> $DIR/lint-non-uppercase-usages.rs:11:7
+   |
+LL | const my_static: u32 = 0;
+   |       ^^^^^^^^^
+   |
+   = note: `#[warn(non_upper_case_globals)]` on by default
+help: convert the identifier to upper case
+   |
+LL - const my_static: u32 = 0;
+LL + const MY_STATIC: u32 = 0;
+   |
+help: convert the identifier to upper case
+   |
+LL - const LOL: u32 = my_static + 0;
+LL + const LOL: u32 = MY_STATIC + 0;
+   |
+help: convert the identifier to upper case
+   |
+LL -     let _a = crate::my_static;
+LL +     let _a = crate::MY_STATIC;
+   |
+
+warning: constant `fooFOO` should have an upper case name
+  --> $DIR/lint-non-uppercase-usages.rs:19:12
+   |
+LL |     static fooFOO: Cell<usize> = unreachable!();
+   |            ^^^^^^
+   |
+help: convert the identifier to upper case
+   |
+LL -     static fooFOO: Cell<usize> = unreachable!();
+LL +     static FOO_FOO: Cell<usize> = unreachable!();
+   |
+help: convert the identifier to upper case
+   |
+LL -     fooFOO.set(9);
+LL +     FOO_FOO.set(9);
+   |
+help: convert the identifier to upper case
+   |
+LL -     println!("{}", fooFOO.get());
+LL +     println!("{}", FOO_FOO.get());
+   |
+
+warning: const parameter `foo` should have an upper case name
+  --> $DIR/lint-non-uppercase-usages.rs:24:14
+   |
+LL | fn foo<const foo: u32>() {
+   |              ^^^
+   |
+help: convert the identifier to upper case (notice the capitalization difference)
+   |
+LL - fn foo<const foo: u32>() {
+LL + fn foo<const FOO: u32>() {
+   |
+help: convert the identifier to upper case (notice the capitalization difference)
+   |
+LL -     let _a = foo + 1;
+LL +     let _a = FOO + 1;
+   |
+
+warning: 3 warnings emitted
+