aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/patterns.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/patterns.rs')
-rw-r--r--crates/ide_completion/src/patterns.rs95
1 files changed, 25 insertions, 70 deletions
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index d82564381..04f2c532b 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -4,7 +4,7 @@ use syntax::{
4 algo::non_trivia_sibling, 4 algo::non_trivia_sibling,
5 ast::{self, LoopBodyOwner}, 5 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, 6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
7 SyntaxKind::*, 7 SyntaxKind::{self, *},
8 SyntaxNode, SyntaxToken, T, 8 SyntaxNode, SyntaxToken, T,
9}; 9};
10 10
@@ -73,6 +73,7 @@ fn test_has_block_expr_parent() {
73pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { 73pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
74 element.ancestors().any(|it| it.kind() == IDENT_PAT) 74 element.ancestors().any(|it| it.kind() == IDENT_PAT)
75} 75}
76
76#[test] 77#[test]
77fn test_has_bind_pat_parent() { 78fn test_has_bind_pat_parent() {
78 check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent); 79 check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent);
@@ -91,11 +92,10 @@ fn test_has_ref_parent() {
91} 92}
92 93
93pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { 94pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
94 let ancestor = not_same_range_ancestor(element); 95 match not_same_range_ancestor(element) {
95 if !ancestor.is_some() { 96 Some(it) => it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST,
96 return true; 97 None => true,
97 } 98 }
98 ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
99} 99}
100#[test] 100#[test]
101fn test_has_item_list_or_source_file_parent() { 101fn test_has_item_list_or_source_file_parent() {
@@ -115,36 +115,8 @@ fn test_is_match_arm() {
115 check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); 115 check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm);
116} 116}
117 117
118pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { 118pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
119 element 119 element.into_token().and_then(|it| previous_non_trivia_token(it))
120 .into_token()
121 .and_then(|it| previous_non_trivia_token(it))
122 .filter(|it| it.kind() == T![unsafe])
123 .is_some()
124}
125#[test]
126fn test_unsafe_is_prev() {
127 check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev);
128}
129
130pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
131 element
132 .into_token()
133 .and_then(|it| previous_non_trivia_token(it))
134 .filter(|it| it.kind() == T![if])
135 .is_some()
136}
137
138pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool {
139 element
140 .into_token()
141 .and_then(|it| previous_non_trivia_token(it))
142 .filter(|it| it.kind() == T![fn])
143 .is_some()
144}
145#[test]
146fn test_fn_is_prev() {
147 check_pattern_is_applicable(r"fn l$0", fn_is_prev);
148} 120}
149 121
150/// Check if the token previous to the previous one is `for`. 122/// Check if the token previous to the previous one is `for`.
@@ -162,47 +134,30 @@ fn test_for_is_prev2() {
162 check_pattern_is_applicable(r"for i i$0", for_is_prev2); 134 check_pattern_is_applicable(r"for i i$0", for_is_prev2);
163} 135}
164 136
165#[test] 137pub(crate) fn has_prev_sibling(element: SyntaxElement, kind: SyntaxKind) -> bool {
166fn test_if_is_prev() { 138 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == kind).is_some()
167 check_pattern_is_applicable(r"if l$0", if_is_prev);
168}
169
170pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
171 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some()
172}
173#[test]
174fn test_has_trait_as_prev_sibling() {
175 check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling);
176}
177
178pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
179 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some()
180} 139}
181#[test] 140#[test]
182fn test_has_impl_as_prev_sibling() { 141fn test_has_impl_as_prev_sibling() {
183 check_pattern_is_applicable(r"impl A w$0 {}", has_impl_as_prev_sibling); 142 check_pattern_is_applicable(r"impl A w$0 {}", |it| has_prev_sibling(it, IMPL));
184} 143}
185 144
186pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { 145pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
187 for node in element.ancestors() { 146 element
188 if node.kind() == FN || node.kind() == CLOSURE_EXPR { 147 .ancestors()
189 break; 148 .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR)
190 } 149 .find_map(|it| {
191 let loop_body = match_ast! { 150 let loop_body = match_ast! {
192 match node { 151 match it {
193 ast::ForExpr(it) => it.loop_body(), 152 ast::ForExpr(it) => it.loop_body(),
194 ast::WhileExpr(it) => it.loop_body(), 153 ast::WhileExpr(it) => it.loop_body(),
195 ast::LoopExpr(it) => it.loop_body(), 154 ast::LoopExpr(it) => it.loop_body(),
196 _ => None, 155 _ => None,
197 } 156 }
198 }; 157 };
199 if let Some(body) = loop_body { 158 loop_body.filter(|it| it.syntax().text_range().contains_range(element.text_range()))
200 if body.syntax().text_range().contains_range(element.text_range()) { 159 })
201 return true; 160 .is_some()
202 }
203 }
204 }
205 false
206} 161}
207 162
208fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { 163fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {