about summary refs log tree commit diff
diff options
context:
space:
mode:
authory21 <30553356+y21@users.noreply.github.com>2025-06-21 15:34:31 +0200
committery21 <30553356+y21@users.noreply.github.com>2025-06-21 18:09:56 +0200
commit47e8c315f3e600357f0147b867de798b1b96cd03 (patch)
tree4366cdfc0effb5caa8a0b875b79a57d36a6260ba
parentbfd73ccae051b32686486d1849ea92750d259ad6 (diff)
downloadrust-47e8c315f3e600357f0147b867de798b1b96cd03.tar.gz
rust-47e8c315f3e600357f0147b867de798b1b96cd03.zip
Make sure spans are from the root
-rw-r--r--clippy_lints/src/vec.rs18
1 files changed, 14 insertions, 4 deletions
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index 1646f222021..52b30ddce12 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -25,7 +25,7 @@ pub struct UselessVec {
     /// Maps from a `vec![]` source callsite invocation span to the "state" (i.e., whether we can
     /// emit a warning there or not).
     ///
-    /// The purpose of this is to buffer lints up until `check_expr_post` so that we can cancel a
+    /// The purpose of this is to buffer lints up until `check_crate_post` so that we can cancel a
     /// lint while visiting, because a `vec![]` invocation span can appear multiple times when
     /// it is passed as a macro argument, once in a context that doesn't require a `Vec<_>` and
     /// another time that does. Consider:
@@ -187,7 +187,11 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                                     .checked_mul(length)
                                     .is_some_and(|size| size <= self.too_large_for_stack)
                             {
-                                suggest_ty.snippet(cx, Some(expr.span), Some(len.span))
+                                suggest_ty.snippet(
+                                    cx,
+                                    Some(expr.span.source_callsite()),
+                                    Some(len.span.source_callsite()),
+                                )
                             } else {
                                 return;
                             }
@@ -267,11 +271,17 @@ impl SuggestedType {
     }
 
     fn snippet(self, cx: &LateContext<'_>, args_span: Option<Span>, len_span: Option<Span>) -> String {
+        // Invariant of the lint as implemented: all spans are from the root context (and as a result,
+        // always trivially crate-local).
+        assert!(args_span.is_none_or(|s| !s.from_expansion()));
+        assert!(len_span.is_none_or(|s| !s.from_expansion()));
+
         let maybe_args = args_span
-            .and_then(|sp| sp.get_source_text(cx))
+            .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"))
             .map_or(String::new(), |x| x.to_owned());
         let maybe_len = len_span
-            .and_then(|sp| sp.get_source_text(cx).map(|s| format!("; {s}")))
+            .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"))
+            .map(|st| format!("; {st}"))
             .unwrap_or_default();
 
         match self {