Unnamed repository; edit this file 'description' to name the repository.
Stringify literals create client-side properly
Amos Wenger 2022-07-21
parent 36d825f · commit 9cf99a9
-rw-r--r--crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs61
-rw-r--r--crates/proc-macro-srv/src/tests/mod.rs1
2 files changed, 51 insertions, 11 deletions
diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs
index 066e0e26ac..2e5751756a 100644
--- a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs
+++ b/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs
@@ -132,17 +132,11 @@ impl server::TokenStream for RustAnalyzer {
}
bridge::TokenTree::Literal(literal) => {
- // FIXME: remove unnecessary clones here
- let symbol = ThreadLocalSymbolInterner::get_cloned(&literal.symbol);
-
- let text: tt::SmolStr = if let Some(suffix) = literal.suffix {
- let suffix = ThreadLocalSymbolInterner::get_cloned(&suffix);
- format!("{symbol}{suffix}").into()
- } else {
- symbol
- };
+ let literal = LiteralFormatter(literal);
+ let text = literal
+ .with_stringify_parts(|parts| tt::SmolStr::from_iter(parts.iter().copied()));
- let literal = tt::Literal { text, id: literal.span };
+ let literal = tt::Literal { text, id: literal.0.span };
let leaf = tt::Leaf::from(literal);
let tree = TokenTree::from(leaf);
Self::TokenStream::from_iter(vec![tree])
@@ -416,6 +410,53 @@ impl server::Server for RustAnalyzer {
}
}
+struct LiteralFormatter(bridge::Literal<tt::TokenId, Symbol>);
+
+impl LiteralFormatter {
+ /// Invokes the callback with a `&[&str]` consisting of each part of the
+ /// literal's representation. This is done to allow the `ToString` and
+ /// `Display` implementations to borrow references to symbol values, and
+ /// both be optimized to reduce overhead.
+ fn with_stringify_parts<R>(&self, f: impl FnOnce(&[&str]) -> R) -> R {
+ /// Returns a string containing exactly `num` '#' characters.
+ /// Uses a 256-character source string literal which is always safe to
+ /// index with a `u8` index.
+ fn get_hashes_str(num: u8) -> &'static str {
+ const HASHES: &str = "\
+ ################################################################\
+ ################################################################\
+ ################################################################\
+ ################################################################\
+ ";
+ const _: () = assert!(HASHES.len() == 256);
+ &HASHES[..num as usize]
+ }
+
+ self.with_symbol_and_suffix(|symbol, suffix| match self.0.kind {
+ bridge::LitKind::Byte => f(&["b'", symbol, "'", suffix]),
+ bridge::LitKind::Char => f(&["'", symbol, "'", suffix]),
+ bridge::LitKind::Str => f(&["\"", symbol, "\"", suffix]),
+ bridge::LitKind::StrRaw(n) => {
+ let hashes = get_hashes_str(n);
+ f(&["r", hashes, "\"", symbol, "\"", hashes, suffix])
+ }
+ bridge::LitKind::ByteStr => f(&["b\"", symbol, "\"", suffix]),
+ bridge::LitKind::ByteStrRaw(n) => {
+ let hashes = get_hashes_str(n);
+ f(&["br", hashes, "\"", symbol, "\"", hashes, suffix])
+ }
+ _ => f(&[symbol, suffix]),
+ })
+ }
+
+ fn with_symbol_and_suffix<R>(&self, f: impl FnOnce(&str, &str) -> R) -> R {
+ ThreadLocalSymbolInterner::with(&self.0.symbol, |symbol| match self.0.suffix.as_ref() {
+ Some(suffix) => ThreadLocalSymbolInterner::with(suffix, |suffix| f(symbol, suffix)),
+ None => f(symbol, ""),
+ })
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs
index 30e1ea3343..94c27fad30 100644
--- a/crates/proc-macro-srv/src/tests/mod.rs
+++ b/crates/proc-macro-srv/src/tests/mod.rs
@@ -77,7 +77,6 @@ fn test_fn_like_mk_literals() {
LITERAL b"byte_string" 4294967295
LITERAL 'c' 4294967295
LITERAL "string" 4294967295
- LITERAL "maybe \"raw\"?" 4294967295
LITERAL 3.14f64 4294967295
LITERAL 3.14 4294967295
LITERAL 123i64 4294967295