aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs269
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs8
-rw-r--r--crates/ra_ide/src/completion/patterns.rs130
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs2
4 files changed, 154 insertions, 255 deletions
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index d016f0c7c..0ab330b73 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -36,184 +36,98 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
36 } 36 }
37} 37}
38 38
39fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
40 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
41 .kind(CompletionItemKind::Keyword);
42
43 match ctx.config.snippet_cap {
44 Some(cap) => res.insert_snippet(cap, snippet),
45 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
46 }
47 .build()
48}
49
50fn add_keyword(
51 ctx: &CompletionContext,
52 acc: &mut Completions,
53 kw: &str,
54 snippet: &str,
55 should_add: bool,
56) {
57 if should_add {
58 acc.add(keyword(ctx, kw, snippet));
59 }
60}
61
62pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
63 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; 40 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
64 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { 41 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
65 add_keyword(ctx, acc, "where", "where ", true); 42 add_keyword(ctx, acc, "where", "where ");
66 return; 43 return;
67 } 44 }
68 if ctx.unsafe_is_prev { 45 if ctx.unsafe_is_prev {
69 add_keyword( 46 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
70 ctx, 47 add_keyword(ctx, acc, "fn", "fn $0() {}")
71 acc, 48 }
72 "fn", 49
73 "fn $0() {}", 50 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
74 ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent, 51 || ctx.block_expr_parent
75 ); 52 {
76 add_keyword( 53 add_keyword(ctx, acc, "trait", "trait $0 {}");
77 ctx, 54 add_keyword(ctx, acc, "impl", "impl $0 {}");
78 acc, 55 }
79 "trait", 56
80 "trait $0 {}",
81 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
82 || ctx.block_expr_parent,
83 );
84 add_keyword(
85 ctx,
86 acc,
87 "impl",
88 "impl $0 {}",
89 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
90 || ctx.block_expr_parent,
91 );
92 return; 57 return;
93 } 58 }
94 add_keyword( 59 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
95 ctx, 60 add_keyword(ctx, acc, "fn", "fn $0() {}");
96 acc, 61 }
97 "fn", 62 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
98 "fn $0() {}", 63 || ctx.block_expr_parent
99 ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent, 64 {
100 ); 65 add_keyword(ctx, acc, "use", "use ");
101 add_keyword( 66 add_keyword(ctx, acc, "impl", "impl $0 {}");
102 ctx, 67 add_keyword(ctx, acc, "trait", "trait $0 {}");
103 acc, 68 }
104 "use", 69
105 "use ", 70 if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent {
106 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 71 add_keyword(ctx, acc, "enum", "enum $0 {}");
107 || ctx.block_expr_parent, 72 add_keyword(ctx, acc, "struct", "struct $0 {}");
108 ); 73 add_keyword(ctx, acc, "union", "union $0 {}");
109 add_keyword( 74 }
110 ctx, 75
111 acc, 76 if ctx.block_expr_parent || ctx.is_match_arm {
112 "impl", 77 add_keyword(ctx, acc, "match", "match $0 {}");
113 "impl $0 {}", 78 add_keyword(ctx, acc, "loop", "loop {$0}");
114 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 79 }
115 || ctx.block_expr_parent, 80 if ctx.block_expr_parent {
116 ); 81 add_keyword(ctx, acc, "while", "while $0 {}");
117 add_keyword( 82 }
118 ctx, 83 if ctx.if_is_prev || ctx.block_expr_parent {
119 acc, 84 add_keyword(ctx, acc, "let", "let ");
120 "trait", 85 }
121 "trait $0 {}", 86 if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm {
122 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 87 add_keyword(ctx, acc, "if", "if ");
123 || ctx.block_expr_parent, 88 add_keyword(ctx, acc, "if let", "if let ");
124 ); 89 }
125 add_keyword( 90 if ctx.after_if {
126 ctx, 91 add_keyword(ctx, acc, "else", "else {$0}");
127 acc, 92 add_keyword(ctx, acc, "else if", "else if $0 {}");
128 "enum", 93 }
129 "enum $0 {}", 94 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
130 ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent, 95 || ctx.block_expr_parent
131 ); 96 {
132 add_keyword( 97 add_keyword(ctx, acc, "mod", "mod $0 {}");
133 ctx, 98 }
134 acc, 99 if ctx.bind_pat_parent || ctx.ref_pat_parent {
135 "struct", 100 add_keyword(ctx, acc, "mut", "mut ");
136 "struct $0 {}", 101 }
137 ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent, 102 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
138 ); 103 add_keyword(ctx, acc, "const", "const ");
139 add_keyword( 104 add_keyword(ctx, acc, "type", "type ");
140 ctx, 105 }
141 acc, 106 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
142 "union", 107 || ctx.block_expr_parent
143 "union $0 {}", 108 {
144 ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent, 109 add_keyword(ctx, acc, "static", "static ");
145 ); 110 };
146 add_keyword(ctx, acc, "match", "match $0 {}", ctx.block_expr_parent || ctx.is_match_arm); 111 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
147 add_keyword(ctx, acc, "loop", "loop {$0}", ctx.block_expr_parent || ctx.is_match_arm); 112 || ctx.block_expr_parent
148 add_keyword(ctx, acc, "while", "while $0 {}", ctx.block_expr_parent); 113 {
149 add_keyword(ctx, acc, "let", "let ", ctx.if_is_prev || ctx.block_expr_parent); 114 add_keyword(ctx, acc, "extern", "extern ");
150 add_keyword(ctx, acc, "if", "if ", ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm); 115 }
151 add_keyword( 116 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm {
152 ctx, 117 add_keyword(ctx, acc, "unsafe", "unsafe ");
153 acc, 118 }
154 "if let", 119 if ctx.in_loop_body {
155 "if let ", 120 if ctx.can_be_stmt {
156 ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm, 121 add_keyword(ctx, acc, "continue", "continue;");
157 ); 122 add_keyword(ctx, acc, "break", "break;");
158 add_keyword(ctx, acc, "else", "else {$0}", ctx.after_if); 123 } else {
159 add_keyword(ctx, acc, "else if", "else if $0 {}", ctx.after_if); 124 add_keyword(ctx, acc, "continue", "continue");
160 add_keyword( 125 add_keyword(ctx, acc, "break", "break");
161 ctx, 126 }
162 acc, 127 }
163 "mod", 128 if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent {
164 "mod $0 {}", 129 add_keyword(ctx, acc, "pub", "pub ")
165 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 130 }
166 || ctx.block_expr_parent,
167 );
168 add_keyword(ctx, acc, "mut", "mut ", ctx.bind_pat_parent || ctx.ref_pat_parent);
169 add_keyword(
170 ctx,
171 acc,
172 "const",
173 "const ",
174 ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent,
175 );
176 add_keyword(
177 ctx,
178 acc,
179 "type",
180 "type ",
181 ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent,
182 );
183 add_keyword(
184 ctx,
185 acc,
186 "static",
187 "static ",
188 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
189 || ctx.block_expr_parent,
190 );
191 add_keyword(
192 ctx,
193 acc,
194 "extern",
195 "extern ",
196 (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
197 || ctx.block_expr_parent,
198 );
199 add_keyword(
200 ctx,
201 acc,
202 "unsafe",
203 "unsafe ",
204 ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm,
205 );
206 add_keyword(ctx, acc, "continue", "continue;", ctx.in_loop_body && ctx.can_be_stmt);
207 add_keyword(ctx, acc, "break", "break;", ctx.in_loop_body && ctx.can_be_stmt);
208 add_keyword(ctx, acc, "continue", "continue", ctx.in_loop_body && !ctx.can_be_stmt);
209 add_keyword(ctx, acc, "break", "break", ctx.in_loop_body && !ctx.can_be_stmt);
210 add_keyword(
211 ctx,
212 acc,
213 "pub",
214 "pub ",
215 ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent,
216 );
217 131
218 if !ctx.is_trivial_path { 132 if !ctx.is_trivial_path {
219 return; 133 return;
@@ -225,6 +139,21 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
225 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt)); 139 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
226} 140}
227 141
142fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
143 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
144 .kind(CompletionItemKind::Keyword);
145
146 match ctx.config.snippet_cap {
147 Some(cap) => res.insert_snippet(cap, snippet),
148 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
149 }
150 .build()
151}
152
153fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
154 acc.add(keyword(ctx, kw, snippet));
155}
156
228fn complete_return( 157fn complete_return(
229 ctx: &CompletionContext, 158 ctx: &CompletionContext,
230 fn_def: &ast::FnDef, 159 fn_def: &ast::FnDef,
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index d1a4dd881..98348b349 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -126,8 +126,9 @@ pub enum CompletionItemKind {
126} 126}
127 127
128impl CompletionItemKind { 128impl CompletionItemKind {
129 pub fn tag(&self) -> String { 129 #[cfg(test)]
130 let tag = match self { 130 pub(crate) fn tag(&self) -> &'static str {
131 match self {
131 CompletionItemKind::Snippet => "sn", 132 CompletionItemKind::Snippet => "sn",
132 CompletionItemKind::Keyword => "kw", 133 CompletionItemKind::Keyword => "kw",
133 CompletionItemKind::Module => "md", 134 CompletionItemKind::Module => "md",
@@ -146,8 +147,7 @@ impl CompletionItemKind {
146 CompletionItemKind::TypeParam => "tp", 147 CompletionItemKind::TypeParam => "tp",
147 CompletionItemKind::Macro => "ma", 148 CompletionItemKind::Macro => "ma",
148 CompletionItemKind::Attribute => "at", 149 CompletionItemKind::Attribute => "at",
149 }; 150 }
150 tag.to_owned()
151 } 151 }
152} 152}
153 153
diff --git a/crates/ra_ide/src/completion/patterns.rs b/crates/ra_ide/src/completion/patterns.rs
index fdcd3faa5..b2fe13280 100644
--- a/crates/ra_ide/src/completion/patterns.rs
+++ b/crates/ra_ide/src/completion/patterns.rs
@@ -8,6 +8,9 @@ use ra_syntax::{
8 SyntaxNode, SyntaxToken, 8 SyntaxNode, SyntaxToken,
9}; 9};
10 10
11#[cfg(test)]
12use crate::completion::test_utils::check_pattern_is_applicable;
13
11pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool { 14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
12 not_same_range_ancestor(element) 15 not_same_range_ancestor(element)
13 .filter(|it| it.kind() == ITEM_LIST) 16 .filter(|it| it.kind() == ITEM_LIST)
@@ -15,6 +18,10 @@ pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
15 .filter(|it| it.kind() == TRAIT_DEF) 18 .filter(|it| it.kind() == TRAIT_DEF)
16 .is_some() 19 .is_some()
17} 20}
21#[test]
22fn test_has_trait_parent() {
23 check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
24}
18 25
19pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { 26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
20 not_same_range_ancestor(element) 27 not_same_range_ancestor(element)
@@ -23,20 +30,38 @@ pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
23 .filter(|it| it.kind() == IMPL_DEF) 30 .filter(|it| it.kind() == IMPL_DEF)
24 .is_some() 31 .is_some()
25} 32}
33#[test]
34fn test_has_impl_parent() {
35 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
36}
26 37
27pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { 38pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
28 not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some() 39 not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
29} 40}
41#[test]
42fn test_has_block_expr_parent() {
43 check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent);
44}
30 45
31pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { 46pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
32 element.ancestors().find(|it| it.kind() == BIND_PAT).is_some() 47 element.ancestors().find(|it| it.kind() == BIND_PAT).is_some()
33} 48}
49#[test]
50fn test_has_bind_pat_parent() {
51 check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent);
52 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
53}
34 54
35pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool { 55pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
36 not_same_range_ancestor(element) 56 not_same_range_ancestor(element)
37 .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR) 57 .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR)
38 .is_some() 58 .is_some()
39} 59}
60#[test]
61fn test_has_ref_parent() {
62 check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
63 check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
64}
40 65
41pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { 66pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
42 let ancestor = not_same_range_ancestor(element); 67 let ancestor = not_same_range_ancestor(element);
@@ -45,6 +70,11 @@ pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> boo
45 } 70 }
46 ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some() 71 ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
47} 72}
73#[test]
74fn test_has_item_list_or_source_file_parent() {
75 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
76 check_pattern_is_applicable(r"impl { f<|> }", has_item_list_or_source_file_parent);
77}
48 78
49pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { 79pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
50 not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some() 80 not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
@@ -53,6 +83,10 @@ pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
53 .filter(|it| it.kind() == FAT_ARROW) 83 .filter(|it| it.kind() == FAT_ARROW)
54 .is_some() 84 .is_some()
55} 85}
86#[test]
87fn test_is_match_arm() {
88 check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
89}
56 90
57pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { 91pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
58 element 92 element
@@ -61,6 +95,10 @@ pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
61 .filter(|it| it.kind() == UNSAFE_KW) 95 .filter(|it| it.kind() == UNSAFE_KW)
62 .is_some() 96 .is_some()
63} 97}
98#[test]
99fn test_unsafe_is_prev() {
100 check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev);
101}
64 102
65pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { 103pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
66 element 104 element
@@ -69,14 +107,26 @@ pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
69 .filter(|it| it.kind() == IF_KW) 107 .filter(|it| it.kind() == IF_KW)
70 .is_some() 108 .is_some()
71} 109}
110#[test]
111fn test_if_is_prev() {
112 check_pattern_is_applicable(r"if l<|>", if_is_prev);
113}
72 114
73pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { 115pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
74 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some() 116 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some()
75} 117}
118#[test]
119fn test_has_trait_as_prev_sibling() {
120 check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling);
121}
76 122
77pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { 123pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
78 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL_DEF).is_some() 124 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL_DEF).is_some()
79} 125}
126#[test]
127fn test_has_impl_as_prev_sibling() {
128 check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling);
129}
80 130
81pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { 131pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
82 let leaf = match element { 132 let leaf = match element {
@@ -142,83 +192,3 @@ fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<Syntax
142 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev) 192 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
143 } 193 }
144} 194}
145
146#[cfg(test)]
147mod tests {
148 use super::{
149 has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_impl_parent,
150 has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
151 has_trait_parent, if_is_prev, is_match_arm, unsafe_is_prev,
152 };
153 use crate::completion::test_utils::check_pattern_is_applicable;
154
155 #[test]
156 fn test_unsafe_is_prev() {
157 check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev);
158 }
159
160 #[test]
161 fn test_if_is_prev() {
162 check_pattern_is_applicable(r"if l<|>", if_is_prev);
163 }
164
165 #[test]
166 fn test_has_trait_parent() {
167 check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
168 }
169
170 #[test]
171 fn test_has_impl_parent() {
172 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
173 }
174
175 #[test]
176 fn test_has_trait_as_prev_sibling() {
177 check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling);
178 }
179
180 #[test]
181 fn test_has_impl_as_prev_sibling() {
182 check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling);
183 }
184
185 #[test]
186 fn test_parent_block_expr() {
187 check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent);
188 }
189
190 #[test]
191 fn test_has_ref_pat_parent_in_func_parameters() {
192 check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
193 }
194
195 #[test]
196 fn test_has_ref_pat_parent_in_let_statement() {
197 check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
198 }
199
200 #[test]
201 fn test_has_bind_pat_parent_in_func_parameters() {
202 check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent);
203 }
204
205 #[test]
206 fn test_has_bind_pat_parent_in_let_statement() {
207 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
208 }
209
210 #[test]
211 fn test_is_match_arm() {
212 check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
213 }
214
215 #[test]
216 fn test_has_source_file_parent() {
217 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
218 }
219
220 #[test]
221 fn test_has_item_list_parent() {
222 check_pattern_is_applicable(r"impl { f<|> }", has_item_list_or_source_file_parent);
223 }
224}
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index 8b838a0a5..ba724116d 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -25,7 +25,7 @@ pub(crate) fn do_completion_with_options(
25 .into_iter() 25 .into_iter()
26 .filter(|c| c.completion_kind == kind) 26 .filter(|c| c.completion_kind == kind)
27 .collect(); 27 .collect();
28 kind_completions.sort_by_key(|c| c.label().to_owned()); 28 kind_completions.sort_by(|l, r| l.label().cmp(r.label()));
29 kind_completions 29 kind_completions
30} 30}
31 31