// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! This module contains utilities that work with the `CodeMap` from `libsyntax` / `syntex_syntax`. //! This includes extension traits and methods for looking up spans and line ranges for AST nodes. use config::file_lines::LineRange; use syntax::codemap::{BytePos, CodeMap, Span}; use visitor::SnippetProvider; use comment::FindUncommented; pub trait SpanUtils { fn span_after(&self, original: Span, needle: &str) -> BytePos; fn span_after_last(&self, original: Span, needle: &str) -> BytePos; fn span_before(&self, original: Span, needle: &str) -> BytePos; fn opt_span_after(&self, original: Span, needle: &str) -> Option; fn opt_span_before(&self, original: Span, needle: &str) -> Option; } pub trait LineRangeUtils { /// Returns the `LineRange` that corresponds to `span` in `self`. /// /// # Panics /// /// Panics if `span` crosses a file boundary, which shouldn't happen. fn lookup_line_range(&self, span: Span) -> LineRange; } impl<'a> SpanUtils for SnippetProvider<'a> { fn span_after(&self, original: Span, needle: &str) -> BytePos { self.opt_span_after(original, needle).expect("bad span") } fn span_after_last(&self, original: Span, needle: &str) -> BytePos { let snippet = self.span_to_snippet(original).unwrap(); let mut offset = 0; while let Some(additional_offset) = snippet[offset..].find_uncommented(needle) { offset += additional_offset + needle.len(); } original.lo() + BytePos(offset as u32) } fn span_before(&self, original: Span, needle: &str) -> BytePos { self.opt_span_before(original, needle).expect("bad span") } fn opt_span_after(&self, original: Span, needle: &str) -> Option { self.opt_span_before(original, needle) .map(|bytepos| bytepos + BytePos(needle.len() as u32)) } fn opt_span_before(&self, original: Span, needle: &str) -> Option { let snippet = self.span_to_snippet(original)?; let offset = snippet.find_uncommented(needle)?; Some(original.lo() + BytePos(offset as u32)) } } impl LineRangeUtils for CodeMap { fn lookup_line_range(&self, span: Span) -> LineRange { let lo = self.lookup_line(span.lo()).unwrap(); let hi = self.lookup_line(span.hi()).unwrap(); debug_assert_eq!( lo.fm.name, hi.fm.name, "span crossed file boundary: lo: {:?}, hi: {:?}", lo, hi ); // Line numbers start at 1 LineRange { file: lo.fm.clone(), lo: lo.line + 1, hi: hi.line + 1, } } }