diff options
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 30 | ||||
-rw-r--r-- | crates/ra_assists/src/ast_transform.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/doc_tests/generated.rs | 23 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_missing_impl_members.rs | 194 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 42 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/early_return.rs | 16 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/inline_local_variable.rs | 1 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/introduce_variable.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/move_guard.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/unwrap_block.rs | 348 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/utils.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/utils/insert_use.rs | 9 |
14 files changed, 569 insertions, 110 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 2fe7c3de3..da2880037 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -105,7 +105,7 @@ impl<'a> AssistCtx<'a> { | |||
105 | let mut info = AssistInfo::new(label); | 105 | let mut info = AssistInfo::new(label); |
106 | if self.should_compute_edit { | 106 | if self.should_compute_edit { |
107 | let action = { | 107 | let action = { |
108 | let mut edit = ActionBuilder::default(); | 108 | let mut edit = ActionBuilder::new(&self); |
109 | f(&mut edit); | 109 | f(&mut edit); |
110 | edit.build() | 110 | edit.build() |
111 | }; | 111 | }; |
@@ -130,6 +130,12 @@ impl<'a> AssistCtx<'a> { | |||
130 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { | 130 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { |
131 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) | 131 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) |
132 | } | 132 | } |
133 | |||
134 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { | ||
135 | self.sema | ||
136 | .find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start()) | ||
137 | } | ||
138 | |||
133 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 139 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
134 | find_covering_element(self.source_file.syntax(), self.frange.range) | 140 | find_covering_element(self.source_file.syntax(), self.frange.range) |
135 | } | 141 | } |
@@ -156,7 +162,7 @@ impl<'a> AssistGroup<'a> { | |||
156 | let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone())); | 162 | let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone())); |
157 | if self.ctx.should_compute_edit { | 163 | if self.ctx.should_compute_edit { |
158 | let action = { | 164 | let action = { |
159 | let mut edit = ActionBuilder::default(); | 165 | let mut edit = ActionBuilder::new(&self.ctx); |
160 | f(&mut edit); | 166 | f(&mut edit); |
161 | edit.build() | 167 | edit.build() |
162 | }; | 168 | }; |
@@ -175,15 +181,29 @@ impl<'a> AssistGroup<'a> { | |||
175 | } | 181 | } |
176 | } | 182 | } |
177 | 183 | ||
178 | #[derive(Default)] | 184 | pub(crate) struct ActionBuilder<'a, 'b> { |
179 | pub(crate) struct ActionBuilder { | ||
180 | edit: TextEditBuilder, | 185 | edit: TextEditBuilder, |
181 | cursor_position: Option<TextSize>, | 186 | cursor_position: Option<TextSize>, |
182 | target: Option<TextRange>, | 187 | target: Option<TextRange>, |
183 | file: AssistFile, | 188 | file: AssistFile, |
189 | ctx: &'a AssistCtx<'b>, | ||
184 | } | 190 | } |
185 | 191 | ||
186 | impl ActionBuilder { | 192 | impl<'a, 'b> ActionBuilder<'a, 'b> { |
193 | fn new(ctx: &'a AssistCtx<'b>) -> Self { | ||
194 | Self { | ||
195 | edit: TextEditBuilder::default(), | ||
196 | cursor_position: None, | ||
197 | target: None, | ||
198 | file: AssistFile::default(), | ||
199 | ctx, | ||
200 | } | ||
201 | } | ||
202 | |||
203 | pub(crate) fn ctx(&self) -> &AssistCtx<'b> { | ||
204 | &self.ctx | ||
205 | } | ||
206 | |||
187 | /// Replaces specified `range` of text with a given string. | 207 | /// Replaces specified `range` of text with a given string. |
188 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { | 208 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { |
189 | self.edit.replace(range, replace_with.into()) | 209 | self.edit.replace(range, replace_with.into()) |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 52b4c82db..9ac65ab39 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -85,6 +85,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
85 | ast::TypeRef::PathType(path_type) => path_type.path()?, | 85 | ast::TypeRef::PathType(path_type) => path_type.path()?, |
86 | _ => return None, | 86 | _ => return None, |
87 | }; | 87 | }; |
88 | // FIXME: use `hir::Path::from_src` instead. | ||
88 | let path = hir::Path::from_ast(path)?; | 89 | let path = hir::Path::from_ast(path)?; |
89 | let resolution = self.source_scope.resolve_hir_path(&path)?; | 90 | let resolution = self.source_scope.resolve_hir_path(&path)?; |
90 | match resolution { | 91 | match resolution { |
@@ -128,6 +129,7 @@ impl<'a> QualifyPaths<'a> { | |||
128 | // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway | 129 | // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway |
129 | return None; | 130 | return None; |
130 | } | 131 | } |
132 | // FIXME: use `hir::Path::from_src` instead. | ||
131 | let hir_path = hir::Path::from_ast(p.clone()); | 133 | let hir_path = hir::Path::from_ast(p.clone()); |
132 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 134 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
133 | match resolution { | 135 | match resolution { |
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index e4fa9ee36..6696cc832 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -180,7 +180,9 @@ trait Trait<T> { | |||
180 | } | 180 | } |
181 | 181 | ||
182 | impl Trait<u32> for () { | 182 | impl Trait<u32> for () { |
183 | fn foo(&self) -> u32 { todo!() } | 183 | fn foo(&self) -> u32 { |
184 | todo!() | ||
185 | } | ||
184 | 186 | ||
185 | } | 187 | } |
186 | "#####, | 188 | "#####, |
@@ -726,3 +728,22 @@ use std::{collections::HashMap}; | |||
726 | "#####, | 728 | "#####, |
727 | ) | 729 | ) |
728 | } | 730 | } |
731 | |||
732 | #[test] | ||
733 | fn doctest_unwrap_block() { | ||
734 | check( | ||
735 | "unwrap_block", | ||
736 | r#####" | ||
737 | fn foo() { | ||
738 | if true {<|> | ||
739 | println!("foo"); | ||
740 | } | ||
741 | } | ||
742 | "#####, | ||
743 | r#####" | ||
744 | fn foo() { | ||
745 | println!("foo"); | ||
746 | } | ||
747 | "#####, | ||
748 | ) | ||
749 | } | ||
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 2d6d44980..e466c9a86 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -1,6 +1,10 @@ | |||
1 | use hir::HasSource; | 1 | use hir::HasSource; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, edit, make, AstNode, NameOwner}, | 3 | ast::{ |
4 | self, | ||
5 | edit::{self, IndentLevel}, | ||
6 | make, AstNode, NameOwner, | ||
7 | }, | ||
4 | SmolStr, | 8 | SmolStr, |
5 | }; | 9 | }; |
6 | 10 | ||
@@ -40,7 +44,9 @@ enum AddMissingImplMembersMode { | |||
40 | // } | 44 | // } |
41 | // | 45 | // |
42 | // impl Trait<u32> for () { | 46 | // impl Trait<u32> for () { |
43 | // fn foo(&self) -> u32 { todo!() } | 47 | // fn foo(&self) -> u32 { |
48 | // todo!() | ||
49 | // } | ||
44 | // | 50 | // |
45 | // } | 51 | // } |
46 | // ``` | 52 | // ``` |
@@ -165,7 +171,9 @@ fn add_missing_impl_members_inner( | |||
165 | 171 | ||
166 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 172 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
167 | if fn_def.body().is_none() { | 173 | if fn_def.body().is_none() { |
168 | fn_def.with_body(make::block_from_expr(make::expr_todo())) | 174 | let body = make::block_expr(None, Some(make::expr_todo())); |
175 | let body = IndentLevel(1).increase_indent(body); | ||
176 | fn_def.with_body(body) | ||
169 | } else { | 177 | } else { |
170 | fn_def | 178 | fn_def |
171 | } | 179 | } |
@@ -181,7 +189,7 @@ mod tests { | |||
181 | fn test_add_missing_impl_members() { | 189 | fn test_add_missing_impl_members() { |
182 | check_assist( | 190 | check_assist( |
183 | add_missing_impl_members, | 191 | add_missing_impl_members, |
184 | " | 192 | r#" |
185 | trait Foo { | 193 | trait Foo { |
186 | type Output; | 194 | type Output; |
187 | 195 | ||
@@ -197,8 +205,8 @@ struct S; | |||
197 | impl Foo for S { | 205 | impl Foo for S { |
198 | fn bar(&self) {} | 206 | fn bar(&self) {} |
199 | <|> | 207 | <|> |
200 | }", | 208 | }"#, |
201 | " | 209 | r#" |
202 | trait Foo { | 210 | trait Foo { |
203 | type Output; | 211 | type Output; |
204 | 212 | ||
@@ -215,10 +223,14 @@ impl Foo for S { | |||
215 | fn bar(&self) {} | 223 | fn bar(&self) {} |
216 | <|>type Output; | 224 | <|>type Output; |
217 | const CONST: usize = 42; | 225 | const CONST: usize = 42; |
218 | fn foo(&self) { todo!() } | 226 | fn foo(&self) { |
219 | fn baz(&self) { todo!() } | 227 | todo!() |
228 | } | ||
229 | fn baz(&self) { | ||
230 | todo!() | ||
231 | } | ||
220 | 232 | ||
221 | }", | 233 | }"#, |
222 | ); | 234 | ); |
223 | } | 235 | } |
224 | 236 | ||
@@ -226,7 +238,7 @@ impl Foo for S { | |||
226 | fn test_copied_overriden_members() { | 238 | fn test_copied_overriden_members() { |
227 | check_assist( | 239 | check_assist( |
228 | add_missing_impl_members, | 240 | add_missing_impl_members, |
229 | " | 241 | r#" |
230 | trait Foo { | 242 | trait Foo { |
231 | fn foo(&self); | 243 | fn foo(&self); |
232 | fn bar(&self) -> bool { true } | 244 | fn bar(&self) -> bool { true } |
@@ -238,8 +250,8 @@ struct S; | |||
238 | impl Foo for S { | 250 | impl Foo for S { |
239 | fn bar(&self) {} | 251 | fn bar(&self) {} |
240 | <|> | 252 | <|> |
241 | }", | 253 | }"#, |
242 | " | 254 | r#" |
243 | trait Foo { | 255 | trait Foo { |
244 | fn foo(&self); | 256 | fn foo(&self); |
245 | fn bar(&self) -> bool { true } | 257 | fn bar(&self) -> bool { true } |
@@ -250,9 +262,11 @@ struct S; | |||
250 | 262 | ||
251 | impl Foo for S { | 263 | impl Foo for S { |
252 | fn bar(&self) {} | 264 | fn bar(&self) {} |
253 | <|>fn foo(&self) { todo!() } | 265 | <|>fn foo(&self) { |
266 | todo!() | ||
267 | } | ||
254 | 268 | ||
255 | }", | 269 | }"#, |
256 | ); | 270 | ); |
257 | } | 271 | } |
258 | 272 | ||
@@ -260,16 +274,18 @@ impl Foo for S { | |||
260 | fn test_empty_impl_def() { | 274 | fn test_empty_impl_def() { |
261 | check_assist( | 275 | check_assist( |
262 | add_missing_impl_members, | 276 | add_missing_impl_members, |
263 | " | 277 | r#" |
264 | trait Foo { fn foo(&self); } | 278 | trait Foo { fn foo(&self); } |
265 | struct S; | 279 | struct S; |
266 | impl Foo for S { <|> }", | 280 | impl Foo for S { <|> }"#, |
267 | " | 281 | r#" |
268 | trait Foo { fn foo(&self); } | 282 | trait Foo { fn foo(&self); } |
269 | struct S; | 283 | struct S; |
270 | impl Foo for S { | 284 | impl Foo for S { |
271 | <|>fn foo(&self) { todo!() } | 285 | <|>fn foo(&self) { |
272 | }", | 286 | todo!() |
287 | } | ||
288 | }"#, | ||
273 | ); | 289 | ); |
274 | } | 290 | } |
275 | 291 | ||
@@ -277,16 +293,18 @@ impl Foo for S { | |||
277 | fn fill_in_type_params_1() { | 293 | fn fill_in_type_params_1() { |
278 | check_assist( | 294 | check_assist( |
279 | add_missing_impl_members, | 295 | add_missing_impl_members, |
280 | " | 296 | r#" |
281 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 297 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
282 | struct S; | 298 | struct S; |
283 | impl Foo<u32> for S { <|> }", | 299 | impl Foo<u32> for S { <|> }"#, |
284 | " | 300 | r#" |
285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 301 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
286 | struct S; | 302 | struct S; |
287 | impl Foo<u32> for S { | 303 | impl Foo<u32> for S { |
288 | <|>fn foo(&self, t: u32) -> &u32 { todo!() } | 304 | <|>fn foo(&self, t: u32) -> &u32 { |
289 | }", | 305 | todo!() |
306 | } | ||
307 | }"#, | ||
290 | ); | 308 | ); |
291 | } | 309 | } |
292 | 310 | ||
@@ -294,16 +312,18 @@ impl Foo<u32> for S { | |||
294 | fn fill_in_type_params_2() { | 312 | fn fill_in_type_params_2() { |
295 | check_assist( | 313 | check_assist( |
296 | add_missing_impl_members, | 314 | add_missing_impl_members, |
297 | " | 315 | r#" |
298 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 316 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
299 | struct S; | 317 | struct S; |
300 | impl<U> Foo<U> for S { <|> }", | 318 | impl<U> Foo<U> for S { <|> }"#, |
301 | " | 319 | r#" |
302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 320 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
303 | struct S; | 321 | struct S; |
304 | impl<U> Foo<U> for S { | 322 | impl<U> Foo<U> for S { |
305 | <|>fn foo(&self, t: U) -> &U { todo!() } | 323 | <|>fn foo(&self, t: U) -> &U { |
306 | }", | 324 | todo!() |
325 | } | ||
326 | }"#, | ||
307 | ); | 327 | ); |
308 | } | 328 | } |
309 | 329 | ||
@@ -311,16 +331,18 @@ impl<U> Foo<U> for S { | |||
311 | fn test_cursor_after_empty_impl_def() { | 331 | fn test_cursor_after_empty_impl_def() { |
312 | check_assist( | 332 | check_assist( |
313 | add_missing_impl_members, | 333 | add_missing_impl_members, |
314 | " | 334 | r#" |
315 | trait Foo { fn foo(&self); } | 335 | trait Foo { fn foo(&self); } |
316 | struct S; | 336 | struct S; |
317 | impl Foo for S {}<|>", | 337 | impl Foo for S {}<|>"#, |
318 | " | 338 | r#" |
319 | trait Foo { fn foo(&self); } | 339 | trait Foo { fn foo(&self); } |
320 | struct S; | 340 | struct S; |
321 | impl Foo for S { | 341 | impl Foo for S { |
322 | <|>fn foo(&self) { todo!() } | 342 | <|>fn foo(&self) { |
323 | }", | 343 | todo!() |
344 | } | ||
345 | }"#, | ||
324 | ) | 346 | ) |
325 | } | 347 | } |
326 | 348 | ||
@@ -328,22 +350,24 @@ impl Foo for S { | |||
328 | fn test_qualify_path_1() { | 350 | fn test_qualify_path_1() { |
329 | check_assist( | 351 | check_assist( |
330 | add_missing_impl_members, | 352 | add_missing_impl_members, |
331 | " | 353 | r#" |
332 | mod foo { | 354 | mod foo { |
333 | pub struct Bar; | 355 | pub struct Bar; |
334 | trait Foo { fn foo(&self, bar: Bar); } | 356 | trait Foo { fn foo(&self, bar: Bar); } |
335 | } | 357 | } |
336 | struct S; | 358 | struct S; |
337 | impl foo::Foo for S { <|> }", | 359 | impl foo::Foo for S { <|> }"#, |
338 | " | 360 | r#" |
339 | mod foo { | 361 | mod foo { |
340 | pub struct Bar; | 362 | pub struct Bar; |
341 | trait Foo { fn foo(&self, bar: Bar); } | 363 | trait Foo { fn foo(&self, bar: Bar); } |
342 | } | 364 | } |
343 | struct S; | 365 | struct S; |
344 | impl foo::Foo for S { | 366 | impl foo::Foo for S { |
345 | <|>fn foo(&self, bar: foo::Bar) { todo!() } | 367 | <|>fn foo(&self, bar: foo::Bar) { |
346 | }", | 368 | todo!() |
369 | } | ||
370 | }"#, | ||
347 | ); | 371 | ); |
348 | } | 372 | } |
349 | 373 | ||
@@ -351,22 +375,24 @@ impl foo::Foo for S { | |||
351 | fn test_qualify_path_generic() { | 375 | fn test_qualify_path_generic() { |
352 | check_assist( | 376 | check_assist( |
353 | add_missing_impl_members, | 377 | add_missing_impl_members, |
354 | " | 378 | r#" |
355 | mod foo { | 379 | mod foo { |
356 | pub struct Bar<T>; | 380 | pub struct Bar<T>; |
357 | trait Foo { fn foo(&self, bar: Bar<u32>); } | 381 | trait Foo { fn foo(&self, bar: Bar<u32>); } |
358 | } | 382 | } |
359 | struct S; | 383 | struct S; |
360 | impl foo::Foo for S { <|> }", | 384 | impl foo::Foo for S { <|> }"#, |
361 | " | 385 | r#" |
362 | mod foo { | 386 | mod foo { |
363 | pub struct Bar<T>; | 387 | pub struct Bar<T>; |
364 | trait Foo { fn foo(&self, bar: Bar<u32>); } | 388 | trait Foo { fn foo(&self, bar: Bar<u32>); } |
365 | } | 389 | } |
366 | struct S; | 390 | struct S; |
367 | impl foo::Foo for S { | 391 | impl foo::Foo for S { |
368 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } | 392 | <|>fn foo(&self, bar: foo::Bar<u32>) { |
369 | }", | 393 | todo!() |
394 | } | ||
395 | }"#, | ||
370 | ); | 396 | ); |
371 | } | 397 | } |
372 | 398 | ||
@@ -374,22 +400,24 @@ impl foo::Foo for S { | |||
374 | fn test_qualify_path_and_substitute_param() { | 400 | fn test_qualify_path_and_substitute_param() { |
375 | check_assist( | 401 | check_assist( |
376 | add_missing_impl_members, | 402 | add_missing_impl_members, |
377 | " | 403 | r#" |
378 | mod foo { | 404 | mod foo { |
379 | pub struct Bar<T>; | 405 | pub struct Bar<T>; |
380 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | 406 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } |
381 | } | 407 | } |
382 | struct S; | 408 | struct S; |
383 | impl foo::Foo<u32> for S { <|> }", | 409 | impl foo::Foo<u32> for S { <|> }"#, |
384 | " | 410 | r#" |
385 | mod foo { | 411 | mod foo { |
386 | pub struct Bar<T>; | 412 | pub struct Bar<T>; |
387 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | 413 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } |
388 | } | 414 | } |
389 | struct S; | 415 | struct S; |
390 | impl foo::Foo<u32> for S { | 416 | impl foo::Foo<u32> for S { |
391 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } | 417 | <|>fn foo(&self, bar: foo::Bar<u32>) { |
392 | }", | 418 | todo!() |
419 | } | ||
420 | }"#, | ||
393 | ); | 421 | ); |
394 | } | 422 | } |
395 | 423 | ||
@@ -398,15 +426,15 @@ impl foo::Foo<u32> for S { | |||
398 | // when substituting params, the substituted param should not be qualified! | 426 | // when substituting params, the substituted param should not be qualified! |
399 | check_assist( | 427 | check_assist( |
400 | add_missing_impl_members, | 428 | add_missing_impl_members, |
401 | " | 429 | r#" |
402 | mod foo { | 430 | mod foo { |
403 | trait Foo<T> { fn foo(&self, bar: T); } | 431 | trait Foo<T> { fn foo(&self, bar: T); } |
404 | pub struct Param; | 432 | pub struct Param; |
405 | } | 433 | } |
406 | struct Param; | 434 | struct Param; |
407 | struct S; | 435 | struct S; |
408 | impl foo::Foo<Param> for S { <|> }", | 436 | impl foo::Foo<Param> for S { <|> }"#, |
409 | " | 437 | r#" |
410 | mod foo { | 438 | mod foo { |
411 | trait Foo<T> { fn foo(&self, bar: T); } | 439 | trait Foo<T> { fn foo(&self, bar: T); } |
412 | pub struct Param; | 440 | pub struct Param; |
@@ -414,8 +442,10 @@ mod foo { | |||
414 | struct Param; | 442 | struct Param; |
415 | struct S; | 443 | struct S; |
416 | impl foo::Foo<Param> for S { | 444 | impl foo::Foo<Param> for S { |
417 | <|>fn foo(&self, bar: Param) { todo!() } | 445 | <|>fn foo(&self, bar: Param) { |
418 | }", | 446 | todo!() |
447 | } | ||
448 | }"#, | ||
419 | ); | 449 | ); |
420 | } | 450 | } |
421 | 451 | ||
@@ -423,15 +453,15 @@ impl foo::Foo<Param> for S { | |||
423 | fn test_qualify_path_associated_item() { | 453 | fn test_qualify_path_associated_item() { |
424 | check_assist( | 454 | check_assist( |
425 | add_missing_impl_members, | 455 | add_missing_impl_members, |
426 | " | 456 | r#" |
427 | mod foo { | 457 | mod foo { |
428 | pub struct Bar<T>; | 458 | pub struct Bar<T>; |
429 | impl Bar<T> { type Assoc = u32; } | 459 | impl Bar<T> { type Assoc = u32; } |
430 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } | 460 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } |
431 | } | 461 | } |
432 | struct S; | 462 | struct S; |
433 | impl foo::Foo for S { <|> }", | 463 | impl foo::Foo for S { <|> }"#, |
434 | " | 464 | r#" |
435 | mod foo { | 465 | mod foo { |
436 | pub struct Bar<T>; | 466 | pub struct Bar<T>; |
437 | impl Bar<T> { type Assoc = u32; } | 467 | impl Bar<T> { type Assoc = u32; } |
@@ -439,8 +469,10 @@ mod foo { | |||
439 | } | 469 | } |
440 | struct S; | 470 | struct S; |
441 | impl foo::Foo for S { | 471 | impl foo::Foo for S { |
442 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() } | 472 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { |
443 | }", | 473 | todo!() |
474 | } | ||
475 | }"#, | ||
444 | ); | 476 | ); |
445 | } | 477 | } |
446 | 478 | ||
@@ -448,15 +480,15 @@ impl foo::Foo for S { | |||
448 | fn test_qualify_path_nested() { | 480 | fn test_qualify_path_nested() { |
449 | check_assist( | 481 | check_assist( |
450 | add_missing_impl_members, | 482 | add_missing_impl_members, |
451 | " | 483 | r#" |
452 | mod foo { | 484 | mod foo { |
453 | pub struct Bar<T>; | 485 | pub struct Bar<T>; |
454 | pub struct Baz; | 486 | pub struct Baz; |
455 | trait Foo { fn foo(&self, bar: Bar<Baz>); } | 487 | trait Foo { fn foo(&self, bar: Bar<Baz>); } |
456 | } | 488 | } |
457 | struct S; | 489 | struct S; |
458 | impl foo::Foo for S { <|> }", | 490 | impl foo::Foo for S { <|> }"#, |
459 | " | 491 | r#" |
460 | mod foo { | 492 | mod foo { |
461 | pub struct Bar<T>; | 493 | pub struct Bar<T>; |
462 | pub struct Baz; | 494 | pub struct Baz; |
@@ -464,8 +496,10 @@ mod foo { | |||
464 | } | 496 | } |
465 | struct S; | 497 | struct S; |
466 | impl foo::Foo for S { | 498 | impl foo::Foo for S { |
467 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() } | 499 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { |
468 | }", | 500 | todo!() |
501 | } | ||
502 | }"#, | ||
469 | ); | 503 | ); |
470 | } | 504 | } |
471 | 505 | ||
@@ -473,22 +507,24 @@ impl foo::Foo for S { | |||
473 | fn test_qualify_path_fn_trait_notation() { | 507 | fn test_qualify_path_fn_trait_notation() { |
474 | check_assist( | 508 | check_assist( |
475 | add_missing_impl_members, | 509 | add_missing_impl_members, |
476 | " | 510 | r#" |
477 | mod foo { | 511 | mod foo { |
478 | pub trait Fn<Args> { type Output; } | 512 | pub trait Fn<Args> { type Output; } |
479 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | 513 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } |
480 | } | 514 | } |
481 | struct S; | 515 | struct S; |
482 | impl foo::Foo for S { <|> }", | 516 | impl foo::Foo for S { <|> }"#, |
483 | " | 517 | r#" |
484 | mod foo { | 518 | mod foo { |
485 | pub trait Fn<Args> { type Output; } | 519 | pub trait Fn<Args> { type Output; } |
486 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | 520 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } |
487 | } | 521 | } |
488 | struct S; | 522 | struct S; |
489 | impl foo::Foo for S { | 523 | impl foo::Foo for S { |
490 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() } | 524 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { |
491 | }", | 525 | todo!() |
526 | } | ||
527 | }"#, | ||
492 | ); | 528 | ); |
493 | } | 529 | } |
494 | 530 | ||
@@ -496,10 +532,10 @@ impl foo::Foo for S { | |||
496 | fn test_empty_trait() { | 532 | fn test_empty_trait() { |
497 | check_assist_not_applicable( | 533 | check_assist_not_applicable( |
498 | add_missing_impl_members, | 534 | add_missing_impl_members, |
499 | " | 535 | r#" |
500 | trait Foo; | 536 | trait Foo; |
501 | struct S; | 537 | struct S; |
502 | impl Foo for S { <|> }", | 538 | impl Foo for S { <|> }"#, |
503 | ) | 539 | ) |
504 | } | 540 | } |
505 | 541 | ||
@@ -507,13 +543,13 @@ impl Foo for S { <|> }", | |||
507 | fn test_ignore_unnamed_trait_members_and_default_methods() { | 543 | fn test_ignore_unnamed_trait_members_and_default_methods() { |
508 | check_assist_not_applicable( | 544 | check_assist_not_applicable( |
509 | add_missing_impl_members, | 545 | add_missing_impl_members, |
510 | " | 546 | r#" |
511 | trait Foo { | 547 | trait Foo { |
512 | fn (arg: u32); | 548 | fn (arg: u32); |
513 | fn valid(some: u32) -> bool { false } | 549 | fn valid(some: u32) -> bool { false } |
514 | } | 550 | } |
515 | struct S; | 551 | struct S; |
516 | impl Foo for S { <|> }", | 552 | impl Foo for S { <|> }"#, |
517 | ) | 553 | ) |
518 | } | 554 | } |
519 | 555 | ||
@@ -544,7 +580,9 @@ trait Foo { | |||
544 | struct S; | 580 | struct S; |
545 | impl Foo for S { | 581 | impl Foo for S { |
546 | <|>type Output; | 582 | <|>type Output; |
547 | fn foo(&self) { todo!() } | 583 | fn foo(&self) { |
584 | todo!() | ||
585 | } | ||
548 | }"#, | 586 | }"#, |
549 | ) | 587 | ) |
550 | } | 588 | } |
@@ -553,7 +591,7 @@ impl Foo for S { | |||
553 | fn test_default_methods() { | 591 | fn test_default_methods() { |
554 | check_assist( | 592 | check_assist( |
555 | add_missing_default_members, | 593 | add_missing_default_members, |
556 | " | 594 | r#" |
557 | trait Foo { | 595 | trait Foo { |
558 | type Output; | 596 | type Output; |
559 | 597 | ||
@@ -563,8 +601,8 @@ trait Foo { | |||
563 | fn foo(some: u32) -> bool; | 601 | fn foo(some: u32) -> bool; |
564 | } | 602 | } |
565 | struct S; | 603 | struct S; |
566 | impl Foo for S { <|> }", | 604 | impl Foo for S { <|> }"#, |
567 | " | 605 | r#" |
568 | trait Foo { | 606 | trait Foo { |
569 | type Output; | 607 | type Output; |
570 | 608 | ||
@@ -576,7 +614,7 @@ trait Foo { | |||
576 | struct S; | 614 | struct S; |
577 | impl Foo for S { | 615 | impl Foo for S { |
578 | <|>fn valid(some: u32) -> bool { false } | 616 | <|>fn valid(some: u32) -> bool { false } |
579 | }", | 617 | }"#, |
580 | ) | 618 | ) |
581 | } | 619 | } |
582 | } | 620 | } |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 99682e023..db6c4d2fa 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -45,15 +45,12 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
45 | return None; | 45 | return None; |
46 | } | 46 | } |
47 | 47 | ||
48 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; | ||
48 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); | 49 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); |
49 | for import in proposed_imports { | 50 | for import in proposed_imports { |
50 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { | 51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { |
51 | edit.target(auto_import_assets.syntax_under_caret.text_range()); | 52 | edit.target(range); |
52 | insert_use_statement( | 53 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); |
53 | &auto_import_assets.syntax_under_caret, | ||
54 | &import, | ||
55 | edit.text_edit_builder(), | ||
56 | ); | ||
57 | }); | 54 | }); |
58 | } | 55 | } |
59 | group.finish() | 56 | group.finish() |
@@ -68,10 +65,10 @@ struct AutoImportAssets { | |||
68 | 65 | ||
69 | impl AutoImportAssets { | 66 | impl AutoImportAssets { |
70 | fn new(ctx: &AssistCtx) -> Option<Self> { | 67 | fn new(ctx: &AssistCtx) -> Option<Self> { |
71 | if let Some(path_under_caret) = ctx.find_node_at_offset::<ast::Path>() { | 68 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { |
72 | Self::for_regular_path(path_under_caret, &ctx) | 69 | Self::for_regular_path(path_under_caret, &ctx) |
73 | } else { | 70 | } else { |
74 | Self::for_method_call(ctx.find_node_at_offset()?, &ctx) | 71 | Self::for_method_call(ctx.find_node_at_offset_with_descend()?, &ctx) |
75 | } | 72 | } |
76 | } | 73 | } |
77 | 74 | ||
@@ -306,6 +303,35 @@ mod tests { | |||
306 | } | 303 | } |
307 | 304 | ||
308 | #[test] | 305 | #[test] |
306 | fn applicable_when_found_an_import_in_macros() { | ||
307 | check_assist( | ||
308 | auto_import, | ||
309 | r" | ||
310 | macro_rules! foo { | ||
311 | ($i:ident) => { fn foo(a: $i) {} } | ||
312 | } | ||
313 | foo!(Pub<|>Struct); | ||
314 | |||
315 | pub mod PubMod { | ||
316 | pub struct PubStruct; | ||
317 | } | ||
318 | ", | ||
319 | r" | ||
320 | use PubMod::PubStruct; | ||
321 | |||
322 | macro_rules! foo { | ||
323 | ($i:ident) => { fn foo(a: $i) {} } | ||
324 | } | ||
325 | foo!(Pub<|>Struct); | ||
326 | |||
327 | pub mod PubMod { | ||
328 | pub struct PubStruct; | ||
329 | } | ||
330 | ", | ||
331 | ); | ||
332 | } | ||
333 | |||
334 | #[test] | ||
309 | fn auto_imports_are_merged() { | 335 | fn auto_imports_are_merged() { |
310 | check_assist( | 336 | check_assist( |
311 | auto_import, | 337 | auto_import, |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index ea6c56f8c..eede2fe91 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -2,7 +2,7 @@ use std::{iter::once, ops::RangeInclusive}; | |||
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::replace_children, | 4 | algo::replace_children, |
5 | ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat}, | 5 | ast::{self, edit::IndentLevel, make}, |
6 | AstNode, | 6 | AstNode, |
7 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, | 7 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, |
8 | SyntaxNode, | 8 | SyntaxNode, |
@@ -47,7 +47,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
47 | // Check if there is an IfLet that we can handle. | 47 | // Check if there is an IfLet that we can handle. |
48 | let if_let_pat = match cond.pat() { | 48 | let if_let_pat = match cond.pat() { |
49 | None => None, // No IfLet, supported. | 49 | None => None, // No IfLet, supported. |
50 | Some(TupleStructPat(pat)) if pat.args().count() == 1 => { | 50 | Some(ast::Pat::TupleStructPat(pat)) if pat.args().count() == 1 => { |
51 | let path = pat.path()?; | 51 | let path = pat.path()?; |
52 | match path.qualifier() { | 52 | match path.qualifier() { |
53 | None => { | 53 | None => { |
@@ -61,9 +61,9 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | let cond_expr = cond.expr()?; | 63 | let cond_expr = cond.expr()?; |
64 | let then_block = if_expr.then_branch()?.block()?; | 64 | let then_block = if_expr.then_branch()?; |
65 | 65 | ||
66 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; | 66 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; |
67 | 67 | ||
68 | if parent_block.expr()? != if_expr.clone().into() { | 68 | if parent_block.expr()? != if_expr.clone().into() { |
69 | return None; | 69 | return None; |
@@ -80,7 +80,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
80 | return None; | 80 | return None; |
81 | } | 81 | } |
82 | 82 | ||
83 | let parent_container = parent_block.syntax().parent()?.parent()?; | 83 | let parent_container = parent_block.syntax().parent()?; |
84 | 84 | ||
85 | let early_expression: ast::Expr = match parent_container.kind() { | 85 | let early_expression: ast::Expr = match parent_container.kind() { |
86 | WHILE_EXPR | LOOP_EXPR => make::expr_continue(), | 86 | WHILE_EXPR | LOOP_EXPR => make::expr_continue(), |
@@ -144,13 +144,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
144 | } | 144 | } |
145 | }; | 145 | }; |
146 | edit.target(if_expr.syntax().text_range()); | 146 | edit.target(if_expr.syntax().text_range()); |
147 | edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); | 147 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); |
148 | edit.set_cursor(cursor_position); | 148 | edit.set_cursor(cursor_position); |
149 | 149 | ||
150 | fn replace( | 150 | fn replace( |
151 | new_expr: &SyntaxNode, | 151 | new_expr: &SyntaxNode, |
152 | then_block: &Block, | 152 | then_block: &ast::BlockExpr, |
153 | parent_block: &Block, | 153 | parent_block: &ast::BlockExpr, |
154 | if_expr: &ast::IfExpr, | 154 | if_expr: &ast::IfExpr, |
155 | ) -> SyntaxNode { | 155 | ) -> SyntaxNode { |
156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | 156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index f5702f6e0..60ec536a7 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -89,6 +89,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
89 | | (ast::Expr::ParenExpr(_), _) | 89 | | (ast::Expr::ParenExpr(_), _) |
90 | | (ast::Expr::PathExpr(_), _) | 90 | | (ast::Expr::PathExpr(_), _) |
91 | | (ast::Expr::BlockExpr(_), _) | 91 | | (ast::Expr::BlockExpr(_), _) |
92 | | (ast::Expr::EffectExpr(_), _) | ||
92 | | (_, ast::Expr::CallExpr(_)) | 93 | | (_, ast::Expr::CallExpr(_)) |
93 | | (_, ast::Expr::TupleExpr(_)) | 94 | | (_, ast::Expr::TupleExpr(_)) |
94 | | (_, ast::Expr::ArrayExpr(_)) | 95 | | (_, ast::Expr::ArrayExpr(_)) |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index eda9ac296..39c656305 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -111,7 +111,7 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> { | |||
111 | /// expression like a lambda or match arm. | 111 | /// expression like a lambda or match arm. |
112 | fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { | 112 | fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { |
113 | expr.syntax().ancestors().find_map(|node| { | 113 | expr.syntax().ancestors().find_map(|node| { |
114 | if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) { | 114 | if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { |
115 | if expr.syntax() == &node { | 115 | if expr.syntax() == &node { |
116 | tested_by!(test_introduce_var_last_expr); | 116 | tested_by!(test_introduce_var_last_expr); |
117 | return Some((node, false)); | 117 | return Some((node, false)); |
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index d5ccdd91c..b084dd9ee 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -113,9 +113,9 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | |||
113 | "Move condition to match guard", | 113 | "Move condition to match guard", |
114 | |edit| { | 114 | |edit| { |
115 | edit.target(if_expr.syntax().text_range()); | 115 | edit.target(if_expr.syntax().text_range()); |
116 | let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none(); | 116 | let then_only_expr = then_block.statements().next().is_none(); |
117 | 117 | ||
118 | match &then_block.block().and_then(|it| it.expr()) { | 118 | match &then_block.expr() { |
119 | Some(then_expr) if then_only_expr => { | 119 | Some(then_expr) if then_only_expr => { |
120 | edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) | 120 | edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) |
121 | } | 121 | } |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index 2f02df303..ff2463c77 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -27,7 +27,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | 29 | ||
30 | let hir_path = hir::Path::from_ast(path.clone())?; | 30 | let hir_path = ctx.sema.lower_path(&path)?; |
31 | let segments = collect_hir_path_segments(&hir_path)?; | 31 | let segments = collect_hir_path_segments(&hir_path)?; |
32 | if segments.len() < 2 { | 32 | if segments.len() < 2 { |
33 | return None; | 33 | return None; |
@@ -38,7 +38,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
38 | "Replace qualified path with use", | 38 | "Replace qualified path with use", |
39 | |edit| { | 39 | |edit| { |
40 | let path_to_import = hir_path.mod_path().clone(); | 40 | let path_to_import = hir_path.mod_path().clone(); |
41 | insert_use_statement(path.syntax(), &path_to_import, edit.text_edit_builder()); | 41 | insert_use_statement(path.syntax(), &path_to_import, edit); |
42 | 42 | ||
43 | if let Some(last) = path.segment() { | 43 | if let Some(last) = path.segment() { |
44 | // Here we are assuming the assist will provide a correct use statement | 44 | // Here we are assuming the assist will provide a correct use statement |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs new file mode 100644 index 000000000..58649c47e --- /dev/null +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -0,0 +1,348 @@ | |||
1 | use crate::{Assist, AssistCtx, AssistId}; | ||
2 | |||
3 | use ast::{BlockExpr, Expr, ForExpr, IfExpr, LoopBodyOwner, LoopExpr, WhileExpr}; | ||
4 | use ra_fmt::unwrap_trivial_block; | ||
5 | use ra_syntax::{ast, AstNode, TextRange, T}; | ||
6 | |||
7 | // Assist: unwrap_block | ||
8 | // | ||
9 | // This assist removes if...else, for, while and loop control statements to just keep the body. | ||
10 | // | ||
11 | // ``` | ||
12 | // fn foo() { | ||
13 | // if true {<|> | ||
14 | // println!("foo"); | ||
15 | // } | ||
16 | // } | ||
17 | // ``` | ||
18 | // -> | ||
19 | // ``` | ||
20 | // fn foo() { | ||
21 | // println!("foo"); | ||
22 | // } | ||
23 | // ``` | ||
24 | pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | ||
25 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | ||
26 | |||
27 | let res = if let Some(if_expr) = l_curly_token.ancestors().find_map(IfExpr::cast) { | ||
28 | // if expression | ||
29 | let expr_to_unwrap = if_expr.blocks().find_map(|expr| extract_expr(ctx.frange.range, expr)); | ||
30 | let expr_to_unwrap = expr_to_unwrap?; | ||
31 | // Find if we are in a else if block | ||
32 | let ancestor = if_expr.syntax().ancestors().skip(1).find_map(ast::IfExpr::cast); | ||
33 | |||
34 | if let Some(ancestor) = ancestor { | ||
35 | Some((ast::Expr::IfExpr(ancestor), expr_to_unwrap)) | ||
36 | } else { | ||
37 | Some((ast::Expr::IfExpr(if_expr), expr_to_unwrap)) | ||
38 | } | ||
39 | } else if let Some(for_expr) = l_curly_token.ancestors().find_map(ForExpr::cast) { | ||
40 | // for expression | ||
41 | let block_expr = for_expr.loop_body()?; | ||
42 | extract_expr(ctx.frange.range, block_expr) | ||
43 | .map(|expr_to_unwrap| (ast::Expr::ForExpr(for_expr), expr_to_unwrap)) | ||
44 | } else if let Some(while_expr) = l_curly_token.ancestors().find_map(WhileExpr::cast) { | ||
45 | // while expression | ||
46 | let block_expr = while_expr.loop_body()?; | ||
47 | extract_expr(ctx.frange.range, block_expr) | ||
48 | .map(|expr_to_unwrap| (ast::Expr::WhileExpr(while_expr), expr_to_unwrap)) | ||
49 | } else if let Some(loop_expr) = l_curly_token.ancestors().find_map(LoopExpr::cast) { | ||
50 | // loop expression | ||
51 | let block_expr = loop_expr.loop_body()?; | ||
52 | extract_expr(ctx.frange.range, block_expr) | ||
53 | .map(|expr_to_unwrap| (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap)) | ||
54 | } else { | ||
55 | None | ||
56 | }; | ||
57 | |||
58 | let (expr, expr_to_unwrap) = res?; | ||
59 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| { | ||
60 | edit.set_cursor(expr.syntax().text_range().start()); | ||
61 | edit.target(expr_to_unwrap.syntax().text_range()); | ||
62 | |||
63 | let pat_start: &[_] = &[' ', '{', '\n']; | ||
64 | let expr_to_unwrap = expr_to_unwrap.to_string(); | ||
65 | let expr_string = expr_to_unwrap.trim_start_matches(pat_start); | ||
66 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); | ||
67 | expr_string_lines.pop(); // Delete last line | ||
68 | |||
69 | let expr_string = expr_string_lines | ||
70 | .into_iter() | ||
71 | .map(|line| line.replacen(" ", "", 1)) // Delete indentation | ||
72 | .collect::<Vec<String>>() | ||
73 | .join("\n"); | ||
74 | |||
75 | edit.replace(expr.syntax().text_range(), expr_string); | ||
76 | }) | ||
77 | } | ||
78 | |||
79 | fn extract_expr(cursor_range: TextRange, block: BlockExpr) -> Option<Expr> { | ||
80 | let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range); | ||
81 | |||
82 | if cursor_in_range { | ||
83 | Some(unwrap_trivial_block(block)) | ||
84 | } else { | ||
85 | None | ||
86 | } | ||
87 | } | ||
88 | |||
89 | #[cfg(test)] | ||
90 | mod tests { | ||
91 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
92 | |||
93 | use super::*; | ||
94 | |||
95 | #[test] | ||
96 | fn simple_if() { | ||
97 | check_assist( | ||
98 | unwrap_block, | ||
99 | r#" | ||
100 | fn main() { | ||
101 | bar(); | ||
102 | if true {<|> | ||
103 | foo(); | ||
104 | |||
105 | //comment | ||
106 | bar(); | ||
107 | } else { | ||
108 | println!("bar"); | ||
109 | } | ||
110 | } | ||
111 | "#, | ||
112 | r#" | ||
113 | fn main() { | ||
114 | bar(); | ||
115 | <|>foo(); | ||
116 | |||
117 | //comment | ||
118 | bar(); | ||
119 | } | ||
120 | "#, | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn simple_if_else() { | ||
126 | check_assist( | ||
127 | unwrap_block, | ||
128 | r#" | ||
129 | fn main() { | ||
130 | bar(); | ||
131 | if true { | ||
132 | foo(); | ||
133 | |||
134 | //comment | ||
135 | bar(); | ||
136 | } else {<|> | ||
137 | println!("bar"); | ||
138 | } | ||
139 | } | ||
140 | "#, | ||
141 | r#" | ||
142 | fn main() { | ||
143 | bar(); | ||
144 | <|>println!("bar"); | ||
145 | } | ||
146 | "#, | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn simple_if_else_if() { | ||
152 | check_assist( | ||
153 | unwrap_block, | ||
154 | r#" | ||
155 | fn main() { | ||
156 | //bar(); | ||
157 | if true { | ||
158 | println!("true"); | ||
159 | |||
160 | //comment | ||
161 | //bar(); | ||
162 | } else if false {<|> | ||
163 | println!("bar"); | ||
164 | } else { | ||
165 | println!("foo"); | ||
166 | } | ||
167 | } | ||
168 | "#, | ||
169 | r#" | ||
170 | fn main() { | ||
171 | //bar(); | ||
172 | <|>println!("bar"); | ||
173 | } | ||
174 | "#, | ||
175 | ); | ||
176 | } | ||
177 | |||
178 | #[test] | ||
179 | fn simple_if_bad_cursor_position() { | ||
180 | check_assist_not_applicable( | ||
181 | unwrap_block, | ||
182 | r#" | ||
183 | fn main() { | ||
184 | bar();<|> | ||
185 | if true { | ||
186 | foo(); | ||
187 | |||
188 | //comment | ||
189 | bar(); | ||
190 | } else { | ||
191 | println!("bar"); | ||
192 | } | ||
193 | } | ||
194 | "#, | ||
195 | ); | ||
196 | } | ||
197 | |||
198 | #[test] | ||
199 | fn simple_for() { | ||
200 | check_assist( | ||
201 | unwrap_block, | ||
202 | r#" | ||
203 | fn main() { | ||
204 | for i in 0..5 {<|> | ||
205 | if true { | ||
206 | foo(); | ||
207 | |||
208 | //comment | ||
209 | bar(); | ||
210 | } else { | ||
211 | println!("bar"); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | fn main() { | ||
218 | <|>if true { | ||
219 | foo(); | ||
220 | |||
221 | //comment | ||
222 | bar(); | ||
223 | } else { | ||
224 | println!("bar"); | ||
225 | } | ||
226 | } | ||
227 | "#, | ||
228 | ); | ||
229 | } | ||
230 | |||
231 | #[test] | ||
232 | fn simple_if_in_for() { | ||
233 | check_assist( | ||
234 | unwrap_block, | ||
235 | r#" | ||
236 | fn main() { | ||
237 | for i in 0..5 { | ||
238 | if true {<|> | ||
239 | foo(); | ||
240 | |||
241 | //comment | ||
242 | bar(); | ||
243 | } else { | ||
244 | println!("bar"); | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | "#, | ||
249 | r#" | ||
250 | fn main() { | ||
251 | for i in 0..5 { | ||
252 | <|>foo(); | ||
253 | |||
254 | //comment | ||
255 | bar(); | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn simple_loop() { | ||
264 | check_assist( | ||
265 | unwrap_block, | ||
266 | r#" | ||
267 | fn main() { | ||
268 | loop {<|> | ||
269 | if true { | ||
270 | foo(); | ||
271 | |||
272 | //comment | ||
273 | bar(); | ||
274 | } else { | ||
275 | println!("bar"); | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | "#, | ||
280 | r#" | ||
281 | fn main() { | ||
282 | <|>if true { | ||
283 | foo(); | ||
284 | |||
285 | //comment | ||
286 | bar(); | ||
287 | } else { | ||
288 | println!("bar"); | ||
289 | } | ||
290 | } | ||
291 | "#, | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn simple_while() { | ||
297 | check_assist( | ||
298 | unwrap_block, | ||
299 | r#" | ||
300 | fn main() { | ||
301 | while true {<|> | ||
302 | if true { | ||
303 | foo(); | ||
304 | |||
305 | //comment | ||
306 | bar(); | ||
307 | } else { | ||
308 | println!("bar"); | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | "#, | ||
313 | r#" | ||
314 | fn main() { | ||
315 | <|>if true { | ||
316 | foo(); | ||
317 | |||
318 | //comment | ||
319 | bar(); | ||
320 | } else { | ||
321 | println!("bar"); | ||
322 | } | ||
323 | } | ||
324 | "#, | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn simple_if_in_while_bad_cursor_position() { | ||
330 | check_assist_not_applicable( | ||
331 | unwrap_block, | ||
332 | r#" | ||
333 | fn main() { | ||
334 | while true { | ||
335 | if true { | ||
336 | foo();<|> | ||
337 | |||
338 | //comment | ||
339 | bar(); | ||
340 | } else { | ||
341 | println!("bar"); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | "#, | ||
346 | ); | ||
347 | } | ||
348 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 64bd87afb..c5df86600 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -143,6 +143,7 @@ mod handlers { | |||
143 | mod split_import; | 143 | mod split_import; |
144 | mod add_from_impl_for_enum; | 144 | mod add_from_impl_for_enum; |
145 | mod reorder_fields; | 145 | mod reorder_fields; |
146 | mod unwrap_block; | ||
146 | 147 | ||
147 | pub(crate) fn all() -> &'static [AssistHandler] { | 148 | pub(crate) fn all() -> &'static [AssistHandler] { |
148 | &[ | 149 | &[ |
@@ -181,6 +182,7 @@ mod handlers { | |||
181 | replace_unwrap_with_match::replace_unwrap_with_match, | 182 | replace_unwrap_with_match::replace_unwrap_with_match, |
182 | split_import::split_import, | 183 | split_import::split_import, |
183 | add_from_impl_for_enum::add_from_impl_for_enum, | 184 | add_from_impl_for_enum::add_from_impl_for_enum, |
185 | unwrap_block::unwrap_block, | ||
184 | // These are manually sorted for better priorities | 186 | // These are manually sorted for better priorities |
185 | add_missing_impl_members::add_missing_impl_members, | 187 | add_missing_impl_members::add_missing_impl_members, |
186 | add_missing_impl_members::add_missing_default_members, | 188 | add_missing_impl_members::add_missing_default_members, |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index efd988697..6be704ce3 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | }; | 11 | }; |
12 | use rustc_hash::FxHashSet; | 12 | use rustc_hash::FxHashSet; |
13 | 13 | ||
14 | pub use insert_use::insert_use_statement; | 14 | pub(crate) use insert_use::insert_use_statement; |
15 | 15 | ||
16 | pub fn get_missing_impl_items( | 16 | pub fn get_missing_impl_items( |
17 | sema: &Semantics<RootDatabase>, | 17 | sema: &Semantics<RootDatabase>, |
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index c507e71e0..c1f447efe 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | // FIXME: rewrite according to the plan, outlined in | 2 | // FIXME: rewrite according to the plan, outlined in |
3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 | 3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 |
4 | 4 | ||
5 | use crate::assist_ctx::ActionBuilder; | ||
5 | use hir::{self, ModPath}; | 6 | use hir::{self, ModPath}; |
6 | use ra_syntax::{ | 7 | use ra_syntax::{ |
7 | ast::{self, NameOwner}, | 8 | ast::{self, NameOwner}, |
@@ -14,14 +15,14 @@ use ra_text_edit::TextEditBuilder; | |||
14 | /// Creates and inserts a use statement for the given path to import. | 15 | /// Creates and inserts a use statement for the given path to import. |
15 | /// The use statement is inserted in the scope most appropriate to the | 16 | /// The use statement is inserted in the scope most appropriate to the |
16 | /// the cursor position given, additionally merged with the existing use imports. | 17 | /// the cursor position given, additionally merged with the existing use imports. |
17 | pub fn insert_use_statement( | 18 | pub(crate) fn insert_use_statement( |
18 | // Ideally the position of the cursor, used to | 19 | // Ideally the position of the cursor, used to |
19 | position: &SyntaxNode, | 20 | position: &SyntaxNode, |
20 | path_to_import: &ModPath, | 21 | path_to_import: &ModPath, |
21 | edit: &mut TextEditBuilder, | 22 | edit: &mut ActionBuilder, |
22 | ) { | 23 | ) { |
23 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); | 24 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); |
24 | let container = position.ancestors().find_map(|n| { | 25 | let container = edit.ctx().sema.ancestors_with_macros(position.clone()).find_map(|n| { |
25 | if let Some(module) = ast::Module::cast(n.clone()) { | 26 | if let Some(module) = ast::Module::cast(n.clone()) { |
26 | return module.item_list().map(|it| it.syntax().clone()); | 27 | return module.item_list().map(|it| it.syntax().clone()); |
27 | } | 28 | } |
@@ -30,7 +31,7 @@ pub fn insert_use_statement( | |||
30 | 31 | ||
31 | if let Some(container) = container { | 32 | if let Some(container) = container { |
32 | let action = best_action_for_target(container, position.clone(), &target); | 33 | let action = best_action_for_target(container, position.clone(), &target); |
33 | make_assist(&action, &target, edit); | 34 | make_assist(&action, &target, edit.text_edit_builder()); |
34 | } | 35 | } |
35 | } | 36 | } |
36 | 37 | ||