Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/syntax_helpers/node_ext.rs')
-rw-r--r--crates/ide-db/src/syntax_helpers/node_ext.rs39
1 files changed, 38 insertions, 1 deletions
diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs
index acce066b83..94ecf6a02d 100644
--- a/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -1,12 +1,15 @@
//! Various helper functions to work with SyntaxNodes.
use std::ops::ControlFlow;
+use either::Either;
use itertools::Itertools;
use parser::T;
use span::Edition;
use syntax::{
- AstNode, AstToken, Preorder, RustLanguage, WalkEvent,
+ AstNode, AstToken, Direction, Preorder, RustLanguage, SyntaxToken, WalkEvent,
+ algo::non_trivia_sibling,
ast::{self, HasLoopBody, MacroCall, PathSegmentKind, VisibilityKind},
+ syntax_editor::Element,
};
pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
@@ -542,3 +545,37 @@ pub fn macro_call_for_string_token(string: &ast::String) -> Option<MacroCall> {
let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
Some(macro_call)
}
+
+pub fn is_in_macro_matcher(token: &SyntaxToken) -> bool {
+ let Some(macro_def) = token
+ .parent_ancestors()
+ .map_while(Either::<ast::TokenTree, ast::Macro>::cast)
+ .find_map(Either::right)
+ else {
+ return false;
+ };
+ let range = token.text_range();
+ let Some(body) = (match macro_def {
+ ast::Macro::MacroDef(macro_def) => {
+ if let Some(args) = macro_def.args() {
+ return args.syntax().text_range().contains_range(range);
+ }
+ macro_def.body()
+ }
+ ast::Macro::MacroRules(macro_rules) => macro_rules.token_tree(),
+ }) else {
+ return false;
+ };
+ if !body.syntax().text_range().contains_range(range) {
+ return false;
+ }
+ body.token_trees_and_tokens().filter_map(|tt| tt.into_node()).any(|tt| {
+ let Some(next) = non_trivia_sibling(tt.syntax().syntax_element(), Direction::Next) else {
+ return false;
+ };
+ let Some(next_next) = next.next_sibling_or_token() else { return false };
+ next.kind() == T![=]
+ && next_next.kind() == T![>]
+ && tt.syntax().text_range().contains_range(range)
+ })
+}