about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src/coverage/unexpand.rs
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2024-06-30 17:36:16 +1000
committerZalathar <Zalathar@users.noreply.github.com>2024-06-30 17:44:19 +1000
commit617de8cfb59252a501fc7e0ab7c2510dd8a8a7f4 (patch)
treef1d317dc7149b278f3c2924197150d4c119adad7 /compiler/rustc_mir_transform/src/coverage/unexpand.rs
parent716752ebe6974b5c6ab9b34b894e075f3e4a4b1e (diff)
downloadrust-617de8cfb59252a501fc7e0ab7c2510dd8a8a7f4.tar.gz
rust-617de8cfb59252a501fc7e0ab7c2510dd8a8a7f4.zip
coverage: Move span unexpansion into its own submodule
Diffstat (limited to 'compiler/rustc_mir_transform/src/coverage/unexpand.rs')
-rw-r--r--compiler/rustc_mir_transform/src/coverage/unexpand.rs54
1 files changed, 54 insertions, 0 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs
new file mode 100644
index 00000000000..18532b8ee45
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs
@@ -0,0 +1,54 @@
+use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
+
+/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
+/// within the function's body source. This span is guaranteed to be contained
+/// within, or equal to, the `body_span`. If the extrapolated span is not
+/// contained within the `body_span`, `None` is returned.
+///
+/// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
+/// etc.).
+pub(crate) fn unexpand_into_body_span_with_visible_macro(
+    original_span: Span,
+    body_span: Span,
+) -> Option<(Span, Option<Symbol>)> {
+    let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?;
+
+    let visible_macro = prev
+        .map(|prev| match prev.ctxt().outer_expn_data().kind {
+            ExpnKind::Macro(MacroKind::Bang, name) => Some(name),
+            _ => None,
+        })
+        .flatten();
+
+    Some((span, visible_macro))
+}
+
+/// Walks through the expansion ancestors of `original_span` to find a span that
+/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`.
+/// The ancestor that was traversed just before the matching span (if any) is
+/// also returned.
+///
+/// For example, a return value of `Some((ancestor, Some(prev))` means that:
+/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)`
+/// - `ancestor == prev.parent_callsite()`
+///
+/// [`SyntaxContext`]: rustc_span::SyntaxContext
+fn unexpand_into_body_span_with_prev(
+    original_span: Span,
+    body_span: Span,
+) -> Option<(Span, Option<Span>)> {
+    let mut prev = None;
+    let mut curr = original_span;
+
+    while !body_span.contains(curr) || !curr.eq_ctxt(body_span) {
+        prev = Some(curr);
+        curr = curr.parent_callsite()?;
+    }
+
+    debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span));
+    if let Some(prev) = prev {
+        debug_assert_eq!(Some(curr), prev.parent_callsite());
+    }
+
+    Some((curr, prev))
+}