// 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 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; } 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).expect("Bad snippet"); let offset = snippet.find_uncommented(needle).expect("Bad offset") + 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) } fn opt_span_after(&self, original: Span, needle: &str) -> Option { let snippet = self.span_to_snippet(original).ok()?; let offset = snippet.find_uncommented(needle)? + needle.len(); Some(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_eq!( 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, } } }