about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-07-02 19:29:39 +0200
committerGitHub <noreply@github.com>2025-07-02 19:29:39 +0200
commit45b32efc499d0db2a896a03812a0b55825dce7cb (patch)
tree20fcf174b913311eb5eeb78fb44f19ff4b8d3982
parenta51c494d209edb124408be651900d7fac68be655 (diff)
parent8bd580b80e3c31f9c2d4115768a3ac0b71372587 (diff)
downloadrust-45b32efc499d0db2a896a03812a0b55825dce7cb.tar.gz
rust-45b32efc499d0db2a896a03812a0b55825dce7cb.zip
Rollup merge of #143306 - samueltardieu:track-clippy-lints-emission, r=petrochenkov
Add `track_caller` attributes to trace origin of Clippy lints

This allows the use of `-Z track-diagnostics` to see the origin of Clippy lints emission, as is already the case for lints coming from rustc.
-rw-r--r--clippy_utils/src/diagnostics.rs7
-rw-r--r--tests/ui/track-diagnostics-clippy.rs22
-rw-r--r--tests/ui/track-diagnostics-clippy.stderr29
3 files changed, 58 insertions, 0 deletions
diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs
index dc240dd067b..8453165818b 100644
--- a/clippy_utils/src/diagnostics.rs
+++ b/clippy_utils/src/diagnostics.rs
@@ -98,6 +98,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) {
 /// 17 |     std::mem::forget(seven);
 ///    |     ^^^^^^^^^^^^^^^^^^^^^^^
 /// ```
+#[track_caller]
 pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
     cx.span_lint(lint, sp, |diag| {
@@ -143,6 +144,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 ///    |
 ///    = help: consider using `f64::NAN` if you would like a constant representing NaN
 /// ```
+#[track_caller]
 pub fn span_lint_and_help<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
@@ -203,6 +205,7 @@ pub fn span_lint_and_help<T: LintContext>(
 /// 10 |     forget(&SomeStruct);
 ///    |            ^^^^^^^^^^^
 /// ```
+#[track_caller]
 pub fn span_lint_and_note<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
@@ -244,6 +247,7 @@ pub fn span_lint_and_note<T: LintContext>(
 /// If you're unsure which function you should use, you can test if the `#[expect]` attribute works
 /// where you would expect it to.
 /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
+#[track_caller]
 pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F)
 where
     C: LintContext,
@@ -286,6 +290,7 @@ where
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
+#[track_caller]
 pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
     cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
@@ -321,6 +326,7 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
+#[track_caller]
 pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
@@ -374,6 +380,7 @@ pub fn span_lint_hir_and_then(
 ///     = note: `-D fold-any` implied by `-D warnings`
 /// ```
 #[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))]
+#[track_caller]
 pub fn span_lint_and_sugg<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
diff --git a/tests/ui/track-diagnostics-clippy.rs b/tests/ui/track-diagnostics-clippy.rs
new file mode 100644
index 00000000000..2e67fb65efc
--- /dev/null
+++ b/tests/ui/track-diagnostics-clippy.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Z track-diagnostics
+//@no-rustfix
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+#![warn(clippy::let_and_return, clippy::unnecessary_cast)]
+
+fn main() {
+    // Check the provenance of a lint sent through `LintContext::span_lint()`
+    let a = 3u32;
+    let b = a as u32;
+    //~^ unnecessary_cast
+    
+    // Check the provenance of a lint sent through `TyCtxt::node_span_lint()`
+    let c = {
+        let d = 42;
+        d
+        //~^ let_and_return
+    };
+}
diff --git a/tests/ui/track-diagnostics-clippy.stderr b/tests/ui/track-diagnostics-clippy.stderr
new file mode 100644
index 00000000000..f3aca685417
--- /dev/null
+++ b/tests/ui/track-diagnostics-clippy.stderr
@@ -0,0 +1,29 @@
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> tests/ui/track-diagnostics-clippy.rs:LL:CC
+   |
+LL |     let b = a as u32;
+   |             ^^^^^^^^ help: try: `a`
+-Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC
+   |
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/track-diagnostics-clippy.rs:LL:CC
+   |
+LL |         let d = 42;
+   |         ----------- unnecessary `let` binding
+LL |         d
+   |         ^
+-Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
+help: return the expression directly
+   |
+LL ~         
+LL ~         42
+   |
+
+error: aborting due to 2 previous errors
+