]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax_pos/lib.rs
Auto merge of #43710 - zackmdavis:field_init_shorthand_power_slam, r=Mark-Simulacrum
[rust.git] / src / libsyntax_pos / lib.rs
index 25f74aeecf4046eed1ce357fb435ed246a002203..f5449061b87fabed7eb3d096ebb3c3b5945823b7 100644 (file)
 
 #![feature(const_fn)]
 #![feature(custom_attribute)]
+#![feature(i128_type)]
 #![feature(optin_builtin_traits)]
 #![allow(unused_attributes)]
 #![feature(specialization)]
 
-#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
-#![cfg_attr(stage0, feature(rustc_private))]
-#![cfg_attr(stage0, feature(staged_api))]
-
+use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
+use std::cmp;
+use std::fmt;
+use std::hash::Hasher;
 use std::ops::{Add, Sub};
 use std::rc::Rc;
-use std::cmp;
 
-use std::fmt;
+use rustc_data_structures::stable_hasher::StableHasher;
+
+extern crate rustc_data_structures;
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
@@ -98,6 +100,7 @@ pub fn substitute_dummy(self, other: Span) -> Span {
         if self.source_equal(&DUMMY_SP) { other } else { self }
     }
 
+    /// Return true if `self` fully encloses `other`.
     pub fn contains(self, other: Span) -> bool {
         self.lo <= other.lo && other.hi <= self.hi
     }
@@ -150,6 +153,16 @@ pub fn allows_unstable(&self) -> bool {
         }
     }
 
+    /// Check if a span is "internal" to a macro in which `unsafe`
+    /// 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.callee.allow_internal_unsafe,
+            None => false,
+        }
+    }
+
     pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
         let mut prev_span = DUMMY_SP;
         let mut result = vec![];
@@ -171,8 +184,8 @@ pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
             if !info.call_site.source_equal(&prev_span) {
                 result.push(MacroBacktrace {
                     call_site: info.call_site,
-                    macro_decl_name: macro_decl_name,
-                    def_site_span: def_site_span,
+                    macro_decl_name,
+                    def_site_span,
                 });
             }
 
@@ -182,15 +195,21 @@ pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
         result
     }
 
+    /// Return a `Span` that would enclose both `self` and `end`.
     pub fn to(self, end: Span) -> Span {
-        // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
-        if end.ctxt == SyntaxContext::empty() {
-            Span { lo: self.lo, ..end }
-        } else {
-            Span { hi: end.hi, ..self }
+        Span {
+            lo: cmp::min(self.lo, end.lo),
+            hi: cmp::max(self.hi, end.hi),
+            // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
+            ctxt: if self.ctxt == SyntaxContext::empty() {
+                end.ctxt
+            } else {
+                self.ctxt
+            },
         }
     }
 
+    /// Return a `Span` between the end of `self` to the beginning of `end`.
     pub fn between(self, end: Span) -> Span {
         Span {
             lo: self.hi,
@@ -203,6 +222,7 @@ pub fn between(self, end: Span) -> Span {
         }
     }
 
+    /// Return a `Span` between the beginning of `self` to the beginning of `end`.
     pub fn until(self, end: Span) -> Span {
         Span {
             lo: self.lo,
@@ -229,6 +249,12 @@ pub struct SpanLabel {
     pub label: Option<String>,
 }
 
+impl Default for Span {
+    fn default() -> Self {
+        DUMMY_SP
+    }
+}
+
 impl serialize::UseSpecializedEncodable for Span {
     fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_struct("Span", 2, |s| {
@@ -302,7 +328,7 @@ pub fn primary_spans(&self) -> &[Span] {
         &self.primary_spans
     }
 
-    /// Replaces all occurances of one Span with another. Used to move Spans in areas that don't
+    /// Replaces all occurrences of one Span with another. Used to move Spans in areas that don't
     /// display well (like std macros). Returns true if replacements occurred.
     pub fn replace(&mut self, before: Span, after: Span) -> bool {
         let mut replacements_occurred = false;
@@ -332,7 +358,7 @@ pub fn span_labels(&self) -> Vec<SpanLabel> {
 
         for &(span, ref label) in &self.span_labels {
             span_labels.push(SpanLabel {
-                span: span,
+                span,
                 is_primary: is_primary(span),
                 label: Some(label.clone())
             });
@@ -341,7 +367,7 @@ pub fn span_labels(&self) -> Vec<SpanLabel> {
         for &span in &self.primary_spans {
             if !span_labels.iter().any(|sl| sl.span == span) {
                 span_labels.push(SpanLabel {
-                    span: span,
+                    span,
                     is_primary: true,
                     label: None
                 });
@@ -369,6 +395,35 @@ pub struct MultiByteChar {
     pub bytes: usize,
 }
 
+/// The state of the lazy external source loading mechanism of a FileMap.
+#[derive(PartialEq, Eq, Clone)]
+pub enum ExternalSource {
+    /// The external source has been loaded already.
+    Present(String),
+    /// No attempt has been made to load the external source.
+    AbsentOk,
+    /// A failed attempt has been made to load the external source.
+    AbsentErr,
+    /// No external source has to be loaded, since the FileMap represents a local crate.
+    Unneeded,
+}
+
+impl ExternalSource {
+    pub fn is_absent(&self) -> bool {
+        match *self {
+            ExternalSource::Present(_) => false,
+            _ => true,
+        }
+    }
+
+    pub fn get_source(&self) -> Option<&str> {
+        match *self {
+            ExternalSource::Present(ref src) => Some(src),
+            _ => None,
+        }
+    }
+}
+
 /// A single source in the CodeMap.
 #[derive(Clone)]
 pub struct FileMap {
@@ -382,6 +437,11 @@ pub struct FileMap {
     pub crate_of_origin: u32,
     /// The complete source code
     pub src: Option<Rc<String>>,
+    /// The source code's hash
+    pub src_hash: u128,
+    /// The external source code (used for external crates, which will have a `None`
+    /// value as `self.src`.
+    pub external_src: RefCell<ExternalSource>,
     /// The start position of this source in the CodeMap
     pub start_pos: BytePos,
     /// The end position of this source in the CodeMap
@@ -394,9 +454,10 @@ pub struct FileMap {
 
 impl Encodable for FileMap {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct("FileMap", 6, |s| {
+        s.emit_struct("FileMap", 7, |s| {
             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
             s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
+            s.emit_struct_field("src_hash", 6, |s| self.src_hash.encode(s))?;
             s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
             s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
             s.emit_struct_field("lines", 4, |s| {
@@ -459,7 +520,10 @@ fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> {
             let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
             let name_was_remapped: bool =
                 d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
-            let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
+            let src_hash: u128 =
+                d.read_struct_field("src_hash", 6, |d| Decodable::decode(d))?;
+            let start_pos: BytePos =
+                d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
             let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
             let lines: Vec<BytePos> = d.read_struct_field("lines", 4, |d| {
                 let num_lines: u32 = Decodable::decode(d)?;
@@ -492,15 +556,17 @@ fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> {
             let multibyte_chars: Vec<MultiByteChar> =
                 d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
             Ok(FileMap {
-                name: name,
-                name_was_remapped: name_was_remapped,
+                name,
+                name_was_remapped,
                 // `crate_of_origin` has to be set by the importer.
                 // This value matches up with rustc::hir::def_id::INVALID_CRATE.
                 // That constant is not available here unfortunately :(
                 crate_of_origin: ::std::u32::MAX - 1,
-                start_pos: start_pos,
-                end_pos: end_pos,
+                start_pos,
+                end_pos,
                 src: None,
+                src_hash,
+                external_src: RefCell::new(ExternalSource::AbsentOk),
                 lines: RefCell::new(lines),
                 multibyte_chars: RefCell::new(multibyte_chars)
             })
@@ -515,6 +581,32 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl FileMap {
+    pub fn new(name: FileName,
+               name_was_remapped: bool,
+               mut src: String,
+               start_pos: BytePos) -> FileMap {
+        remove_bom(&mut src);
+
+        let mut hasher: StableHasher<u128> = StableHasher::new();
+        hasher.write(src.as_bytes());
+        let src_hash = hasher.finish();
+
+        let end_pos = start_pos.to_usize() + src.len();
+
+        FileMap {
+            name,
+            name_was_remapped,
+            crate_of_origin: 0,
+            src: Some(Rc::new(src)),
+            src_hash,
+            external_src: RefCell::new(ExternalSource::Unneeded),
+            start_pos,
+            end_pos: Pos::from_usize(end_pos),
+            lines: RefCell::new(Vec::new()),
+            multibyte_chars: RefCell::new(Vec::new()),
+        }
+    }
+
     /// EFFECT: register a start-of-line offset in the
     /// table of line-beginnings.
     /// UNCHECKED INVARIANT: these offsets must be added in the right
@@ -532,34 +624,71 @@ pub fn next_line(&self, pos: BytePos) {
         lines.push(pos);
     }
 
-    /// get a line from the list of pre-computed line-beginnings.
-    /// line-number here is 0-based.
-    pub fn get_line(&self, line_number: usize) -> Option<&str> {
-        match self.src {
-            Some(ref src) => {
-                let lines = self.lines.borrow();
-                lines.get(line_number).map(|&line| {
-                    let begin: BytePos = line - self.start_pos;
-                    let begin = begin.to_usize();
-                    // We can't use `lines.get(line_number+1)` because we might
-                    // be parsing when we call this function and thus the current
-                    // line is the last one we have line info for.
-                    let slice = &src[begin..];
-                    match slice.find('\n') {
-                        Some(e) => &slice[..e],
-                        None => slice
-                    }
-                })
+    /// Add externally loaded source.
+    /// If the hash of the input doesn't match or no input is supplied via None,
+    /// it is interpreted as an error and the corresponding enum variant is set.
+    /// The return value signifies whether some kind of source is present.
+    pub fn add_external_src<F>(&self, get_src: F) -> bool
+        where F: FnOnce() -> Option<String>
+    {
+        if *self.external_src.borrow() == ExternalSource::AbsentOk {
+            let src = get_src();
+            let mut external_src = self.external_src.borrow_mut();
+            if let Some(src) = src {
+                let mut hasher: StableHasher<u128> = StableHasher::new();
+                hasher.write(src.as_bytes());
+
+                if hasher.finish() == self.src_hash {
+                    *external_src = ExternalSource::Present(src);
+                    return true;
+                }
+            } else {
+                *external_src = ExternalSource::AbsentErr;
+            }
+
+            false
+        } else {
+            self.src.is_some() || self.external_src.borrow().get_source().is_some()
+        }
+    }
+
+    /// Get a line from the list of pre-computed line-beginnings.
+    /// The line number here is 0-based.
+    pub fn get_line(&self, line_number: usize) -> Option<Cow<str>> {
+        fn get_until_newline(src: &str, begin: usize) -> &str {
+            // We can't use `lines.get(line_number+1)` because we might
+            // be parsing when we call this function and thus the current
+            // line is the last one we have line info for.
+            let slice = &src[begin..];
+            match slice.find('\n') {
+                Some(e) => &slice[..e],
+                None => slice
             }
-            None => None
+        }
+
+        let lines = self.lines.borrow();
+        let line = if let Some(line) = lines.get(line_number) {
+            line
+        } else {
+            return None;
+        };
+        let begin: BytePos = *line - self.start_pos;
+        let begin = begin.to_usize();
+
+        if let Some(ref src) = self.src {
+            Some(Cow::from(get_until_newline(src, begin)))
+        } else if let Some(src) = self.external_src.borrow().get_source() {
+            Some(Cow::Owned(String::from(get_until_newline(src, begin))))
+        } else {
+            None
         }
     }
 
     pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) {
         assert!(bytes >=2 && bytes <= 4);
         let mbc = MultiByteChar {
-            pos: pos,
-            bytes: bytes,
+            pos,
+            bytes,
         };
         self.multibyte_chars.borrow_mut().push(mbc);
     }
@@ -614,6 +743,13 @@ pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) {
     }
 }
 
+/// Remove utf-8 BOM if any.
+fn remove_bom(src: &mut String) {
+    if src.starts_with("\u{feff}") {
+        src.drain(..3);
+    }
+}
+
 // _____________________________________________________________________________
 // Pos, BytePos, CharPos
 //
@@ -743,6 +879,7 @@ pub struct FileLines {
 thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
                 Cell::new(default_span_debug));
 
+#[derive(Debug)]
 pub struct MacroBacktrace {
     /// span where macro was applied to generate this code
     pub call_site: Span,