diff options
Diffstat (limited to 'crates/ide_completion/src/patterns.rs')
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 95 |
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() { | |||
73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 73 | pub(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] |
77 | fn test_has_bind_pat_parent() { | 78 | fn 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 | ||
93 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { | 94 | pub(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] |
101 | fn test_has_item_list_or_source_file_parent() { | 101 | fn 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 | ||
118 | pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { | 118 | pub(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] | ||
126 | fn test_unsafe_is_prev() { | ||
127 | check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev); | ||
128 | } | ||
129 | |||
130 | pub(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 | |||
138 | pub(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] | ||
146 | fn 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] | 137 | pub(crate) fn has_prev_sibling(element: SyntaxElement, kind: SyntaxKind) -> bool { |
166 | fn 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 | |||
170 | pub(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] | ||
174 | fn test_has_trait_as_prev_sibling() { | ||
175 | check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling); | ||
176 | } | ||
177 | |||
178 | pub(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] |
182 | fn test_has_impl_as_prev_sibling() { | 141 | fn 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 | ||
186 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 145 | pub(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 | ||
208 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { | 163 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { |