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}