]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/span_utils.rs
Remove intermediate forms and some other refactoring
[rust.git] / src / librustc_save_analysis / span_utils.rs
1 // Copyright 2012-2014 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 use rustc::session::Session;
12
13 use generated_code;
14
15 use std::cell::Cell;
16 use std::env;
17 use std::path::Path;
18
19 use syntax::ast;
20 use syntax::parse::lexer::{self, StringReader};
21 use syntax::parse::token::{self, Token};
22 use syntax::symbol::keywords;
23 use syntax_pos::*;
24
25 #[derive(Clone)]
26 pub struct SpanUtils<'a> {
27     pub sess: &'a Session,
28     // FIXME given that we clone SpanUtils all over the place, this err_count is
29     // probably useless and any logic relying on it is bogus.
30     pub err_count: Cell<isize>,
31 }
32
33 impl<'a> SpanUtils<'a> {
34     pub fn new(sess: &'a Session) -> SpanUtils<'a> {
35         SpanUtils {
36             sess: sess,
37             err_count: Cell::new(0),
38         }
39     }
40
41     pub fn make_path_string(file_name: &str) -> String {
42         let path = Path::new(file_name);
43         if path.is_absolute() {
44             path.clone().display().to_string()
45         } else {
46             env::current_dir().unwrap().join(&path).display().to_string()
47         }
48     }
49
50     pub fn snippet(&self, span: Span) -> String {
51         match self.sess.codemap().span_to_snippet(span) {
52             Ok(s) => s,
53             Err(_) => String::new(),
54         }
55     }
56
57     pub fn retokenise_span(&self, span: Span) -> StringReader<'a> {
58         lexer::StringReader::retokenize(&self.sess.parse_sess, span)
59     }
60
61     // Re-parses a path and returns the span for the last identifier in the path
62     pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
63         let mut result = None;
64
65         let mut toks = self.retokenise_span(span);
66         let mut bracket_count = 0;
67         loop {
68             let ts = toks.real_token();
69             if ts.tok == token::Eof {
70                 return result
71             }
72             if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
73                 result = Some(ts.sp);
74             }
75
76             bracket_count += match ts.tok {
77                 token::Lt => 1,
78                 token::Gt => -1,
79                 token::BinOp(token::Shr) => -2,
80                 _ => 0,
81             }
82         }
83     }
84
85     // Return the span for the first identifier in the path.
86     pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
87         let mut toks = self.retokenise_span(span);
88         let mut bracket_count = 0;
89         loop {
90             let ts = toks.real_token();
91             if ts.tok == token::Eof {
92                 return None;
93             }
94             if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
95                 return Some(ts.sp);
96             }
97
98             bracket_count += match ts.tok {
99                 token::Lt => 1,
100                 token::Gt => -1,
101                 token::BinOp(token::Shr) => -2,
102                 _ => 0,
103             }
104         }
105     }
106
107     // Return the span for the last ident before a `(` or `<` or '::<' and outside any
108     // any brackets, or the last span.
109     pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
110         let mut toks = self.retokenise_span(span);
111         let mut prev = toks.real_token();
112         let mut result = None;
113         let mut bracket_count = 0;
114         let mut prev_span = None;
115         while prev.tok != token::Eof {
116             prev_span = None;
117             let mut next = toks.real_token();
118
119             if (next.tok == token::OpenDelim(token::Paren) || next.tok == token::Lt) &&
120                bracket_count == 0 && prev.tok.is_ident() {
121                 result = Some(prev.sp);
122             }
123
124             if bracket_count == 0 && next.tok == token::ModSep {
125                 let old = prev;
126                 prev = next;
127                 next = toks.real_token();
128                 if next.tok == token::Lt && old.tok.is_ident() {
129                     result = Some(old.sp);
130                 }
131             }
132
133             bracket_count += match prev.tok {
134                 token::OpenDelim(token::Paren) | token::Lt => 1,
135                 token::CloseDelim(token::Paren) | token::Gt => -1,
136                 token::BinOp(token::Shr) => -2,
137                 _ => 0,
138             };
139
140             if prev.tok.is_ident() && bracket_count == 0 {
141                 prev_span = Some(prev.sp);
142             }
143             prev = next;
144         }
145         result.or(prev_span)
146     }
147
148     // Return the span for the last ident before a `<` and outside any
149     // angle brackets, or the last span.
150     pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
151         let mut toks = self.retokenise_span(span);
152         let mut prev = toks.real_token();
153         let mut result = None;
154
155         // We keep track of the following two counts - the depth of nesting of
156         // angle brackets, and the depth of nesting of square brackets. For the
157         // angle bracket count, we only count tokens which occur outside of any
158         // square brackets (i.e. bracket_count == 0). The intutition here is
159         // that we want to count angle brackets in the type, but not any which
160         // could be in expression context (because these could mean 'less than',
161         // etc.).
162         let mut angle_count = 0;
163         let mut bracket_count = 0;
164         loop {
165             let next = toks.real_token();
166
167             if (next.tok == token::Lt || next.tok == token::Colon) &&
168                angle_count == 0 &&
169                bracket_count == 0 &&
170                prev.tok.is_ident() {
171                 result = Some(prev.sp);
172             }
173
174             if bracket_count == 0 {
175                 angle_count += match prev.tok {
176                     token::Lt => 1,
177                     token::Gt => -1,
178                     token::BinOp(token::Shl) => 2,
179                     token::BinOp(token::Shr) => -2,
180                     _ => 0,
181                 };
182             }
183
184             bracket_count += match prev.tok {
185                 token::OpenDelim(token::Bracket) => 1,
186                 token::CloseDelim(token::Bracket) => -1,
187                 _ => 0,
188             };
189
190             if next.tok == token::Eof {
191                 break;
192             }
193             prev = next;
194         }
195         if angle_count != 0 || bracket_count != 0 {
196             let loc = self.sess.codemap().lookup_char_pos(span.lo);
197             span_bug!(span,
198                       "Mis-counted brackets when breaking path? Parsing '{}' \
199                        in {}, line {}",
200                       self.snippet(span),
201                       loc.file.name,
202                       loc.line);
203         }
204         if result.is_none() && prev.tok.is_ident() && angle_count == 0 {
205             return Some(prev.sp);
206         }
207         result
208     }
209
210     // Reparse span and return an owned vector of sub spans of the first limit
211     // identifier tokens in the given nesting level.
212     // example with Foo<Bar<T,V>, Bar<T,V>>
213     // Nesting = 0: all idents outside of angle brackets: [Foo]
214     // Nesting = 1: idents within one level of angle brackets: [Bar, Bar]
215     pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec<Span> {
216         let mut result: Vec<Span> = vec![];
217
218         let mut toks = self.retokenise_span(span);
219         // We keep track of how many brackets we're nested in
220         let mut angle_count: isize = 0;
221         let mut bracket_count: isize = 0;
222         let mut found_ufcs_sep = false;
223         loop {
224             let ts = toks.real_token();
225             if ts.tok == token::Eof {
226                 if angle_count != 0 || bracket_count != 0 {
227                     if generated_code(span) {
228                         return vec![];
229                     }
230                     let loc = self.sess.codemap().lookup_char_pos(span.lo);
231                     span_bug!(span,
232                               "Mis-counted brackets when breaking path? \
233                                Parsing '{}' in {}, line {}",
234                               self.snippet(span),
235                               loc.file.name,
236                               loc.line);
237                 }
238                 return result
239             }
240             if (result.len() as isize) == limit {
241                 return result;
242             }
243             bracket_count += match ts.tok {
244                 token::OpenDelim(token::Bracket) => 1,
245                 token::CloseDelim(token::Bracket) => -1,
246                 _ => 0,
247             };
248             if bracket_count > 0 {
249                 continue;
250             }
251             angle_count += match ts.tok {
252                 token::Lt => 1,
253                 token::Gt => -1,
254                 token::BinOp(token::Shl) => 2,
255                 token::BinOp(token::Shr) => -2,
256                 _ => 0,
257             };
258
259             // Ignore the `>::` in `<Type as Trait>::AssocTy`.
260
261             // The root cause of this hack is that the AST representation of
262             // qpaths is horrible. It treats <A as B>::C as a path with two
263             // segments, B and C and notes that there is also a self type A at
264             // position 0. Because we don't have spans for individual idents,
265             // only the whole path, we have to iterate over the tokens in the
266             // path, trying to pull out the non-nested idents (e.g., avoiding 'a
267             // in `<A as B<'a>>::C`). So we end up with a span for `B>::C` from
268             // the start of the first ident to the end of the path.
269             if !found_ufcs_sep && angle_count == -1 {
270                 found_ufcs_sep = true;
271                 angle_count += 1;
272             }
273             if ts.tok.is_ident() && angle_count == nesting {
274                 result.push(ts.sp);
275             }
276         }
277     }
278
279     pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
280         let mut toks = self.retokenise_span(span);
281         let mut prev = toks.real_token();
282         loop {
283             if prev.tok == token::Eof {
284                 return None;
285             }
286             let next = toks.real_token();
287             if next.tok == tok {
288                 return Some(prev.sp);
289             }
290             prev = next;
291         }
292     }
293
294     pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
295         let mut toks = self.retokenise_span(span);
296         loop {
297             let next = toks.real_token();
298             if next.tok == token::Eof {
299                 return None;
300             }
301             if next.tok == tok {
302                 return Some(next.sp);
303             }
304         }
305     }
306
307     pub fn sub_span_after_keyword(&self, span: Span, keyword: keywords::Keyword) -> Option<Span> {
308         self.sub_span_after(span, |t| t.is_keyword(keyword))
309     }
310
311     pub fn sub_span_after_token(&self, span: Span, tok: Token) -> Option<Span> {
312         self.sub_span_after(span, |t| t == tok)
313     }
314
315     fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> {
316         let mut toks = self.retokenise_span(span);
317         loop {
318             let ts = toks.real_token();
319             if ts.tok == token::Eof {
320                 return None;
321             }
322             if f(ts.tok) {
323                 let ts = toks.real_token();
324                 if ts.tok == token::Eof {
325                     return None
326                 } else {
327                     return Some(ts.sp);
328                 }
329             }
330         }
331     }
332
333
334     // Returns a list of the spans of idents in a path.
335     // E.g., For foo::bar<x,t>::baz, we return [foo, bar, baz] (well, their spans)
336     pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec<Span> {
337         self.spans_with_brackets(path.span, 0, -1)
338     }
339
340     // Return an owned vector of the subspans of the param identifier
341     // tokens found in span.
342     pub fn spans_for_ty_params(&self, span: Span, number: isize) -> Vec<Span> {
343         // Type params are nested within one level of brackets:
344         // i.e. we want Vec<A, B> from Foo<A, B<T,U>>
345         self.spans_with_brackets(span, 1, number)
346     }
347
348     // // Return the name for a macro definition (identifier after first `!`)
349     // pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
350     //     let mut toks = self.retokenise_span(span);
351     //     loop {
352     //         let ts = toks.real_token();
353     //         if ts.tok == token::Eof {
354     //             return None;
355     //         }
356     //         if ts.tok == token::Not {
357     //             let ts = toks.real_token();
358     //             if ts.tok.is_ident() {
359     //                 return Some(ts.sp);
360     //             } else {
361     //                 return None;
362     //             }
363     //         }
364     //     }
365     // }
366
367     // // Return the name for a macro use (identifier before first `!`).
368     // pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> {
369     //     let mut toks = self.retokenise_span(span);
370     //     let mut prev = toks.real_token();
371     //     loop {
372     //         if prev.tok == token::Eof {
373     //             return None;
374     //         }
375     //         let ts = toks.real_token();
376     //         if ts.tok == token::Not {
377     //             if prev.tok.is_ident() {
378     //                 return Some(prev.sp);
379     //             } else {
380     //                 return None;
381     //             }
382     //         }
383     //         prev = ts;
384     //     }
385     // }
386
387     /// Return true if the span is generated code, and
388     /// it is not a subspan of the root callsite.
389     ///
390     /// Used to filter out spans of minimal value,
391     /// such as references to macro internal variables.
392     pub fn filter_generated(&self, sub_span: Option<Span>, parent: Span) -> bool {
393         if !generated_code(parent) {
394             if sub_span.is_none() {
395                 // Edge case - this occurs on generated code with incorrect expansion info.
396                 return true;
397             }
398             return false;
399         }
400         // If sub_span is none, filter out generated code.
401         if sub_span.is_none() {
402             return true;
403         }
404
405         //If the span comes from a fake filemap, filter it.
406         if !self.sess.codemap().lookup_char_pos(parent.lo).file.is_real_file() {
407             return true;
408         }
409
410         // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
411         // callsite. This filters out macro internal variables and most malformed spans.
412         !parent.source_callsite().contains(parent)
413     }
414 }
415
416 macro_rules! filter {
417     ($util: expr, $span: ident, $parent: expr, None) => {
418         if $util.filter_generated($span, $parent) {
419             return None;
420         }
421     };
422     ($util: expr, $span: ident, $parent: expr) => {
423         if $util.filter_generated($span, $parent) {
424             return;
425         }
426     };
427 }