diff options
author | Aleksey Kladov <[email protected]> | 2018-12-30 14:09:27 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-12-30 14:22:12 +0000 |
commit | 0f75ac1ae073e8735a84484ef9d1453e6c919b24 (patch) | |
tree | fa52db75cb2b16c86050852f7dc6c02d0803f53b | |
parent | c182aab5460fb5dc14b8c0e47fae45a09ccf0ac8 (diff) |
add `;` to last return in block
-rw-r--r-- | crates/ra_analysis/src/completion/complete_keyword.rs | 43 | ||||
-rw-r--r-- | crates/ra_analysis/src/completion/completion_context.rs | 18 |
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 | ||
41 | fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { | 41 | fn 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 | ||
60 | fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option<CompletionItem> { | 60 | fn 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 | ||