diff options
Diffstat (limited to 'src/libsyntax_pos/lib.rs')
| -rw-r--r-- | src/libsyntax_pos/lib.rs | 164 |
1 files changed, 109 insertions, 55 deletions
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 02a7433d946..a17cd7625fb 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,7 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; pub mod edition; use edition::Edition; pub mod hygiene; -pub use hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind, MacroKind, DesugaringKind}; +pub use hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind, MacroKind, DesugaringKind}; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -49,7 +49,6 @@ pub struct Globals { symbol_interner: Lock<symbol::Interner>, span_interner: Lock<span_encoding::SpanInterner>, hygiene_data: Lock<hygiene::HygieneData>, - edition: Edition, } impl Globals { @@ -58,7 +57,6 @@ impl Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), - edition, } } } @@ -288,6 +286,17 @@ impl Span { span.lo.0 == 0 && span.hi.0 == 0 } + /// Returns `true` if this span comes from a macro or desugaring. + #[inline] + pub fn from_expansion(self) -> bool { + self.ctxt() != SyntaxContext::root() + } + + #[inline] + pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span { + Span::new(lo, hi, SyntaxContext::root()) + } + /// Returns a new span representing an empty span at the beginning of this span #[inline] pub fn shrink_to_lo(self) -> Span { @@ -344,20 +353,20 @@ impl Span { /// Returns the source span -- this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(self) -> Span { - self.ctxt().outer_expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + let expn_data = self.ctxt().outer_expn_data(); + if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self } } /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any. pub fn parent(self) -> Option<Span> { - self.ctxt().outer_expn_info().map(|i| i.call_site) + let expn_data = self.ctxt().outer_expn_data(); + if !expn_data.is_root() { Some(expn_data.call_site) } else { None } } /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { - self.ctxt().outer_expn_info().map_or_else(|| { - Edition::from_session() - }, |einfo| einfo.edition) + self.ctxt().outer_expn_data().edition } #[inline] @@ -373,52 +382,42 @@ impl Span { /// Returns the source callee. /// /// Returns `None` if the supplied span has no expansion trace, - /// else returns the `ExpnInfo` for the macro definition + /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. - pub fn source_callee(self) -> Option<ExpnInfo> { - fn source_callee(info: ExpnInfo) -> ExpnInfo { - match info.call_site.ctxt().outer_expn_info() { - Some(info) => source_callee(info), - None => info, - } + pub fn source_callee(self) -> Option<ExpnData> { + fn source_callee(expn_data: ExpnData) -> ExpnData { + let next_expn_data = expn_data.call_site.ctxt().outer_expn_data(); + if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data } } - self.ctxt().outer_expn_info().map(source_callee) + let expn_data = self.ctxt().outer_expn_data(); + if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None } } /// Checks if a span is "internal" to a macro in which `#[unstable]` /// items can be used (that is, a macro marked with /// `#[allow_internal_unstable]`). pub fn allows_unstable(&self, feature: Symbol) -> bool { - match self.ctxt().outer_expn_info() { - Some(info) => info - .allow_internal_unstable - .map_or(false, |features| features.iter().any(|&f| - f == feature || f == sym::allow_internal_unstable_backcompat_hack - )), - None => false, - } + self.ctxt().outer_expn_data().allow_internal_unstable.map_or(false, |features| { + features.iter().any(|&f| { + f == feature || f == sym::allow_internal_unstable_backcompat_hack + }) + }) } /// Checks if this span arises from a compiler desugaring of kind `kind`. pub fn is_desugaring(&self, kind: DesugaringKind) -> bool { - match self.ctxt().outer_expn_info() { - Some(info) => match info.kind { - ExpnKind::Desugaring(k) => k == kind, - _ => false, - }, - None => false, + match self.ctxt().outer_expn_data().kind { + ExpnKind::Desugaring(k) => k == kind, + _ => false, } } /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. pub fn desugaring_kind(&self) -> Option<DesugaringKind> { - match self.ctxt().outer_expn_info() { - Some(info) => match info.kind { - ExpnKind::Desugaring(k) => Some(k), - _ => None - }, - None => None + match self.ctxt().outer_expn_data().kind { + ExpnKind::Desugaring(k) => Some(k), + _ => None } } @@ -426,19 +425,20 @@ impl Span { /// can be used without triggering the `unsafe_code` lint // (that is, a macro marked with `#[allow_internal_unsafe]`). pub fn allows_unsafe(&self) -> bool { - match self.ctxt().outer_expn_info() { - Some(info) => info.allow_internal_unsafe, - None => false, - } + self.ctxt().outer_expn_data().allow_internal_unsafe } pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> { let mut prev_span = DUMMY_SP; let mut result = vec![]; - while let Some(info) = self.ctxt().outer_expn_info() { + loop { + let expn_data = self.ctxt().outer_expn_data(); + if expn_data.is_root() { + break; + } // Don't print recursive invocations. - if !info.call_site.source_equal(&prev_span) { - let (pre, post) = match info.kind { + if !expn_data.call_site.source_equal(&prev_span) { + let (pre, post) = match expn_data.kind { ExpnKind::Root => break, ExpnKind::Desugaring(..) => ("desugaring of ", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { @@ -448,14 +448,14 @@ impl Span { } }; result.push(MacroBacktrace { - call_site: info.call_site, - macro_decl_name: format!("{}{}{}", pre, info.kind.descr(), post), - def_site_span: info.def_site, + call_site: expn_data.call_site, + macro_decl_name: format!("{}{}{}", pre, expn_data.kind.descr(), post), + def_site_span: expn_data.def_site, }); } prev_span = self; - self = info.call_site; + self = expn_data.call_site; } result } @@ -468,9 +468,9 @@ impl Span { // Return the macro span on its own to avoid weird diagnostic output. It is preferable to // have an incomplete span than a completely nonsensical one. if span_data.ctxt != end_data.ctxt { - if span_data.ctxt == SyntaxContext::empty() { + if span_data.ctxt == SyntaxContext::root() { return end; - } else if end_data.ctxt == SyntaxContext::empty() { + } else if end_data.ctxt == SyntaxContext::root() { return self; } // Both spans fall within a macro. @@ -479,7 +479,7 @@ impl Span { Span::new( cmp::min(span_data.lo, end_data.lo), cmp::max(span_data.hi, end_data.hi), - if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt }, + if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt }, ) } @@ -490,7 +490,7 @@ impl Span { Span::new( span.hi, end.lo, - if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt }, + if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, ) } @@ -501,7 +501,7 @@ impl Span { Span::new( span.lo, end.lo, - if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt }, + if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, ) } @@ -611,7 +611,7 @@ impl rustc_serialize::UseSpecializedDecodable for Span { d.read_struct("Span", 2, |d| { let lo = d.read_struct_field("lo", 0, Decodable::decode)?; let hi = d.read_struct_field("hi", 1, Decodable::decode)?; - Ok(Span::new(lo, hi, NO_EXPANSION)) + Ok(Span::with_root_ctxt(lo, hi)) }) } } @@ -755,8 +755,6 @@ impl From<Vec<Span>> for MultiSpan { } } -pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); - /// Identifies an offset of a multi-byte character in a `SourceFile`. #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)] pub struct MultiByteChar { @@ -1045,6 +1043,7 @@ impl SourceFile { mut src: String, start_pos: BytePos) -> Result<SourceFile, OffsetOverflowError> { remove_bom(&mut src); + normalize_newlines(&mut src); let src_hash = { let mut hasher: StableHasher<u128> = StableHasher::new(); @@ -1212,6 +1211,61 @@ fn remove_bom(src: &mut String) { } } + +/// Replaces `\r\n` with `\n` in-place in `src`. +/// +/// Returns error if there's a lone `\r` in the string +fn normalize_newlines(src: &mut String) { + if !src.as_bytes().contains(&b'\r') { + return; + } + + // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. + // While we *can* call `as_mut_vec` and do surgery on the live string + // directly, let's rather steal the contents of `src`. This makes the code + // safe even if a panic occurs. + + let mut buf = std::mem::replace(src, String::new()).into_bytes(); + let mut gap_len = 0; + let mut tail = buf.as_mut_slice(); + loop { + let idx = match find_crlf(&tail[gap_len..]) { + None => tail.len(), + Some(idx) => idx + gap_len, + }; + tail.copy_within(gap_len..idx, 0); + tail = &mut tail[idx - gap_len..]; + if tail.len() == gap_len { + break; + } + gap_len += 1; + } + + // Account for removed `\r`. + // After `set_len`, `buf` is guaranteed to contain utf-8 again. + let new_len = buf.len() - gap_len; + unsafe { + buf.set_len(new_len); + *src = String::from_utf8_unchecked(buf); + } + + fn find_crlf(src: &[u8]) -> Option<usize> { + let mut search_idx = 0; + while let Some(idx) = find_cr(&src[search_idx..]) { + if src[search_idx..].get(idx + 1) != Some(&b'\n') { + search_idx += idx + 1; + continue; + } + return Some(search_idx + idx); + } + None + } + + fn find_cr(src: &[u8]) -> Option<usize> { + src.iter().position(|&b| b == b'\r') + } +} + // _____________________________________________________________________________ // Pos, BytePos, CharPos // |
