aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/completion/patterns.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/completion/patterns.rs')
-rw-r--r--crates/ide/src/completion/patterns.rs203
1 files changed, 0 insertions, 203 deletions
diff --git a/crates/ide/src/completion/patterns.rs b/crates/ide/src/completion/patterns.rs
deleted file mode 100644
index b17ddf133..000000000
--- a/crates/ide/src/completion/patterns.rs
+++ /dev/null
@@ -1,203 +0,0 @@
1//! Patterns telling us certain facts about current syntax element, they are used in completion context
2
3use syntax::{
4 algo::non_trivia_sibling,
5 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken,
9};
10
11#[cfg(test)]
12use crate::completion::test_utils::check_pattern_is_applicable;
13
14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
15 not_same_range_ancestor(element)
16 .filter(|it| it.kind() == ASSOC_ITEM_LIST)
17 .and_then(|it| it.parent())
18 .filter(|it| it.kind() == TRAIT)
19 .is_some()
20}
21#[test]
22fn test_has_trait_parent() {
23 check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
24}
25
26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
27 not_same_range_ancestor(element)
28 .filter(|it| it.kind() == ASSOC_ITEM_LIST)
29 .and_then(|it| it.parent())
30 .filter(|it| it.kind() == IMPL)
31 .is_some()
32}
33#[test]
34fn test_has_impl_parent() {
35 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
36}
37pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
38 not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some()
39}
40#[test]
41fn test_has_field_list_parent() {
42 check_pattern_is_applicable(r"struct Foo { f<|> }", has_field_list_parent);
43 check_pattern_is_applicable(r"struct Foo { f<|> pub f: i32}", has_field_list_parent);
44}
45
46pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
47 not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
48}
49#[test]
50fn test_has_block_expr_parent() {
51 check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent);
52}
53
54pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
55 element.ancestors().find(|it| it.kind() == IDENT_PAT).is_some()
56}
57#[test]
58fn test_has_bind_pat_parent() {
59 check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent);
60 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
61}
62
63pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
64 not_same_range_ancestor(element)
65 .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR)
66 .is_some()
67}
68#[test]
69fn test_has_ref_parent() {
70 check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
71 check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
72}
73
74pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
75 let ancestor = not_same_range_ancestor(element);
76 if !ancestor.is_some() {
77 return true;
78 }
79 ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
80}
81#[test]
82fn test_has_item_list_or_source_file_parent() {
83 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
84 check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent);
85}
86
87pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
88 not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
89 && previous_sibling_or_ancestor_sibling(element)
90 .and_then(|it| it.into_token())
91 .filter(|it| it.kind() == FAT_ARROW)
92 .is_some()
93}
94#[test]
95fn test_is_match_arm() {
96 check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
97}
98
99pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
100 element
101 .into_token()
102 .and_then(|it| previous_non_trivia_token(it))
103 .filter(|it| it.kind() == UNSAFE_KW)
104 .is_some()
105}
106#[test]
107fn test_unsafe_is_prev() {
108 check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev);
109}
110
111pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
112 element
113 .into_token()
114 .and_then(|it| previous_non_trivia_token(it))
115 .filter(|it| it.kind() == IF_KW)
116 .is_some()
117}
118
119#[test]
120fn test_if_is_prev() {
121 check_pattern_is_applicable(r"if l<|>", if_is_prev);
122}
123
124pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
125 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some()
126}
127#[test]
128fn test_has_trait_as_prev_sibling() {
129 check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling);
130}
131
132pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
133 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some()
134}
135#[test]
136fn test_has_impl_as_prev_sibling() {
137 check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling);
138}
139
140pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
141 let leaf = match element {
142 NodeOrToken::Node(node) => node,
143 NodeOrToken::Token(token) => token.parent(),
144 };
145 for node in leaf.ancestors() {
146 if node.kind() == FN || node.kind() == CLOSURE_EXPR {
147 break;
148 }
149 let loop_body = match_ast! {
150 match node {
151 ast::ForExpr(it) => it.loop_body(),
152 ast::WhileExpr(it) => it.loop_body(),
153 ast::LoopExpr(it) => it.loop_body(),
154 _ => None,
155 }
156 };
157 if let Some(body) = loop_body {
158 if body.syntax().text_range().contains_range(leaf.text_range()) {
159 return true;
160 }
161 }
162 }
163 false
164}
165
166fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {
167 element
168 .ancestors()
169 .take_while(|it| it.text_range() == element.text_range())
170 .last()
171 .and_then(|it| it.parent())
172}
173
174fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
175 let mut token = token.prev_token();
176 while let Some(inner) = token.clone() {
177 if !inner.kind().is_trivia() {
178 return Some(inner);
179 } else {
180 token = inner.prev_token();
181 }
182 }
183 None
184}
185
186fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> {
187 let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev);
188 if let Some(sibling) = token_sibling {
189 Some(sibling)
190 } else {
191 // if not trying to find first ancestor which has such a sibling
192 let node = match element {
193 NodeOrToken::Node(node) => node,
194 NodeOrToken::Token(token) => token.parent(),
195 };
196 let range = node.text_range();
197 let top_node = node.ancestors().take_while(|it| it.text_range() == range).last()?;
198 let prev_sibling_node = top_node.ancestors().find(|it| {
199 non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some()
200 })?;
201 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
202 }
203}