Skip to content

Commit ee0ab7c

Browse files
Merge #1272
1272: Error out non single root token tree conversion r=matklad a=edwin0cheng This PR add a check to prevent non single root token tree conversion between token trees and syntax tree. It should prevent the assert produced in #1267. Co-authored-by: Edwin Cheng <[email protected]>
2 parents bebc5c7 + 10ecb11 commit ee0ab7c

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

crates/ra_mbe/src/syntax_bridge.rs

+46
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ pub fn token_tree_to_expr(tt: &tt::Subtree) -> Result<TreeArc<ast::Expr>, Expand
5050
let token_source = SubtreeTokenSource::new(tt);
5151
let mut tree_sink = TtTreeSink::new(token_source.querier());
5252
ra_parser::parse_expr(&token_source, &mut tree_sink);
53+
if tree_sink.roots.len() != 1 {
54+
return Err(ExpandError::ConversionError);
55+
}
56+
5357
let syntax = tree_sink.inner.finish();
5458
ast::Expr::cast(&syntax)
5559
.map(|m| m.to_owned())
@@ -61,6 +65,10 @@ pub fn token_tree_to_pat(tt: &tt::Subtree) -> Result<TreeArc<ast::Pat>, ExpandEr
6165
let token_source = SubtreeTokenSource::new(tt);
6266
let mut tree_sink = TtTreeSink::new(token_source.querier());
6367
ra_parser::parse_pat(&token_source, &mut tree_sink);
68+
if tree_sink.roots.len() != 1 {
69+
return Err(ExpandError::ConversionError);
70+
}
71+
6472
let syntax = tree_sink.inner.finish();
6573
ast::Pat::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
6674
}
@@ -70,6 +78,9 @@ pub fn token_tree_to_ty(tt: &tt::Subtree) -> Result<TreeArc<ast::TypeRef>, Expan
7078
let token_source = SubtreeTokenSource::new(tt);
7179
let mut tree_sink = TtTreeSink::new(token_source.querier());
7280
ra_parser::parse_ty(&token_source, &mut tree_sink);
81+
if tree_sink.roots.len() != 1 {
82+
return Err(ExpandError::ConversionError);
83+
}
7384
let syntax = tree_sink.inner.finish();
7485
ast::TypeRef::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
7586
}
@@ -81,6 +92,9 @@ pub fn token_tree_to_macro_stmts(
8192
let token_source = SubtreeTokenSource::new(tt);
8293
let mut tree_sink = TtTreeSink::new(token_source.querier());
8394
ra_parser::parse_macro_stmts(&token_source, &mut tree_sink);
95+
if tree_sink.roots.len() != 1 {
96+
return Err(ExpandError::ConversionError);
97+
}
8498
let syntax = tree_sink.inner.finish();
8599
ast::MacroStmts::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
86100
}
@@ -92,6 +106,9 @@ pub fn token_tree_to_macro_items(
92106
let token_source = SubtreeTokenSource::new(tt);
93107
let mut tree_sink = TtTreeSink::new(token_source.querier());
94108
ra_parser::parse_macro_items(&token_source, &mut tree_sink);
109+
if tree_sink.roots.len() != 1 {
110+
return Err(ExpandError::ConversionError);
111+
}
95112
let syntax = tree_sink.inner.finish();
96113
ast::MacroItems::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
97114
}
@@ -268,6 +285,10 @@ struct TtTreeSink<'a, Q: Querier> {
268285
text_pos: TextUnit,
269286
token_pos: usize,
270287
inner: SyntaxTreeBuilder,
288+
289+
// Number of roots
290+
// Use for detect ill-form tree which is not single root
291+
roots: smallvec::SmallVec<[usize; 1]>,
271292
}
272293

273294
impl<'a, Q: Querier> TtTreeSink<'a, Q> {
@@ -278,6 +299,7 @@ impl<'a, Q: Querier> TtTreeSink<'a, Q> {
278299
text_pos: 0.into(),
279300
token_pos: 0,
280301
inner: SyntaxTreeBuilder::default(),
302+
roots: smallvec::SmallVec::new(),
281303
}
282304
}
283305
}
@@ -323,10 +345,16 @@ impl<'a, Q: Querier> TreeSink for TtTreeSink<'a, Q> {
323345

324346
fn start_node(&mut self, kind: SyntaxKind) {
325347
self.inner.start_node(kind);
348+
349+
match self.roots.last_mut() {
350+
None | Some(0) => self.roots.push(1),
351+
Some(ref mut n) => **n += 1,
352+
};
326353
}
327354

328355
fn finish_node(&mut self) {
329356
self.inner.finish_node();
357+
*self.roots.last_mut().unwrap() -= 1;
330358
}
331359

332360
fn error(&mut self, error: ParseError) {
@@ -375,4 +403,22 @@ mod tests {
375403
assert_eq!(query.token(2 + 15 + 3).1, "\"rust1\"");
376404
assert_eq!(query.token(2 + 15 + 3).0, STRING);
377405
}
406+
407+
#[test]
408+
fn stmts_token_trees_to_expr_is_err() {
409+
let rules = create_rules(
410+
r#"
411+
macro_rules! stmts {
412+
() => {
413+
let a = 0;
414+
let b = 0;
415+
let c = 0;
416+
let d = 0;
417+
}
418+
}
419+
"#,
420+
);
421+
let expansion = expand(&rules, "stmts!()");
422+
assert!(token_tree_to_expr(&expansion).is_err());
423+
}
378424
}

0 commit comments

Comments
 (0)