]>
git.proxmox.com Git - rustc.git/blob - 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.
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.
11 use rustc
::session
::Session
;
19 use syntax
::parse
::lexer
::{self, StringReader}
;
20 use syntax
::parse
::token
::{self, Token}
;
21 use syntax
::symbol
::keywords
;
25 pub struct SpanUtils
<'a
> {
26 pub sess
: &'a Session
,
27 // FIXME given that we clone SpanUtils all over the place, this err_count is
28 // probably useless and any logic relying on it is bogus.
29 pub err_count
: Cell
<isize>,
32 impl<'a
> SpanUtils
<'a
> {
33 pub fn new(sess
: &'a Session
) -> SpanUtils
<'a
> {
36 err_count
: Cell
::new(0),
40 pub fn make_path_string(file_name
: &str) -> String
{
41 let path
= Path
::new(file_name
);
42 if path
.is_absolute() {
43 path
.clone().display().to_string()
53 pub fn snippet(&self, span
: Span
) -> String
{
54 match self.sess
.codemap().span_to_snippet(span
) {
56 Err(_
) => String
::new(),
60 pub fn retokenise_span(&self, span
: Span
) -> StringReader
<'a
> {
61 lexer
::StringReader
::retokenize(&self.sess
.parse_sess
, span
)
64 // Re-parses a path and returns the span for the last identifier in the path
65 pub fn span_for_last_ident(&self, span
: Span
) -> Option
<Span
> {
66 let mut result
= None
;
68 let mut toks
= self.retokenise_span(span
);
69 let mut bracket_count
= 0;
71 let ts
= toks
.real_token();
72 if ts
.tok
== token
::Eof
{
75 if bracket_count
== 0 && (ts
.tok
.is_ident() || ts
.tok
.is_keyword(keywords
::SelfValue
)) {
79 bracket_count
+= match ts
.tok
{
82 token
::BinOp(token
::Shr
) => -2,
88 // Return the span for the first identifier in the path.
89 pub fn span_for_first_ident(&self, span
: Span
) -> Option
<Span
> {
90 let mut toks
= self.retokenise_span(span
);
91 let mut bracket_count
= 0;
93 let ts
= toks
.real_token();
94 if ts
.tok
== token
::Eof
{
97 if bracket_count
== 0 && (ts
.tok
.is_ident() || ts
.tok
.is_keyword(keywords
::SelfValue
)) {
101 bracket_count
+= match ts
.tok
{
104 token
::BinOp(token
::Shr
) => -2,
110 // Return the span for the last ident before a `<` and outside any
111 // angle brackets, or the last span.
112 pub fn sub_span_for_type_name(&self, span
: Span
) -> Option
<Span
> {
113 let mut toks
= self.retokenise_span(span
);
114 let mut prev
= toks
.real_token();
115 let mut result
= None
;
117 // We keep track of the following two counts - the depth of nesting of
118 // angle brackets, and the depth of nesting of square brackets. For the
119 // angle bracket count, we only count tokens which occur outside of any
120 // square brackets (i.e. bracket_count == 0). The intutition here is
121 // that we want to count angle brackets in the type, but not any which
122 // could be in expression context (because these could mean 'less than',
124 let mut angle_count
= 0;
125 let mut bracket_count
= 0;
127 let next
= toks
.real_token();
129 if (next
.tok
== token
::Lt
|| next
.tok
== token
::Colon
) && angle_count
== 0
130 && bracket_count
== 0 && prev
.tok
.is_ident()
132 result
= Some(prev
.sp
);
135 if bracket_count
== 0 {
136 angle_count
+= match prev
.tok
{
139 token
::BinOp(token
::Shl
) => 2,
140 token
::BinOp(token
::Shr
) => -2,
145 bracket_count
+= match prev
.tok
{
146 token
::OpenDelim(token
::Bracket
) => 1,
147 token
::CloseDelim(token
::Bracket
) => -1,
151 if next
.tok
== token
::Eof
{
156 if angle_count
!= 0 || bracket_count
!= 0 {
157 let loc
= self.sess
.codemap().lookup_char_pos(span
.lo());
160 "Mis-counted brackets when breaking path? Parsing '{}' \
167 if result
.is_none() && prev
.tok
.is_ident() && angle_count
== 0 {
168 return Some(prev
.sp
);
173 pub fn sub_span_before_token(&self, span
: Span
, tok
: Token
) -> Option
<Span
> {
174 let mut toks
= self.retokenise_span(span
);
175 let mut prev
= toks
.real_token();
177 if prev
.tok
== token
::Eof
{
180 let next
= toks
.real_token();
182 return Some(prev
.sp
);
188 pub fn sub_span_of_token(&self, span
: Span
, tok
: Token
) -> Option
<Span
> {
189 let mut toks
= self.retokenise_span(span
);
191 let next
= toks
.real_token();
192 if next
.tok
== token
::Eof
{
196 return Some(next
.sp
);
201 pub fn sub_span_after_keyword(&self, span
: Span
, keyword
: keywords
::Keyword
) -> Option
<Span
> {
202 self.sub_span_after(span
, |t
| t
.is_keyword(keyword
))
205 pub fn sub_span_after_token(&self, span
: Span
, tok
: Token
) -> Option
<Span
> {
206 self.sub_span_after(span
, |t
| t
== tok
)
209 fn sub_span_after
<F
: Fn(Token
) -> bool
>(&self, span
: Span
, f
: F
) -> Option
<Span
> {
210 let mut toks
= self.retokenise_span(span
);
212 let ts
= toks
.real_token();
213 if ts
.tok
== token
::Eof
{
217 let ts
= toks
.real_token();
218 if ts
.tok
== token
::Eof
{
227 // // Return the name for a macro definition (identifier after first `!`)
228 // pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
229 // let mut toks = self.retokenise_span(span);
231 // let ts = toks.real_token();
232 // if ts.tok == token::Eof {
235 // if ts.tok == token::Not {
236 // let ts = toks.real_token();
237 // if ts.tok.is_ident() {
238 // return Some(ts.sp);
246 // // Return the name for a macro use (identifier before first `!`).
247 // pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> {
248 // let mut toks = self.retokenise_span(span);
249 // let mut prev = toks.real_token();
251 // if prev.tok == token::Eof {
254 // let ts = toks.real_token();
255 // if ts.tok == token::Not {
256 // if prev.tok.is_ident() {
257 // return Some(prev.sp);
266 /// Return true if the span is generated code, and
267 /// it is not a subspan of the root callsite.
269 /// Used to filter out spans of minimal value,
270 /// such as references to macro internal variables.
271 pub fn filter_generated(&self, sub_span
: Option
<Span
>, parent
: Span
) -> bool
{
272 if !generated_code(parent
) {
273 if sub_span
.is_none() {
274 // Edge case - this occurs on generated code with incorrect expansion info.
279 // If sub_span is none, filter out generated code.
280 let sub_span
= match sub_span
{
285 //If the span comes from a fake filemap, filter it.
288 .lookup_char_pos(parent
.lo())
295 // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
296 // callsite. This filters out macro internal variables and most malformed spans.
297 !parent
.source_callsite().contains(sub_span
)
301 macro_rules
! filter
{
302 ($util
: expr
, $span
: expr
, $parent
: expr
, None
) => {
303 if $util
.filter_generated($span
, $parent
) {
307 ($util
: expr
, $span
: ident
, $parent
: expr
) => {
308 if $util
.filter_generated($span
, $parent
) {