Skip to content

Commit e88b0d9

Browse files
committed
Introduce proc_macro::Span::source_text
1 parent d48ab69 commit e88b0d9

File tree

5 files changed

+59
-2
lines changed

5 files changed

+59
-2
lines changed

src/libproc_macro/bridge/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ macro_rules! with_api {
165165
fn end($self: $S::Span) -> LineColumn;
166166
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
167167
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
168+
fn source_text($self: $S::Span) -> Option<String>;
168169
},
169170
}
170171
};

src/libproc_macro/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,18 @@ impl Span {
341341
self.0 == other.0
342342
}
343343

344+
/// Returns the source text behind a span. This preserves the original source
345+
/// code, including spaces and comments. It only returns a result if the span
346+
/// corresponds to real source code.
347+
///
348+
/// Note: The observable result of a macro should only rely on the tokens and
349+
/// not on this source text. The result of this function is a best effort to
350+
/// be used for diagnostics only.
351+
#[unstable(feature = "proc_macro_span", issue = "54725")]
352+
pub fn source_text(&self) -> Option<String> {
353+
self.0.source_text()
354+
}
355+
344356
diagnostic_method!(error, Level::Error);
345357
diagnostic_method!(warning, Level::Warning);
346358
diagnostic_method!(note, Level::Note);

src/libsyntax_ext/proc_macro_server.rs

+3
Original file line numberDiff line numberDiff line change
@@ -748,4 +748,7 @@ impl server::Span for Rustc<'_> {
748748
fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
749749
span.with_ctxt(at.ctxt())
750750
}
751+
fn source_text(&mut self, span: Self::Span) -> Option<String> {
752+
self.sess.source_map().span_to_snippet(span).ok()
753+
}
751754
}

src/test/run-pass/proc-macro/auxiliary/span-api-tests.rs

+11
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,14 @@ pub fn assert_source_file(input: TokenStream) -> TokenStream {
4343

4444
"".parse().unwrap()
4545
}
46+
47+
#[proc_macro]
48+
pub fn macro_stringify(input: TokenStream) -> TokenStream {
49+
let mut tokens = input.into_iter();
50+
let first_span = tokens.next().expect("first token").span();
51+
let last_span = tokens.last().map(|x| x.span()).unwrap_or(first_span);
52+
let span = first_span.join(last_span).expect("joined span");
53+
let src = span.source_text().expect("source_text");
54+
TokenTree::Literal(Literal::string(&src)).into()
55+
}
56+

src/test/run-pass/proc-macro/span-api-tests.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313

1414
// ignore-pretty
1515

16+
#![feature(proc_macro_hygiene)]
17+
1618
#[macro_use]
1719
extern crate span_test_macros;
1820

1921
extern crate span_api_tests;
2022

21-
use span_api_tests::{reemit, assert_fake_source_file, assert_source_file};
23+
use span_api_tests::{reemit, assert_fake_source_file, assert_source_file, macro_stringify};
2224

2325
macro_rules! say_hello {
2426
($macname:ident) => ( $macname! { "Hello, world!" })
@@ -38,4 +40,32 @@ reemit! {
3840
assert_source_file! { "Hello, world!" }
3941
}
4042

41-
fn main() {}
43+
fn main() {
44+
let s = macro_stringify!(Hello, world!);
45+
assert_eq!(s, "Hello, world!");
46+
assert_eq!(macro_stringify!(Hello, world!), "Hello, world!");
47+
assert_eq!(reemit_legacy!(macro_stringify!(Hello, world!)), "Hello, world!");
48+
reemit_legacy!(assert_eq!(macro_stringify!(Hello, world!), "Hello, world!"));
49+
// reemit change the span to be that of the call site
50+
assert_eq!(
51+
reemit!(macro_stringify!(Hello, world!)),
52+
"reemit!(macro_stringify!(Hello, world!))"
53+
);
54+
let r = "reemit!(assert_eq!(macro_stringify!(Hello, world!), r));";
55+
reemit!(assert_eq!(macro_stringify!(Hello, world!), r));
56+
57+
assert_eq!(macro_stringify!(
58+
Hello,
59+
world!
60+
), "Hello,\n world!");
61+
62+
assert_eq!(macro_stringify!(Hello, /*world */ !), "Hello, /*world */ !");
63+
assert_eq!(macro_stringify!(
64+
Hello,
65+
// comment
66+
world!
67+
), "Hello,\n // comment\n world!");
68+
69+
assert_eq!(say_hello! { macro_stringify }, "\"Hello, world!\"");
70+
assert_eq!(say_hello_extern! { macro_stringify }, "\"Hello, world!\"");
71+
}

0 commit comments

Comments
 (0)