aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion/complete_keyword.rs43
-rw-r--r--crates/ra_analysis/src/completion/completion_context.rs18
2 files changed, 46 insertions, 15 deletions
diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs
index d1e0a20a8..2869e67e0 100644
--- a/crates/ra_analysis/src/completion/complete_keyword.rs
+++ b/crates/ra_analysis/src/completion/complete_keyword.rs
@@ -35,7 +35,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
35 acc.add(keyword("continue", "continue")); 35 acc.add(keyword("continue", "continue"));
36 acc.add(keyword("break", "break")); 36 acc.add(keyword("break", "break"));
37 } 37 }
38 acc.add_all(complete_return(fn_def, ctx.is_stmt)); 38 acc.add_all(complete_return(fn_def, ctx.can_be_stmt));
39} 39}
40 40
41fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { 41fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool {
@@ -57,8 +57,8 @@ fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool {
57 false 57 false
58} 58}
59 59
60fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option<CompletionItem> { 60fn complete_return(fn_def: ast::FnDef, can_be_stmt: bool) -> Option<CompletionItem> {
61 let snip = match (is_stmt, fn_def.ret_type().is_some()) { 61 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
62 (true, true) => "return $0;", 62 (true, true) => "return $0;",
63 (true, false) => "return;", 63 (true, false) => "return;",
64 (false, true) => "return $0", 64 (false, true) => "return $0",
@@ -75,7 +75,7 @@ mod tests {
75 } 75 }
76 76
77 #[test] 77 #[test]
78 fn test_completion_kewords() { 78 fn completes_various_keywords_in_function() {
79 check_keyword_completion( 79 check_keyword_completion(
80 r" 80 r"
81 fn quux() { 81 fn quux() {
@@ -87,13 +87,13 @@ mod tests {
87 match "match $0 {}" 87 match "match $0 {}"
88 while "while $0 {}" 88 while "while $0 {}"
89 loop "loop {$0}" 89 loop "loop {$0}"
90 return "return" 90 return "return;"
91 "#, 91 "#,
92 ); 92 );
93 } 93 }
94 94
95 #[test] 95 #[test]
96 fn test_completion_else() { 96 fn completes_else_after_if() {
97 check_keyword_completion( 97 check_keyword_completion(
98 r" 98 r"
99 fn quux() { 99 fn quux() {
@@ -109,7 +109,7 @@ mod tests {
109 loop "loop {$0}" 109 loop "loop {$0}"
110 else "else {$0}" 110 else "else {$0}"
111 else if "else if $0 {}" 111 else if "else if $0 {}"
112 return "return" 112 return "return;"
113 "#, 113 "#,
114 ); 114 );
115 } 115 }
@@ -149,7 +149,7 @@ mod tests {
149 } 149 }
150 150
151 #[test] 151 #[test]
152 fn test_completion_return_no_stmt() { 152 fn dont_add_semi_after_return_if_not_a_statement() {
153 check_keyword_completion( 153 check_keyword_completion(
154 r" 154 r"
155 fn quux() -> i32 { 155 fn quux() -> i32 {
@@ -169,7 +169,27 @@ mod tests {
169 } 169 }
170 170
171 #[test] 171 #[test]
172 fn test_continue_break_completion() { 172 fn last_return_in_block_has_semi() {
173 check_keyword_completion(
174 r"
175 fn quux() -> i32 {
176 if condition {
177 <|>
178 }
179 }
180 ",
181 r#"
182 if "if $0 {}"
183 match "match $0 {}"
184 while "while $0 {}"
185 loop "loop {$0}"
186 return "return $0;"
187 "#,
188 );
189 }
190
191 #[test]
192 fn completes_break_and_continue_in_loops() {
173 check_keyword_completion( 193 check_keyword_completion(
174 r" 194 r"
175 fn quux() -> i32 { 195 fn quux() -> i32 {
@@ -183,9 +203,10 @@ mod tests {
183 loop "loop {$0}" 203 loop "loop {$0}"
184 continue "continue" 204 continue "continue"
185 break "break" 205 break "break"
186 return "return $0" 206 return "return $0;"
187 "#, 207 "#,
188 ); 208 );
209 // No completion: lambda isolates control flow
189 check_keyword_completion( 210 check_keyword_completion(
190 r" 211 r"
191 fn quux() -> i32 { 212 fn quux() -> i32 {
@@ -197,7 +218,7 @@ mod tests {
197 match "match $0 {}" 218 match "match $0 {}"
198 while "while $0 {}" 219 while "while $0 {}"
199 loop "loop {$0}" 220 loop "loop {$0}"
200 return "return $0" 221 return "return $0;"
201 "#, 222 "#,
202 ); 223 );
203 } 224 }
diff --git a/crates/ra_analysis/src/completion/completion_context.rs b/crates/ra_analysis/src/completion/completion_context.rs
index 949b8135e..4685c9328 100644
--- a/crates/ra_analysis/src/completion/completion_context.rs
+++ b/crates/ra_analysis/src/completion/completion_context.rs
@@ -31,7 +31,8 @@ pub(super) struct CompletionContext<'a> {
31 /// If not a trivial, path, the prefix (qualifier). 31 /// If not a trivial, path, the prefix (qualifier).
32 pub(super) path_prefix: Option<hir::Path>, 32 pub(super) path_prefix: Option<hir::Path>,
33 pub(super) after_if: bool, 33 pub(super) after_if: bool,
34 pub(super) is_stmt: bool, 34 /// `true` if we are a statement or a last expr in the block.
35 pub(super) can_be_stmt: bool,
35 /// Something is typed at the "top" level, in module or impl/trait. 36 /// Something is typed at the "top" level, in module or impl/trait.
36 pub(super) is_new_item: bool, 37 pub(super) is_new_item: bool,
37 /// The receiver if this is a field or method access, i.e. writing something.<|> 38 /// The receiver if this is a field or method access, i.e. writing something.<|>
@@ -61,7 +62,7 @@ impl<'a> CompletionContext<'a> {
61 is_trivial_path: false, 62 is_trivial_path: false,
62 path_prefix: None, 63 path_prefix: None,
63 after_if: false, 64 after_if: false,
64 is_stmt: false, 65 can_be_stmt: false,
65 is_new_item: false, 66 is_new_item: false,
66 dot_receiver: None, 67 dot_receiver: None,
67 is_method_call: false, 68 is_method_call: false,
@@ -147,13 +148,22 @@ impl<'a> CompletionContext<'a> {
147 if path.qualifier().is_none() { 148 if path.qualifier().is_none() {
148 self.is_trivial_path = true; 149 self.is_trivial_path = true;
149 150
150 self.is_stmt = match name_ref 151 self.can_be_stmt = match name_ref
151 .syntax() 152 .syntax()
152 .ancestors() 153 .ancestors()
153 .filter_map(ast::ExprStmt::cast) 154 .filter_map(ast::ExprStmt::cast)
154 .next() 155 .next()
155 { 156 {
156 None => false, 157 None => {
158 name_ref
159 .syntax()
160 .ancestors()
161 .filter_map(ast::Block::cast)
162 .next()
163 .and_then(|block| block.expr())
164 .map(|e| e.syntax().range())
165 == Some(name_ref.syntax().range())
166 }
157 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), 167 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
158 }; 168 };
159 169