| use rustc::session::Session; |
| |
| use crate::generated_code; |
| |
| use syntax::parse::lexer::{self, StringReader}; |
| use syntax::parse::token::{self, TokenKind}; |
| use syntax_pos::*; |
| |
| #[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(path) if !file.name_was_remapped => { |
| if path.is_absolute() { |
| self.sess.source_map().path_mapping() |
| .map_prefix(path.clone()).0 |
| .display() |
| .to_string() |
| } else { |
| self.sess.working_dir.0 |
| .join(&path) |
| .display() |
| .to_string() |
| } |
| }, |
| // If the file name is already remapped, we assume the user |
| // configured it the way they wanted to, so use that directly |
| filename => filename.to_string() |
| } |
| } |
| |
| pub fn snippet(&self, span: Span) -> String { |
| match self.sess.source_map().span_to_snippet(span) { |
| Ok(s) => s, |
| Err(_) => String::new(), |
| } |
| } |
| |
| pub fn retokenise_span(&self, span: Span) -> StringReader<'a> { |
| lexer::StringReader::retokenize(&self.sess.parse_sess, span) |
| } |
| |
| pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option<Span> { |
| let mut toks = self.retokenise_span(span); |
| loop { |
| let next = toks.next_token(); |
| if next == token::Eof { |
| return None; |
| } |
| if next == tok { |
| return Some(next.span); |
| } |
| } |
| } |
| |
| // // Return the name for a macro definition (identifier after first `!`) |
| // pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> { |
| // let mut toks = self.retokenise_span(span); |
| // loop { |
| // let ts = toks.real_token(); |
| // if ts == token::Eof { |
| // return None; |
| // } |
| // if ts == token::Not { |
| // let ts = toks.real_token(); |
| // if ts.kind.is_ident() { |
| // return Some(ts.sp); |
| // } else { |
| // return None; |
| // } |
| // } |
| // } |
| // } |
| |
| // // Return the name for a macro use (identifier before first `!`). |
| // pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> { |
| // let mut toks = self.retokenise_span(span); |
| // let mut prev = toks.real_token(); |
| // loop { |
| // if prev == token::Eof { |
| // return None; |
| // } |
| // let ts = toks.real_token(); |
| // if ts == token::Not { |
| // if prev.kind.is_ident() { |
| // return Some(prev.sp); |
| // } else { |
| // return None; |
| // } |
| // } |
| // prev = ts; |
| // } |
| // } |
| |
| /// 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; |
| } |
| }; |
| } |