| use rustc_span::{ExpnKind, Span}; |
| |
| /// Walks through the expansion ancestors of `original_span` to find a span that |
| /// is contained in `body_span` and has the same [syntax context] as `body_span`. |
| pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> Option<Span> { |
| // Because we don't need to return any extra ancestor information, |
| // we can just delegate directly to `find_ancestor_inside_same_ctxt`. |
| original_span.find_ancestor_inside_same_ctxt(body_span) |
| } |
| |
| /// Walks through the expansion ancestors of `original_span` to find a span that |
| /// is contained in `body_span` and has the same [syntax context] as `body_span`. |
| /// |
| /// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), |
| /// the returned symbol will be the name of that macro (e.g. `foo`). |
| pub(crate) fn unexpand_into_body_span_with_expn_kind( |
| original_span: Span, |
| body_span: Span, |
| ) -> Option<(Span, Option<ExpnKind>)> { |
| let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; |
| |
| let expn_kind = prev.map(|prev| prev.ctxt().outer_expn_data().kind); |
| |
| Some((span, expn_kind)) |
| } |
| |
| /// Walks through the expansion ancestors of `original_span` to find a span that |
| /// is contained in `body_span` and has the same [syntax context] 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)` |
| /// - `prev.parent_callsite() == ancestor` |
| /// |
| /// [syntax context]: 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_inside_same_ctxt(body_span)); |
| if let Some(prev) = prev { |
| debug_assert_eq!(Some(curr), prev.parent_callsite()); |
| } |
| |
| Some((curr, prev)) |
| } |