rustc_utils/source_map/spanner/
hir_span.rsuse hir::{HirId, LoopSource};
use rustc_hir::{
self as hir,
intravisit::{self, Visitor as HirVisitor},
ExprKind, MatchSource, Node,
};
use rustc_span::{BytePos, Span};
use super::Spanner;
use crate::SpanExt;
struct ChildExprSpans {
spans: Vec<Span>,
item_span: Span,
}
impl HirVisitor<'_> for ChildExprSpans {
fn visit_expr(&mut self, ex: &hir::Expr) {
match ex.kind {
ExprKind::Block(..) => {
intravisit::walk_expr(self, ex);
}
ExprKind::Match(_, arms, MatchSource::ForLoopDesugar | MatchSource::Normal) => {
for arm in arms {
intravisit::walk_arm(self, arm);
}
}
_ => {
if let Some(span) = ex.span.as_local(self.item_span) {
self.spans.push(span);
}
}
}
}
fn visit_arm(&mut self, arm: &hir::Arm) {
self.visit_expr(arm.body);
}
fn visit_stmt(&mut self, stmt: &hir::Stmt) {
if let Some(span) = stmt.span.as_local(self.item_span) {
self.spans.push(span);
}
}
}
#[derive(Clone, Copy)]
pub enum EnclosingHirSpans {
Full,
OuterOnly,
None,
}
macro_rules! try_span {
($self:expr, $span:expr) => {
match $span.as_local($self.item_span) {
Some(span) if !$self.invalid_span(span) => span,
_ => {
return None;
}
}
};
}
impl Spanner<'_> {
pub fn hir_spans(&self, id: HirId, mode: EnclosingHirSpans) -> Option<Vec<Span>> {
let hir = self.tcx.hir();
let span = try_span!(self, hir.span(id));
let inner_spans = match self.tcx.hir_node(id) {
Node::Expr(expr) => match expr.kind {
ExprKind::Loop(_, _, loop_source, header) => match loop_source {
LoopSource::ForLoop | LoopSource::While => {
vec![expr.span.trim_start(header).unwrap_or(expr.span)]
}
LoopSource::Loop => vec![expr.span.with_lo(expr.span.lo() + BytePos(4))],
},
ExprKind::Break(..) => return None,
_ => {
let mut visitor = ChildExprSpans {
spans: Vec::new(),
item_span: self.item_span,
};
intravisit::walk_expr(&mut visitor, expr);
visitor.spans
}
},
Node::Stmt(stmt) => {
let mut visitor = ChildExprSpans {
spans: Vec::new(),
item_span: self.item_span,
};
intravisit::walk_stmt(&mut visitor, stmt);
visitor.spans
}
Node::Param(_param) => vec![],
_ => {
return None;
}
};
Some(match mode {
EnclosingHirSpans::Full => vec![span],
EnclosingHirSpans::OuterOnly => span.subtract(inner_spans),
EnclosingHirSpans::None => vec![],
})
}
}