Skip to content

Commit 5fc5f63

Browse files
committed
Add tt_from_syntax
Used for inserting syntax nodes into existing token trees
1 parent 4717bdf commit 5fc5f63

File tree

1 file changed

+45
-2
lines changed
  • src/tools/rust-analyzer/crates/ide-assists/src

1 file changed

+45
-2
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/utils.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use syntax::{
1414
edit_in_place::{AttrsOwnerEdit, Indent, Removable},
1515
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
1616
},
17-
ted, AstNode, AstToken, Direction, SourceFile,
17+
ted, AstNode, AstToken, Direction, NodeOrToken, SourceFile,
1818
SyntaxKind::*,
19-
SyntaxNode, TextRange, TextSize, T,
19+
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
2020
};
2121

2222
use crate::assist_context::{AssistContext, SourceChangeBuilder};
@@ -916,3 +916,46 @@ pub(crate) fn replace_record_field_expr(
916916
edit.replace(file_range.range, initializer.syntax().text());
917917
}
918918
}
919+
920+
/// Creates a token tree list from a syntax node, creating the needed delimited sub token trees.
921+
/// Assumes that the input syntax node is a valid syntax tree.
922+
pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec<NodeOrToken<ast::TokenTree, SyntaxToken>> {
923+
let mut tt_stack = vec![(None, vec![])];
924+
925+
for element in node.descendants_with_tokens() {
926+
let NodeOrToken::Token(token) = element else { continue };
927+
928+
match token.kind() {
929+
T!['('] | T!['{'] | T!['['] => {
930+
// Found an opening delimeter, start a new sub token tree
931+
tt_stack.push((Some(token.kind()), vec![]));
932+
}
933+
T![')'] | T!['}'] | T![']'] => {
934+
// Closing a subtree
935+
let (delimiter, tt) = tt_stack.pop().expect("unbalanced delimeters");
936+
let (_, parent_tt) = tt_stack
937+
.last_mut()
938+
.expect("parent token tree was closed before it was completed");
939+
let closing_delimiter = delimiter.map(|it| match it {
940+
T!['('] => T![')'],
941+
T!['{'] => T!['}'],
942+
T!['['] => T![']'],
943+
_ => unreachable!(),
944+
});
945+
stdx::always!(
946+
closing_delimiter == Some(token.kind()),
947+
"mismatched opening and closing delimiters"
948+
);
949+
950+
let sub_tt = make::token_tree(delimiter.expect("unbalanced delimiters"), tt);
951+
parent_tt.push(NodeOrToken::Node(sub_tt));
952+
}
953+
_ => {
954+
let (_, current_tt) = tt_stack.last_mut().expect("unmatched delimiters");
955+
current_tt.push(NodeOrToken::Token(token))
956+
}
957+
}
958+
}
959+
960+
tt_stack.pop().expect("parent token tree was closed before it was completed").1
961+
}

0 commit comments

Comments
 (0)