]> git.lizzy.rs Git - rust.git/blob - rustfmt-core/src/codemap.rs
7292f7f35d1e1d4ce0e478116c444c0c76118eb4
[rust.git] / rustfmt-core / src / codemap.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This module contains utilities that work with the `CodeMap` from `libsyntax` / `syntex_syntax`.
12 //! This includes extension traits and methods for looking up spans and line ranges for AST nodes.
13
14 use config::file_lines::LineRange;
15 use syntax::codemap::{BytePos, CodeMap, Span};
16
17 use comment::FindUncommented;
18
19 pub trait SpanUtils {
20     fn span_after(&self, original: Span, needle: &str) -> BytePos;
21     fn span_after_last(&self, original: Span, needle: &str) -> BytePos;
22     fn span_before(&self, original: Span, needle: &str) -> BytePos;
23     fn opt_span_after(&self, original: Span, needle: &str) -> Option<BytePos>;
24 }
25
26 pub trait LineRangeUtils {
27     /// Returns the `LineRange` that corresponds to `span` in `self`.
28     ///
29     /// # Panics
30     ///
31     /// Panics if `span` crosses a file boundary, which shouldn't happen.
32     fn lookup_line_range(&self, span: Span) -> LineRange;
33 }
34
35 impl SpanUtils for CodeMap {
36     fn span_after(&self, original: Span, needle: &str) -> BytePos {
37         let snippet = self.span_to_snippet(original).expect("Bad snippet");
38         let offset = snippet.find_uncommented(needle).expect("Bad offset") + needle.len();
39
40         original.lo() + BytePos(offset as u32)
41     }
42
43     fn span_after_last(&self, original: Span, needle: &str) -> BytePos {
44         let snippet = self.span_to_snippet(original).unwrap();
45         let mut offset = 0;
46
47         while let Some(additional_offset) = snippet[offset..].find_uncommented(needle) {
48             offset += additional_offset + needle.len();
49         }
50
51         original.lo() + BytePos(offset as u32)
52     }
53
54     fn span_before(&self, original: Span, needle: &str) -> BytePos {
55         let snippet = self.span_to_snippet(original).unwrap();
56         let offset = snippet.find_uncommented(needle).unwrap();
57
58         original.lo() + BytePos(offset as u32)
59     }
60
61     fn opt_span_after(&self, original: Span, needle: &str) -> Option<BytePos> {
62         let snippet = self.span_to_snippet(original).ok()?;
63         let offset = snippet.find_uncommented(needle)? + needle.len();
64
65         Some(original.lo() + BytePos(offset as u32))
66     }
67 }
68
69 impl LineRangeUtils for CodeMap {
70     fn lookup_line_range(&self, span: Span) -> LineRange {
71         let lo = self.lookup_line(span.lo()).unwrap();
72         let hi = self.lookup_line(span.hi()).unwrap();
73
74         assert_eq!(
75             lo.fm.name, hi.fm.name,
76             "span crossed file boundary: lo: {:?}, hi: {:?}",
77             lo, hi
78         );
79
80         // Line numbers start at 1
81         LineRange {
82             file: lo.fm.clone(),
83             lo: lo.line + 1,
84             hi: hi.line + 1,
85         }
86     }
87 }