Skip to content

Commit 0e706a5

Browse files
authored
Merge pull request #21195 from Veykril/push-nnzprznzurwz
fix: More proc-macro-srv proto fixes
2 parents 0b59d48 + 0c605dd commit 0e706a5

File tree

6 files changed

+192
-67
lines changed

6 files changed

+192
-67
lines changed

src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs

Lines changed: 135 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ mod tests {
185185

186186
use super::*;
187187

188-
fn fixture_token_tree() -> TopSubtree<Span> {
188+
fn fixture_token_tree_top_many_none() -> TopSubtree<Span> {
189189
let anchor = SpanAnchor {
190190
file_id: span::EditionedFileId::new(
191191
span::FileId::from_raw(0xe4e4e),
@@ -201,7 +201,7 @@ mod tests {
201201
ctx: SyntaxContext::root(Edition::CURRENT),
202202
},
203203
close: Span {
204-
range: TextRange::empty(TextSize::new(19)),
204+
range: TextRange::empty(TextSize::new(0)),
205205
anchor,
206206
ctx: SyntaxContext::root(Edition::CURRENT),
207207
},
@@ -259,56 +259,159 @@ mod tests {
259259
ctx: SyntaxContext::root(Edition::CURRENT),
260260
},
261261
);
262+
builder.open(
263+
DelimiterKind::Bracket,
264+
Span {
265+
range: TextRange::at(TextSize::new(15), TextSize::of('[')),
266+
anchor,
267+
ctx: SyntaxContext::root(Edition::CURRENT),
268+
},
269+
);
262270
builder.push(Leaf::Literal(Literal {
263271
symbol: sym::INTEGER_0,
264272
span: Span {
265-
range: TextRange::at(TextSize::new(15), TextSize::of("0u32")),
273+
range: TextRange::at(TextSize::new(16), TextSize::of("0u32")),
266274
anchor,
267275
ctx: SyntaxContext::root(Edition::CURRENT),
268276
},
269277
kind: tt::LitKind::Integer,
270278
suffix: Some(sym::u32),
271279
}));
272280
builder.close(Span {
273-
range: TextRange::at(TextSize::new(19), TextSize::of('}')),
281+
range: TextRange::at(TextSize::new(20), TextSize::of(']')),
274282
anchor,
275283
ctx: SyntaxContext::root(Edition::CURRENT),
276284
});
277285

286+
builder.close(Span {
287+
range: TextRange::at(TextSize::new(21), TextSize::of('}')),
288+
anchor,
289+
ctx: SyntaxContext::root(Edition::CURRENT),
290+
});
291+
292+
builder.build()
293+
}
294+
295+
fn fixture_token_tree_top_empty_none() -> TopSubtree<Span> {
296+
let anchor = SpanAnchor {
297+
file_id: span::EditionedFileId::new(
298+
span::FileId::from_raw(0xe4e4e),
299+
span::Edition::CURRENT,
300+
),
301+
ast_id: ROOT_ERASED_FILE_AST_ID,
302+
};
303+
304+
let builder = TopSubtreeBuilder::new(Delimiter {
305+
open: Span {
306+
range: TextRange::empty(TextSize::new(0)),
307+
anchor,
308+
ctx: SyntaxContext::root(Edition::CURRENT),
309+
},
310+
close: Span {
311+
range: TextRange::empty(TextSize::new(0)),
312+
anchor,
313+
ctx: SyntaxContext::root(Edition::CURRENT),
314+
},
315+
kind: DelimiterKind::Invisible,
316+
});
317+
318+
builder.build()
319+
}
320+
321+
fn fixture_token_tree_top_empty_brace() -> TopSubtree<Span> {
322+
let anchor = SpanAnchor {
323+
file_id: span::EditionedFileId::new(
324+
span::FileId::from_raw(0xe4e4e),
325+
span::Edition::CURRENT,
326+
),
327+
ast_id: ROOT_ERASED_FILE_AST_ID,
328+
};
329+
330+
let builder = TopSubtreeBuilder::new(Delimiter {
331+
open: Span {
332+
range: TextRange::empty(TextSize::new(0)),
333+
anchor,
334+
ctx: SyntaxContext::root(Edition::CURRENT),
335+
},
336+
close: Span {
337+
range: TextRange::empty(TextSize::new(0)),
338+
anchor,
339+
ctx: SyntaxContext::root(Edition::CURRENT),
340+
},
341+
kind: DelimiterKind::Brace,
342+
});
343+
278344
builder.build()
279345
}
280346

281347
#[test]
282348
fn test_proc_macro_rpc_works() {
283-
let tt = fixture_token_tree();
284-
for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
285-
let mut span_data_table = Default::default();
286-
let task = ExpandMacro {
287-
data: ExpandMacroData {
288-
macro_body: FlatTree::from_subtree(tt.view(), v, &mut span_data_table),
289-
macro_name: Default::default(),
290-
attributes: None,
291-
has_global_spans: ExpnGlobals {
292-
serialize: true,
293-
def_site: 0,
294-
call_site: 0,
295-
mixed_site: 0,
349+
for tt in [
350+
fixture_token_tree_top_many_none,
351+
fixture_token_tree_top_empty_none,
352+
fixture_token_tree_top_empty_brace,
353+
] {
354+
for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
355+
let tt = tt();
356+
let mut span_data_table = Default::default();
357+
let task = ExpandMacro {
358+
data: ExpandMacroData {
359+
macro_body: FlatTree::from_subtree(tt.view(), v, &mut span_data_table),
360+
macro_name: Default::default(),
361+
attributes: None,
362+
has_global_spans: ExpnGlobals {
363+
serialize: true,
364+
def_site: 0,
365+
call_site: 0,
366+
mixed_site: 0,
367+
},
368+
span_data_table: Vec::new(),
296369
},
297-
span_data_table: Vec::new(),
298-
},
299-
lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(),
300-
env: Default::default(),
301-
current_dir: Default::default(),
302-
};
303-
304-
let json = serde_json::to_string(&task).unwrap();
305-
// println!("{}", json);
306-
let back: ExpandMacro = serde_json::from_str(&json).unwrap();
307-
308-
assert!(
309-
tt == back.data.macro_body.to_subtree_resolved(v, &span_data_table),
310-
"version: {v}"
311-
);
370+
lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(),
371+
env: Default::default(),
372+
current_dir: Default::default(),
373+
};
374+
375+
let json = serde_json::to_string(&task).unwrap();
376+
// println!("{}", json);
377+
let back: ExpandMacro = serde_json::from_str(&json).unwrap();
378+
379+
assert_eq!(
380+
tt,
381+
back.data.macro_body.to_subtree_resolved(v, &span_data_table),
382+
"version: {v}"
383+
);
384+
}
385+
}
386+
}
387+
388+
#[test]
389+
#[cfg(feature = "sysroot-abi")]
390+
fn test_proc_macro_rpc_works_ts() {
391+
for tt in [
392+
fixture_token_tree_top_many_none,
393+
fixture_token_tree_top_empty_none,
394+
fixture_token_tree_top_empty_brace,
395+
] {
396+
let tt = tt();
397+
for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
398+
let mut span_data_table = Default::default();
399+
let flat_tree = FlatTree::from_subtree(tt.view(), v, &mut span_data_table);
400+
assert_eq!(
401+
tt,
402+
flat_tree.clone().to_subtree_resolved(v, &span_data_table),
403+
"version: {v}"
404+
);
405+
let ts = flat_tree.to_tokenstream_resolved(v, &span_data_table, |a, b| a.cover(b));
406+
let call_site = *span_data_table.first().unwrap();
407+
let mut span_data_table = Default::default();
408+
assert_eq!(
409+
tt,
410+
FlatTree::from_tokenstream(ts.clone(), v, call_site, &mut span_data_table)
411+
.to_subtree_resolved(v, &span_data_table),
412+
"version: {v}, ts:\n{ts:#?}"
413+
);
414+
}
312415
}
313416
}
314417
}

src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub fn deserialize_span_data_index_map(map: &[u32]) -> SpanDataIndexMap {
8585
.collect()
8686
}
8787

88-
#[derive(Serialize, Deserialize, Debug)]
88+
#[derive(Serialize, Deserialize, Debug, Clone)]
8989
pub struct FlatTree {
9090
subtree: Vec<u32>,
9191
literal: Vec<u32>,
@@ -615,14 +615,17 @@ impl<'a, T: SpanTransformer>
615615
root: &'a proc_macro_srv::TokenStream<T::Span>,
616616
) {
617617
let call_site = self.token_id_of(call_site);
618-
self.subtree.push(SubtreeRepr {
619-
open: call_site,
620-
close: call_site,
621-
kind: tt::DelimiterKind::Invisible,
622-
tt: [!0, !0],
623-
});
624-
self.work.push_back((0, root.len(), Some(root.iter())));
625-
618+
if let Some(group) = root.as_single_group() {
619+
self.enqueue(group);
620+
} else {
621+
self.subtree.push(SubtreeRepr {
622+
open: call_site,
623+
close: call_site,
624+
kind: tt::DelimiterKind::Invisible,
625+
tt: [!0, !0],
626+
});
627+
self.work.push_back((0, root.len(), Some(root.iter())));
628+
}
626629
while let Some((idx, len, group)) = self.work.pop_front() {
627630
self.group(idx, len, group);
628631
}
@@ -962,6 +965,11 @@ impl<T: SpanTransformer> Reader<'_, T> {
962965
};
963966
res[i] = Some(g);
964967
}
965-
res[0].take().unwrap().stream.unwrap_or_default()
968+
let group = res[0].take().unwrap();
969+
if group.delimiter == proc_macro_srv::Delimiter::None {
970+
group.stream.unwrap_or_default()
971+
} else {
972+
TokenStream::new(vec![proc_macro_srv::TokenTree::Group(group)])
973+
}
966974
}
967975
}

src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -83,31 +83,10 @@ impl<'env> ProcMacroSrv<'env> {
8383
}
8484

8585
pub fn join_spans(&self, first: Span, second: Span) -> Option<Span> {
86-
// We can't modify the span range for fixup spans, those are meaningful to fixup, so just
87-
// prefer the non-fixup span.
88-
if first.anchor.ast_id == span::FIXUP_ERASED_FILE_AST_ID_MARKER {
89-
return Some(second);
90-
}
91-
if second.anchor.ast_id == span::FIXUP_ERASED_FILE_AST_ID_MARKER {
92-
return Some(first);
93-
}
94-
// FIXME: Once we can talk back to the client, implement a "long join" request for anchors
95-
// that differ in [AstId]s as joining those spans requires resolving the AstIds.
96-
if first.anchor != second.anchor {
97-
return None;
98-
}
99-
// Differing context, we can't merge these so prefer the one that's root
100-
if first.ctx != second.ctx {
101-
if first.ctx.is_root() {
102-
return Some(second);
103-
} else if second.ctx.is_root() {
104-
return Some(first);
105-
}
106-
}
107-
Some(Span {
108-
range: first.range.cover(second.range),
109-
anchor: second.anchor,
110-
ctx: second.ctx,
86+
first.join(second, |_, _| {
87+
// FIXME: Once we can talk back to the client, implement a "long join" request for anchors
88+
// that differ in [AstId]s as joining those spans requires resolving the AstIds.
89+
None
11190
})
11291
}
11392
}

src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ impl<S> TokenStream<S> {
4040
TokenStreamIter::new(self)
4141
}
4242

43+
pub fn as_single_group(&self) -> Option<&Group<S>> {
44+
match &**self.0 {
45+
[TokenTree::Group(group)] => Some(group),
46+
_ => None,
47+
}
48+
}
49+
4350
pub(crate) fn from_str(s: &str, span: S) -> Result<Self, String>
4451
where
4552
S: SpanLike + Copy,

src/tools/rust-analyzer/crates/span/src/ast_id.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
4444

4545
/// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be
4646
/// considered fake.
47+
/// Do not modify this, it is used by the proc-macro server.
4748
pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
4849
ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32));
4950

src/tools/rust-analyzer/crates/span/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,33 @@ impl Span {
2828
let range = self.range.cover(other.range);
2929
Span { range, ..self }
3030
}
31+
32+
pub fn join(
33+
self,
34+
other: Span,
35+
differing_anchor: impl FnOnce(Span, Span) -> Option<Span>,
36+
) -> Option<Span> {
37+
// We can't modify the span range for fixup spans, those are meaningful to fixup, so just
38+
// prefer the non-fixup span.
39+
if self.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
40+
return Some(other);
41+
}
42+
if other.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
43+
return Some(self);
44+
}
45+
if self.anchor != other.anchor {
46+
return differing_anchor(self, other);
47+
}
48+
// Differing context, we can't merge these so prefer the one that's root
49+
if self.ctx != other.ctx {
50+
if self.ctx.is_root() {
51+
return Some(other);
52+
} else if other.ctx.is_root() {
53+
return Some(self);
54+
}
55+
}
56+
Some(Span { range: self.range.cover(other.range), anchor: other.anchor, ctx: other.ctx })
57+
}
3158
}
3259

3360
/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs

0 commit comments

Comments
 (0)