2341: Fix mbe fail to parse TokenTree with endings whitespace r=matklad a=edwin0cheng



Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2019-11-21 17:56:12 +00:00 committed by GitHub
commit 3f1a0c3c5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,6 +5,7 @@
ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode,
SyntaxTreeBuilder, TextRange, TextUnit, T,
};
use std::iter::successors;
use tt::buffer::{Cursor, TokenBuffer};
use crate::subtree_source::SubtreeTokenSource;
@ -160,6 +161,31 @@ fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> {
let first_child = tt.first_child_or_token()?;
let last_child = tt.last_child_or_token()?;
// ignore trivial first_child and last_child
let first_child = successors(Some(first_child), |it| {
if it.kind().is_trivia() {
it.next_sibling_or_token()
} else {
None
}
})
.last()
.unwrap();
if first_child.kind().is_trivia() {
return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None });
}
let last_child = successors(Some(last_child), |it| {
if it.kind().is_trivia() {
it.prev_sibling_or_token()
} else {
None
}
})
.last()
.unwrap();
let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) {
(T!['('], T![')']) => (tt::Delimiter::Parenthesis, true),
(T!['{'], T!['}']) => (tt::Delimiter::Brace, true),
@ -363,6 +389,7 @@ mod tests {
use super::*;
use crate::tests::{create_rules, expand};
use ra_parser::TokenSource;
use ra_syntax::algo::{insert_children, InsertPosition};
#[test]
fn convert_tt_token_source() {
@ -423,4 +450,45 @@ macro_rules! stmts {
let expansion = expand(&rules, "stmts!();");
assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err());
}
#[test]
fn test_token_tree_last_child_is_white_space() {
let source_file = ast::SourceFile::parse("f!({} );").ok().unwrap();
let macro_call = source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
let token_tree = macro_call.token_tree().unwrap();
// Token Tree now is :
// TokenTree
// - T!['(']
// - TokenTree
// - T!['{']
// - T!['}']
// - WHITE_SPACE
// - T![')']
let rbrace =
token_tree.syntax().descendants_with_tokens().find(|it| it.kind() == T!['}']).unwrap();
let space = token_tree
.syntax()
.descendants_with_tokens()
.find(|it| it.kind() == SyntaxKind::WHITESPACE)
.unwrap();
// reorder th white space, such that the white is inside the inner token-tree.
let token_tree = insert_children(
&rbrace.parent().unwrap(),
InsertPosition::Last,
&mut std::iter::once(space),
);
// Token Tree now is :
// TokenTree
// - T!['{']
// - T!['}']
// - WHITE_SPACE
let token_tree = ast::TokenTree::cast(token_tree).unwrap();
let tt = ast_to_token_tree(&token_tree).unwrap().0;
assert_eq!(tt.delimiter, tt::Delimiter::Brace);
}
}