Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/load-cargo/src/lib.rs | 40 | ||||
| -rw-r--r-- | crates/proc-macro-api/src/bidirectional_protocol/msg.rs | 13 | ||||
| -rw-r--r-- | crates/proc-macro-srv-cli/src/main_loop.rs | 34 | ||||
| -rw-r--r-- | crates/proc-macro-srv/src/lib.rs | 1 | ||||
| -rw-r--r-- | crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs | 6 | ||||
| -rw-r--r-- | crates/proc-macro-srv/src/tests/utils.rs | 4 |
6 files changed, 95 insertions, 3 deletions
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 654ff4f75b..b8ce3a8da4 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -26,7 +26,7 @@ use ide_db::{ use itertools::Itertools; use proc_macro_api::{ MacroDylib, ProcMacroClient, - bidirectional_protocol::msg::{SubRequest, SubResponse}, + bidirectional_protocol::msg::{ParentSpan, SubRequest, SubResponse}, }; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::{Span, SpanAnchor, SyntaxContext}; @@ -659,6 +659,44 @@ impl ProcMacroExpander for Expander { ctx: current_span.ctx.into_u32(), }) } + SubRequest::SpanParent { file_id, ast_id, start, end, ctx } => { + let span = Span { + range: TextRange::new(TextSize::from(start), TextSize::from(end)), + anchor: SpanAnchor { + file_id: span::EditionedFileId::from_raw(file_id), + ast_id: span::ErasedFileAstId::from_raw(ast_id), + }, + // SAFETY: We only receive spans from the server. If someone mess up the communication UB can happen, + // but that will be their problem. + ctx: unsafe { SyntaxContext::from_u32(ctx) }, + }; + + if let Some(macro_call_id) = span.ctx.outer_expn(db) { + let macro_call_loc = db.lookup_intern_macro_call(macro_call_id.into()); + + let call_site_file = macro_call_loc.kind.file_id(); + let call_site_ast_id = macro_call_loc.kind.erased_ast_id(); + + if let Some(editioned_file_id) = call_site_file.file_id() { + let range = db + .ast_id_map(editioned_file_id.into()) + .get_erased(call_site_ast_id) + .text_range(); + + let parent_span = Some(ParentSpan { + file_id: editioned_file_id.editioned_file_id(db).as_u32(), + ast_id: span::ROOT_ERASED_FILE_AST_ID.into_raw(), + start: u32::from(range.start()), + end: u32::from(range.end()), + ctx: macro_call_loc.ctxt.into_u32(), + }); + + return Ok(SubResponse::SpanParentResult { parent_span }); + } + } + + Ok(SubResponse::SpanParentResult { parent_span: None }) + } }; match self.0.expand( subtree.view(), diff --git a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 10a8d66677..ab4bed81e6 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -22,6 +22,7 @@ pub enum SubRequest { LineColumn { file_id: u32, ast_id: u32, offset: u32 }, ByteRange { file_id: u32, ast_id: u32, start: u32, end: u32 }, SpanSource { file_id: u32, ast_id: u32, start: u32, end: u32, ctx: u32 }, + SpanParent { file_id: u32, ast_id: u32, start: u32, end: u32, ctx: u32 }, } #[derive(Debug, Serialize, Deserialize)] @@ -50,12 +51,24 @@ pub enum SubResponse { end: u32, ctx: u32, }, + SpanParentResult { + parent_span: Option<ParentSpan>, + }, Cancel { reason: String, }, } #[derive(Debug, Serialize, Deserialize)] +pub struct ParentSpan { + pub file_id: u32, + pub ast_id: u32, + pub start: u32, + pub end: u32, + pub ctx: u32, +} + +#[derive(Debug, Serialize, Deserialize)] pub enum BidirectionalMessage { Request(Request), Response(Response), diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index 2c54b18077..c525ed848b 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -309,6 +309,40 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_> { other => handle_failure(other), } } + + fn span_parent( + &mut self, + proc_macro_srv::span::Span { range, anchor, ctx }: proc_macro_srv::span::Span, + ) -> Option<proc_macro_srv::span::Span> { + let response = self.roundtrip(bidirectional::SubRequest::SpanParent { + file_id: anchor.file_id.as_u32(), + ast_id: anchor.ast_id.into_raw(), + start: range.start().into(), + end: range.end().into(), + ctx: ctx.into_u32(), + }); + + match response { + Ok(bidirectional::SubResponse::SpanParentResult { parent_span }) => { + parent_span.map(|bidirectional::ParentSpan { file_id, ast_id, start, end, ctx }| { + proc_macro_srv::span::Span { + range: proc_macro_srv::span::TextRange::new( + proc_macro_srv::span::TextSize::new(start), + proc_macro_srv::span::TextSize::new(end), + ), + anchor: proc_macro_srv::span::SpanAnchor { + file_id: proc_macro_srv::span::EditionedFileId::from_raw(file_id), + ast_id: proc_macro_srv::span::ErasedFileAstId::from_raw(ast_id), + }, + // SAFETY: spans originate from the server. If the protocol is violated, + // undefined behavior is the caller’s responsibility. + ctx: unsafe { proc_macro_srv::span::SyntaxContext::from_u32(ctx) }, + } + }) + } + other => handle_failure(other), + } + } } fn handle_expand_ra( diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 6b770e440c..65de804404 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -121,6 +121,7 @@ pub trait ProcMacroClientInterface { fn byte_range(&mut self, span: Span) -> Range<usize>; fn span_source(&mut self, span: Span) -> Span; + fn span_parent(&mut self, span: Span) -> Option<Span>; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 5eb16c37ac..6b6bfcc934 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -164,8 +164,10 @@ impl server::Server for RaSpanServer<'_> { self.callback.as_mut()?.source_text(span) } - fn span_parent(&mut self, _span: Self::Span) -> Option<Self::Span> { - // FIXME requires db, looks up the parent call site + fn span_parent(&mut self, span: Self::Span) -> Option<Self::Span> { + if let Some(ref mut callback) = self.callback { + return callback.span_parent(span); + } None } fn span_source(&mut self, span: Self::Span) -> Self::Span { diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index 28d826d01e..31beca20d6 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -146,6 +146,10 @@ impl ProcMacroClientInterface for MockCallback<'_> { fn span_source(&mut self, span: Span) -> Span { span } + + fn span_parent(&mut self, _span: Span) -> Option<Span> { + None + } } pub fn assert_expand_with_callback( |