use crate::generated_code; use rustc_data_structures::sync::Lrc; use rustc_lexer::{tokenize, TokenKind}; use rustc_session::Session; use rustc_span::*; #[derive(Clone)] pub struct SpanUtils<'a> { pub sess: &'a Session, } impl<'a> SpanUtils<'a> { pub fn new(sess: &'a Session) -> SpanUtils<'a> { SpanUtils { sess } } pub fn make_filename_string(&self, file: &SourceFile) -> String { match &file.name { FileName::Real(RealFileName::LocalPath(path)) => { if path.is_absolute() { self.sess.source_map().path_mapping().map_prefix(path).0.display().to_string() } else { self.sess .opts .working_dir .remapped_path_if_available() .join(&path) .display() .to_string() } } filename => filename.prefer_remapped().to_string(), } } pub fn snippet(&self, span: Span) -> String { match self.sess.source_map().span_to_snippet(span) { Ok(s) => s, Err(_) => String::new(), } } /// Finds the span of `*` token withing the larger `span`. pub fn sub_span_of_star(&self, mut span: Span) -> Option { let begin = self.sess.source_map().lookup_byte_offset(span.lo()); let end = self.sess.source_map().lookup_byte_offset(span.hi()); // Make the range zero-length if the span is invalid. if begin.sf.start_pos != end.sf.start_pos { span = span.shrink_to_lo(); } let sf = Lrc::clone(&begin.sf); self.sess.source_map().ensure_source_file_source_present(Lrc::clone(&sf)); let src = sf.src.clone().or_else(|| sf.external_src.borrow().get_source().map(Lrc::clone))?; let to_index = |pos: BytePos| -> usize { (pos - sf.start_pos).0 as usize }; let text = &src[to_index(span.lo())..to_index(span.hi())]; let start_pos = { let mut pos = 0; tokenize(text) .map(|token| { let start = pos; pos += token.len; (start, token) }) .find(|(_pos, token)| token.kind == TokenKind::Star)? .0 }; let lo = span.lo() + BytePos(start_pos as u32); let hi = lo + BytePos(1); Some(span.with_lo(lo).with_hi(hi)) } /// Return true if the span is generated code, and /// it is not a subspan of the root callsite. /// /// Used to filter out spans of minimal value, /// such as references to macro internal variables. pub fn filter_generated(&self, span: Span) -> bool { if generated_code(span) { return true; } //If the span comes from a fake source_file, filter it. !self.sess.source_map().lookup_char_pos(span.lo()).file.is_real_file() } } macro_rules! filter { ($util: expr, $parent: expr) => { if $util.filter_generated($parent) { return None; } }; }