aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs68
1 files changed, 68 insertions, 0 deletions
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index d1c49c0b3..1de399fee 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -5,6 +5,7 @@ use ra_syntax::{
5 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, 5 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode,
6 SyntaxTreeBuilder, TextRange, TextUnit, T, 6 SyntaxTreeBuilder, TextRange, TextUnit, T,
7}; 7};
8use std::iter::successors;
8use tt::buffer::{Cursor, TokenBuffer}; 9use tt::buffer::{Cursor, TokenBuffer};
9 10
10use crate::subtree_source::SubtreeTokenSource; 11use crate::subtree_source::SubtreeTokenSource;
@@ -160,6 +161,31 @@ impl Convertor {
160 161
161 let first_child = tt.first_child_or_token()?; 162 let first_child = tt.first_child_or_token()?;
162 let last_child = tt.last_child_or_token()?; 163 let last_child = tt.last_child_or_token()?;
164
165 // ignore trivial first_child and last_child
166 let first_child = successors(Some(first_child), |it| {
167 if it.kind().is_trivia() {
168 it.next_sibling_or_token()
169 } else {
170 None
171 }
172 })
173 .last()
174 .unwrap();
175 if first_child.kind().is_trivia() {
176 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None });
177 }
178
179 let last_child = successors(Some(last_child), |it| {
180 if it.kind().is_trivia() {
181 it.prev_sibling_or_token()
182 } else {
183 None
184 }
185 })
186 .last()
187 .unwrap();
188
163 let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { 189 let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) {
164 (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), 190 (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true),
165 (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), 191 (T!['{'], T!['}']) => (tt::Delimiter::Brace, true),
@@ -363,6 +389,7 @@ mod tests {
363 use super::*; 389 use super::*;
364 use crate::tests::{create_rules, expand}; 390 use crate::tests::{create_rules, expand};
365 use ra_parser::TokenSource; 391 use ra_parser::TokenSource;
392 use ra_syntax::algo::{insert_children, InsertPosition};
366 393
367 #[test] 394 #[test]
368 fn convert_tt_token_source() { 395 fn convert_tt_token_source() {
@@ -423,4 +450,45 @@ mod tests {
423 let expansion = expand(&rules, "stmts!();"); 450 let expansion = expand(&rules, "stmts!();");
424 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); 451 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err());
425 } 452 }
453
454 #[test]
455 fn test_token_tree_last_child_is_white_space() {
456 let source_file = ast::SourceFile::parse("f!({} );").ok().unwrap();
457 let macro_call = source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
458 let token_tree = macro_call.token_tree().unwrap();
459
460 // Token Tree now is :
461 // TokenTree
462 // - T!['(']
463 // - TokenTree
464 // - T!['{']
465 // - T!['}']
466 // - WHITE_SPACE
467 // - T![')']
468
469 let rbrace =
470 token_tree.syntax().descendants_with_tokens().find(|it| it.kind() == T!['}']).unwrap();
471 let space = token_tree
472 .syntax()
473 .descendants_with_tokens()
474 .find(|it| it.kind() == SyntaxKind::WHITESPACE)
475 .unwrap();
476
477 // reorder th white space, such that the white is inside the inner token-tree.
478 let token_tree = insert_children(
479 &rbrace.parent().unwrap(),
480 InsertPosition::Last,
481 &mut std::iter::once(space),
482 );
483
484 // Token Tree now is :
485 // TokenTree
486 // - T!['{']
487 // - T!['}']
488 // - WHITE_SPACE
489 let token_tree = ast::TokenTree::cast(token_tree).unwrap();
490 let tt = ast_to_token_tree(&token_tree).unwrap().0;
491
492 assert_eq!(tt.delimiter, tt::Delimiter::Brace);
493 }
426} 494}