// 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 std::rc::Rc; use syntax::codemap::{BytePos, CodeMap, FileMap, Span}; use comment::FindUncommented; /// A range of lines in a file, inclusive of both ends. pub struct LineRange { pub file: Rc, pub lo: usize, pub hi: usize, } impl LineRange { pub fn file_name(&self) -> &str { self.file.as_ref().name.as_str() } } 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; } 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 SpanUtils for CodeMap { fn span_after(&self, original: Span, needle: &str) -> BytePos { let snippet = self.span_to_snippet(original).unwrap(); let offset = snippet.find_uncommented(needle).unwrap() + needle.len(); original.lo + BytePos(offset as u32) } 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 { let snippet = self.span_to_snippet(original).unwrap(); let offset = snippet.find_uncommented(needle).unwrap(); original.lo + BytePos(offset as u32) } } impl LineRangeUtils for CodeMap { fn lookup_line_range(&self, span: Span) -> LineRange { let lo = self.lookup_char_pos(span.lo); let hi = self.lookup_char_pos(span.hi); assert!(lo.file.name == hi.file.name, "span crossed file boundary: lo: {:?}, hi: {:?}", lo, hi); LineRange { file: lo.file.clone(), lo: lo.line, hi: hi.line, } } }