summary refs log tree commit diff
path: root/src/libproc_macro
diff options
context:
space:
mode:
authorAustin Bonander <austin.bonander@gmail.com>2017-08-01 18:05:08 -0700
committerAustin Bonander <austin.bonander@gmail.com>2017-10-05 17:00:55 -0700
commit7be36d2a6d8855c4ca8ef7ae469f9aac8bf6e63b (patch)
treeb02699f2441b596ff5d4e0279ac65576a2a090f8 /src/libproc_macro
parentc6884b12d9298f1e0af919cb9458a0d80acb3b0a (diff)
downloadrust-7be36d2a6d8855c4ca8ef7ae469f9aac8bf6e63b.tar.gz
rust-7be36d2a6d8855c4ca8ef7ae469f9aac8bf6e63b.zip
`proc_macro::Span` API improvements
Diffstat (limited to 'src/libproc_macro')
-rw-r--r--src/libproc_macro/lib.rs131
1 files changed, 128 insertions, 3 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 2c540c8de8f..e6307f10c13 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -50,6 +50,7 @@ mod diagnostic;
 pub use diagnostic::{Diagnostic, Level};
 
 use std::{ascii, fmt, iter};
+use std::rc::Rc;
 use std::str::FromStr;
 
 use syntax::ast;
@@ -58,7 +59,7 @@ use syntax::parse::{self, token};
 use syntax::symbol::Symbol;
 use syntax::tokenstream;
 use syntax_pos::DUMMY_SP;
-use syntax_pos::SyntaxContext;
+use syntax_pos::{FileMap, Pos, SyntaxContext};
 use syntax_pos::hygiene::Mark;
 
 /// The main type provided by this crate, representing an abstract stream of
@@ -173,7 +174,7 @@ impl TokenStream {
 
 /// A region of source code, along with macro expansion information.
 #[unstable(feature = "proc_macro", issue = "38356")]
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct Span(syntax_pos::Span);
 
 #[unstable(feature = "proc_macro", issue = "38356")]
@@ -211,12 +212,132 @@ impl Span {
         ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
     }
 
+    /// The original source file into which this span points.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn source_file(&self) -> SourceFile {
+        SourceFile {
+            filemap: __internal::lookup_char_pos(self.0.lo()).file,
+        }
+    }
+
+    /// Get the starting line/column in the source file for this span.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn start(&self) -> LineColumn {
+        let loc = __internal::lookup_char_pos(self.0.lo());
+        LineColumn {
+            line: loc.line,
+            column: loc.col.to_usize()
+        }
+    }
+
+    /// Get the ending line/column in the source file for this span.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn end(&self) -> LineColumn {
+        let loc = __internal::lookup_char_pos(self.0.hi());
+        LineColumn {
+            line: loc.line,
+            column: loc.col.to_usize()
+        }
+    }
+
+    /// Create a new span encompassing `self` and `other`.
+    ///
+    /// Returns `None` if `self` and `other` are from different files.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn join(&self, other: Span) -> Option<Span> {
+        let self_loc = __internal::lookup_char_pos(self.0.lo());
+        let other_loc = __internal::lookup_char_pos(self.0.lo());
+
+        if self_loc.file.name != other_loc.file.name { return None }
+
+        Some(Span(self.0.to(other.0)))
+    }
+
     diagnostic_method!(error, Level::Error);
     diagnostic_method!(warning, Level::Warning);
     diagnostic_method!(note, Level::Note);
     diagnostic_method!(help, Level::Help);
 }
 
+/// A line-column pair representing the start or end of a `Span`.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct LineColumn {
+    /// The 1-indexed line in the source file on which the span starts or ends (inclusive).
+    line: usize,
+    /// The 0-indexed column (in UTF-8 characters) in the source file on which
+    /// the span starts or ends (inclusive).
+    column: usize
+}
+
+/// The source file of a given `Span`.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Clone)]
+pub struct SourceFile {
+    filemap: Rc<FileMap>,
+}
+
+impl SourceFile {
+    /// Get the path to this source file as a string.
+    ///
+    /// ### Note
+    /// If the code span associated with this `SourceFile` was generated by an external macro, this
+    /// may not be an actual path on the filesystem. Use [`is_real`] to check.
+    ///
+    /// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on
+    /// the command line, the path as given may not actually be valid.
+    ///
+    /// [`is_real`]: #method.is_real
+    # [unstable(feature = "proc_macro", issue = "38356")]
+    pub fn as_str(&self) -> &str {
+        &self.filemap.name
+    }
+
+    /// Returns `true` if this source file is a real source file, and not generated by an external
+    /// macro's expansion.
+    # [unstable(feature = "proc_macro", issue = "38356")]
+    pub fn is_real(&self) -> bool {
+        // This is a hack until intercrate spans are implemented and we can have real source files
+        // for spans generated in external macros.
+        // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
+        self.filemap.is_real_file()
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl AsRef<str> for SourceFile {
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl fmt::Debug for SourceFile {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("SourceFile")
+            .field("path", &self.as_str())
+            .field("is_real", &self.is_real())
+            .finish()
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl PartialEq for SourceFile {
+    fn eq(&self, other: &Self) -> bool {
+        Rc::ptr_eq(&self.filemap, &other.filemap)
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl Eq for SourceFile {}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl PartialEq<str> for SourceFile {
+    fn eq(&self, other: &str) -> bool {
+        self.as_ref() == other
+    }
+}
+
 /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
 #[unstable(feature = "proc_macro", issue = "38356")]
 #[derive(Clone, Debug)]
@@ -618,10 +739,14 @@ pub mod __internal {
     use syntax::parse::{self, ParseSess};
     use syntax::parse::token::{self, Token};
     use syntax::tokenstream;
-    use syntax_pos::DUMMY_SP;
+    use syntax_pos::{BytePos, Loc, DUMMY_SP};
 
     use super::{TokenStream, LexError};
 
+    pub fn lookup_char_pos(pos: BytePos) -> Loc {
+        with_sess(|(sess, _)| sess.codemap().lookup_char_pos(pos))
+    }
+
     pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
         let token = Token::interpolated(token::NtItem(item));
         TokenStream(tokenstream::TokenTree::Token(DUMMY_SP, token).into())