rapx/utils/
span.rs

1use rustc_middle::mir::{BasicBlock, Body, VarDebugInfoContents};
2use rustc_span::{
3    source_map::get_source_map,
4    {FileName, Pos, Span},
5};
6use std::ops::Range;
7
8#[inline]
9pub fn span_to_source_code(span: Span) -> String {
10    get_source_map().unwrap().span_to_snippet(span).unwrap()
11}
12
13#[inline]
14pub fn span_to_first_line(span: Span) -> Span {
15    get_source_map()
16        .unwrap()
17        .span_extend_to_line(span.shrink_to_lo())
18}
19
20#[inline]
21pub fn span_to_trimmed_span(span: Span) -> Span {
22    span.trim_start(
23        get_source_map()
24            .unwrap()
25            .span_take_while(span, |c| c.is_whitespace()),
26    )
27    .unwrap()
28}
29
30pub fn span_to_filename(span: Span) -> String {
31    let filename = get_source_map().unwrap().span_to_filename(span);
32    if let FileName::Real(realname) = filename {
33        if let Some(ref path) = realname.local_path() {
34            return path.to_string_lossy().into();
35        }
36    }
37    return "<unknown>".to_string();
38}
39
40#[inline]
41pub fn span_to_line_number(span: Span) -> usize {
42    get_source_map().unwrap().lookup_char_pos(span.lo()).line
43}
44
45pub fn get_variable_name<'tcx>(body: &Body<'tcx>, local_index: usize) -> Option<String> {
46    let target_local = rustc_middle::mir::Local::from_usize(local_index);
47
48    for info in &body.var_debug_info {
49        if let VarDebugInfoContents::Place(place) = info.value {
50            if place.local == target_local && place.projection.is_empty() {
51                return Some(info.name.to_string());
52            }
53        }
54    }
55
56    None
57}
58
59pub fn get_basic_block_span<'tcx>(body: &Body<'tcx>, bb_index: usize) -> Span {
60    if bb_index >= body.basic_blocks.len() {
61        return body.span;
62    }
63
64    let bb = BasicBlock::from_usize(bb_index);
65    let block_data = &body.basic_blocks[bb];
66
67    if let Some(ref term) = block_data.terminator {
68        return term.source_info.span;
69    }
70
71    if let Some(stmt) = block_data.statements.first() {
72        return stmt.source_info.span;
73    }
74
75    body.span
76}
77
78#[inline]
79pub fn relative_pos_range(span: Span, sub_span: Span) -> Range<usize> {
80    if sub_span.lo() < span.lo() || sub_span.hi() > span.hi() {
81        return 0..0;
82    }
83    let offset = span.lo();
84    let lo = (sub_span.lo() - offset).to_usize();
85    let hi = (sub_span.hi() - offset).to_usize();
86    lo..hi
87}
88
89pub fn are_spans_in_same_file(span1: Span, span2: Span) -> bool {
90    let file1 = get_source_map().unwrap().lookup_source_file(span1.lo());
91    let file2 = get_source_map().unwrap().lookup_source_file(span2.lo());
92    file1.name == file2.name
93}