Introduce proc_macro::Span::source_text
This commit is contained in:
parent
d48ab693d1
commit
e88b0d9a94
@ -165,6 +165,7 @@ fn sub(
|
|||||||
fn end($self: $S::Span) -> LineColumn;
|
fn end($self: $S::Span) -> LineColumn;
|
||||||
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||||
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
||||||
|
fn source_text($self: $S::Span) -> Option<String>;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -341,6 +341,18 @@ pub fn eq(&self, other: &Span) -> bool {
|
|||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the source text behind a span. This preserves the original source
|
||||||
|
/// code, including spaces and comments. It only returns a result if the span
|
||||||
|
/// corresponds to real source code.
|
||||||
|
///
|
||||||
|
/// Note: The observable result of a macro should only rely on the tokens and
|
||||||
|
/// not on this source text. The result of this function is a best effort to
|
||||||
|
/// be used for diagnostics only.
|
||||||
|
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||||
|
pub fn source_text(&self) -> Option<String> {
|
||||||
|
self.0.source_text()
|
||||||
|
}
|
||||||
|
|
||||||
diagnostic_method!(error, Level::Error);
|
diagnostic_method!(error, Level::Error);
|
||||||
diagnostic_method!(warning, Level::Warning);
|
diagnostic_method!(warning, Level::Warning);
|
||||||
diagnostic_method!(note, Level::Note);
|
diagnostic_method!(note, Level::Note);
|
||||||
|
@ -748,4 +748,7 @@ fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span>
|
|||||||
fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
|
||||||
span.with_ctxt(at.ctxt())
|
span.with_ctxt(at.ctxt())
|
||||||
}
|
}
|
||||||
|
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||||
|
self.sess.source_map().span_to_snippet(span).ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,3 +43,14 @@ pub fn assert_source_file(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
"".parse().unwrap()
|
"".parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn macro_stringify(input: TokenStream) -> TokenStream {
|
||||||
|
let mut tokens = input.into_iter();
|
||||||
|
let first_span = tokens.next().expect("first token").span();
|
||||||
|
let last_span = tokens.last().map(|x| x.span()).unwrap_or(first_span);
|
||||||
|
let span = first_span.join(last_span).expect("joined span");
|
||||||
|
let src = span.source_text().expect("source_text");
|
||||||
|
TokenTree::Literal(Literal::string(&src)).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,14 @@
|
|||||||
|
|
||||||
// ignore-pretty
|
// ignore-pretty
|
||||||
|
|
||||||
|
#![feature(proc_macro_hygiene)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate span_test_macros;
|
extern crate span_test_macros;
|
||||||
|
|
||||||
extern crate span_api_tests;
|
extern crate span_api_tests;
|
||||||
|
|
||||||
use span_api_tests::{reemit, assert_fake_source_file, assert_source_file};
|
use span_api_tests::{reemit, assert_fake_source_file, assert_source_file, macro_stringify};
|
||||||
|
|
||||||
macro_rules! say_hello {
|
macro_rules! say_hello {
|
||||||
($macname:ident) => ( $macname! { "Hello, world!" })
|
($macname:ident) => ( $macname! { "Hello, world!" })
|
||||||
@ -38,4 +40,32 @@ macro_rules! say_hello {
|
|||||||
assert_source_file! { "Hello, world!" }
|
assert_source_file! { "Hello, world!" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {
|
||||||
|
let s = macro_stringify!(Hello, world!);
|
||||||
|
assert_eq!(s, "Hello, world!");
|
||||||
|
assert_eq!(macro_stringify!(Hello, world!), "Hello, world!");
|
||||||
|
assert_eq!(reemit_legacy!(macro_stringify!(Hello, world!)), "Hello, world!");
|
||||||
|
reemit_legacy!(assert_eq!(macro_stringify!(Hello, world!), "Hello, world!"));
|
||||||
|
// reemit change the span to be that of the call site
|
||||||
|
assert_eq!(
|
||||||
|
reemit!(macro_stringify!(Hello, world!)),
|
||||||
|
"reemit!(macro_stringify!(Hello, world!))"
|
||||||
|
);
|
||||||
|
let r = "reemit!(assert_eq!(macro_stringify!(Hello, world!), r));";
|
||||||
|
reemit!(assert_eq!(macro_stringify!(Hello, world!), r));
|
||||||
|
|
||||||
|
assert_eq!(macro_stringify!(
|
||||||
|
Hello,
|
||||||
|
world!
|
||||||
|
), "Hello,\n world!");
|
||||||
|
|
||||||
|
assert_eq!(macro_stringify!(Hello, /*world */ !), "Hello, /*world */ !");
|
||||||
|
assert_eq!(macro_stringify!(
|
||||||
|
Hello,
|
||||||
|
// comment
|
||||||
|
world!
|
||||||
|
), "Hello,\n // comment\n world!");
|
||||||
|
|
||||||
|
assert_eq!(say_hello! { macro_stringify }, "\"Hello, world!\"");
|
||||||
|
assert_eq!(say_hello_extern! { macro_stringify }, "\"Hello, world!\"");
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user