diff --git a/crates/proc-macro-srv/src/server.rs b/crates/proc-macro-srv/src/server.rs index ed9d770505f..bb49dc14f96 100644 --- a/crates/proc-macro-srv/src/server.rs +++ b/crates/proc-macro-srv/src/server.rs @@ -17,7 +17,7 @@ pub mod rust_analyzer_span; mod symbol; pub mod token_id; pub use symbol::*; -use syntax::ast::{self, HasModuleItem, IsString}; +use syntax::ast::{self, IsString}; use tt::Spacing; fn delim_to_internal(d: proc_macro::Delimiter, span: bridge::DelimSpan) -> tt::Delimiter { @@ -56,50 +56,29 @@ fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing { } fn literal_to_external(literal_kind: ast::LiteralKind) -> Option { - Some(match literal_kind { - ast::LiteralKind::String(data) => { - if data.is_raw() { - bridge::LitKind::StrRaw(data.raw_delimiter_count()?) - } else { - bridge::LitKind::Str - } - } - ast::LiteralKind::ByteString(data) => { - if data.is_raw() { - bridge::LitKind::ByteStrRaw(data.raw_delimiter_count()?) - } else { - bridge::LitKind::ByteStr - } - } - ast::LiteralKind::CString(data) => { - if data.is_raw() { - bridge::LitKind::CStrRaw(data.raw_delimiter_count()?) - } else { - bridge::LitKind::CStr - } - } - ast::LiteralKind::IntNumber(_) => bridge::LitKind::Integer, - ast::LiteralKind::FloatNumber(_) => bridge::LitKind::Float, - ast::LiteralKind::Char(_) => bridge::LitKind::Char, - ast::LiteralKind::Byte(_) => bridge::LitKind::Byte, - ast::LiteralKind::Bool(_) => unreachable!(), - }) -} + match literal_kind { + ast::LiteralKind::String(data) => Some(if data.is_raw() { + bridge::LitKind::StrRaw(data.raw_delimiter_count()?) + } else { + bridge::LitKind::Str + }), -fn str_to_lit_node(input: &str) -> Option { - let input = input.trim(); - let source_code = format!("fn f() {{ let _ = {input}; }}"); - - let parse = ast::SourceFile::parse(&source_code); - let file = parse.tree(); - - let ast::Item::Fn(func) = file.items().next()? else { return None }; - let ast::Stmt::LetStmt(stmt) = func.body()?.stmt_list()?.statements().next()? else { - return None; - }; - let ast::Expr::Literal(lit) = stmt.initializer()? else { return None }; - - Some(lit) + ast::LiteralKind::ByteString(data) => Some(if data.is_raw() { + bridge::LitKind::ByteStrRaw(data.raw_delimiter_count()?) + } else { + bridge::LitKind::ByteStr + }), + ast::LiteralKind::CString(data) => Some(if data.is_raw() { + bridge::LitKind::CStrRaw(data.raw_delimiter_count()?) + } else { + bridge::LitKind::CStr + }), + ast::LiteralKind::IntNumber(_) => Some(bridge::LitKind::Integer), + ast::LiteralKind::FloatNumber(_) => Some(bridge::LitKind::Float), + ast::LiteralKind::Char(_) => Some(bridge::LitKind::Char), + ast::LiteralKind::Byte(_) => Some(bridge::LitKind::Byte), + ast::LiteralKind::Bool(_) => None, + } } struct LiteralFormatter(bridge::Literal); diff --git a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs index 1b883c87ea3..7313e99bb12 100644 --- a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs @@ -13,11 +13,11 @@ use std::{ use ::tt::{TextRange, TextSize}; use proc_macro::bridge::{self, server}; use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; -use syntax::ast; +use syntax::ast::{self, IsString}; use crate::server::{ - delim_to_external, delim_to_internal, literal_to_external, str_to_lit_node, - token_stream::TokenStreamBuilder, LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER, + delim_to_external, delim_to_internal, literal_to_external, token_stream::TokenStreamBuilder, + LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; mod tt { pub use ::tt::*; @@ -71,7 +71,8 @@ impl server::FreeFunctions for RaSpanServer { &mut self, s: &str, ) -> Result, ()> { - let literal = str_to_lit_node(s).ok_or(())?; + let literal = ast::Literal::parse(s); + let literal = literal.tree(); let kind = literal_to_external(literal.kind()).ok_or(())?; @@ -80,12 +81,22 @@ impl server::FreeFunctions for RaSpanServer { ast::LiteralKind::FloatNumber(num) => num.suffix().map(ToString::to_string), ast::LiteralKind::IntNumber(num) => num.suffix().map(ToString::to_string), _ => None, - } - .map(|suffix| Symbol::intern(self.interner, &suffix)); + }; + + let text = match literal.kind() { + ast::LiteralKind::String(data) => data.text_without_quotes().to_string(), + ast::LiteralKind::ByteString(data) => data.text_without_quotes().to_string(), + ast::LiteralKind::CString(data) => data.text_without_quotes().to_string(), + _ => s.to_string(), + }; + let text = if let Some(ref suffix) = suffix { text.strip_suffix(suffix) } else { None } + .unwrap_or(&text); + + let suffix = suffix.map(|suffix| Symbol::intern(self.interner, &suffix)); Ok(bridge::Literal { kind, - symbol: Symbol::intern(self.interner, s), + symbol: Symbol::intern(self.interner, text), suffix, span: self.call_site, }) diff --git a/crates/proc-macro-srv/src/server/token_id.rs b/crates/proc-macro-srv/src/server/token_id.rs index 7d2781d89f6..d16e9d25105 100644 --- a/crates/proc-macro-srv/src/server/token_id.rs +++ b/crates/proc-macro-srv/src/server/token_id.rs @@ -6,11 +6,11 @@ use std::{ }; use proc_macro::bridge::{self, server}; -use syntax::ast; +use syntax::ast::{self, IsString}; use crate::server::{ - delim_to_external, delim_to_internal, literal_to_external, str_to_lit_node, - token_stream::TokenStreamBuilder, LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER, + delim_to_external, delim_to_internal, literal_to_external, token_stream::TokenStreamBuilder, + LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; mod tt { pub use proc_macro_api::msg::TokenId; @@ -63,7 +63,8 @@ impl server::FreeFunctions for TokenIdServer { &mut self, s: &str, ) -> Result, ()> { - let literal = str_to_lit_node(s).ok_or(())?; + let literal = ast::Literal::parse(s); + let literal = literal.tree(); let kind = literal_to_external(literal.kind()).ok_or(())?; @@ -72,12 +73,22 @@ impl server::FreeFunctions for TokenIdServer { ast::LiteralKind::FloatNumber(num) => num.suffix().map(ToString::to_string), ast::LiteralKind::IntNumber(num) => num.suffix().map(ToString::to_string), _ => None, - } - .map(|suffix| Symbol::intern(self.interner, &suffix)); + }; + + let text = match literal.kind() { + ast::LiteralKind::String(data) => data.text_without_quotes().to_string(), + ast::LiteralKind::ByteString(data) => data.text_without_quotes().to_string(), + ast::LiteralKind::CString(data) => data.text_without_quotes().to_string(), + _ => s.to_string(), + }; + let text = if let Some(ref suffix) = suffix { text.strip_suffix(suffix) } else { None } + .unwrap_or(&text); + + let suffix = suffix.map(|suffix| Symbol::intern(self.interner, &suffix)); Ok(bridge::Literal { kind, - symbol: Symbol::intern(self.interner, s), + symbol: Symbol::intern(self.interner, text), suffix, span: self.call_site, }) diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 960889b7421..2390cacda28 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -187,6 +187,25 @@ impl SourceFile { } } +impl ast::Literal { + pub fn parse(text: &str) -> Parse { + let lexed = parser::LexedStr::new(text); + let parser_input = lexed.to_input(); + let parser_output = parser::TopEntryPoint::Expr.parse(&parser_input); + let (green, mut errors, _) = parsing::build_tree(lexed, parser_output); + let root = SyntaxNode::new_root(green.clone()); + + errors.extend(validation::validate(&root)); + + assert_eq!(root.kind(), SyntaxKind::LITERAL); + Parse { + green, + errors: if errors.is_empty() { None } else { Some(errors.into()) }, + _ty: PhantomData, + } + } +} + impl ast::TokenTree { pub fn reparse_as_comma_separated_expr(self) -> Parse { let tokens = self.syntax().descendants_with_tokens().filter_map(NodeOrToken::into_token);