aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs30
-rw-r--r--crates/ra_assists/src/ast_transform.rs2
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs23
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs194
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs42
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs16
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs1
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs2
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs4
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs4
-rw-r--r--crates/ra_assists/src/handlers/unwrap_block.rs348
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/utils.rs2
-rw-r--r--crates/ra_assists/src/utils/insert_use.rs9
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)] 184pub(crate) struct ActionBuilder<'a, 'b> {
179pub(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
186impl ActionBuilder { 192impl<'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
182impl Trait<u32> for () { 182impl 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]
733fn doctest_unwrap_block() {
734 check(
735 "unwrap_block",
736 r#####"
737fn foo() {
738 if true {<|>
739 println!("foo");
740 }
741}
742"#####,
743 r#####"
744fn 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 @@
1use hir::HasSource; 1use hir::HasSource;
2use ra_syntax::{ 2use 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
166fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 172fn 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#"
185trait Foo { 193trait Foo {
186 type Output; 194 type Output;
187 195
@@ -197,8 +205,8 @@ struct S;
197impl Foo for S { 205impl Foo for S {
198 fn bar(&self) {} 206 fn bar(&self) {}
199<|> 207<|>
200}", 208}"#,
201 " 209 r#"
202trait Foo { 210trait 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#"
230trait Foo { 242trait 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;
238impl Foo for S { 250impl Foo for S {
239 fn bar(&self) {} 251 fn bar(&self) {}
240<|> 252<|>
241}", 253}"#,
242 " 254 r#"
243trait Foo { 255trait 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
251impl Foo for S { 263impl 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#"
264trait Foo { fn foo(&self); } 278trait Foo { fn foo(&self); }
265struct S; 279struct S;
266impl Foo for S { <|> }", 280impl Foo for S { <|> }"#,
267 " 281 r#"
268trait Foo { fn foo(&self); } 282trait Foo { fn foo(&self); }
269struct S; 283struct S;
270impl Foo for S { 284impl 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#"
281trait Foo<T> { fn foo(&self, t: T) -> &T; } 297trait Foo<T> { fn foo(&self, t: T) -> &T; }
282struct S; 298struct S;
283impl Foo<u32> for S { <|> }", 299impl Foo<u32> for S { <|> }"#,
284 " 300 r#"
285trait Foo<T> { fn foo(&self, t: T) -> &T; } 301trait Foo<T> { fn foo(&self, t: T) -> &T; }
286struct S; 302struct S;
287impl Foo<u32> for S { 303impl 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#"
298trait Foo<T> { fn foo(&self, t: T) -> &T; } 316trait Foo<T> { fn foo(&self, t: T) -> &T; }
299struct S; 317struct S;
300impl<U> Foo<U> for S { <|> }", 318impl<U> Foo<U> for S { <|> }"#,
301 " 319 r#"
302trait Foo<T> { fn foo(&self, t: T) -> &T; } 320trait Foo<T> { fn foo(&self, t: T) -> &T; }
303struct S; 321struct S;
304impl<U> Foo<U> for S { 322impl<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#"
315trait Foo { fn foo(&self); } 335trait Foo { fn foo(&self); }
316struct S; 336struct S;
317impl Foo for S {}<|>", 337impl Foo for S {}<|>"#,
318 " 338 r#"
319trait Foo { fn foo(&self); } 339trait Foo { fn foo(&self); }
320struct S; 340struct S;
321impl Foo for S { 341impl 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#"
332mod foo { 354mod 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}
336struct S; 358struct S;
337impl foo::Foo for S { <|> }", 359impl foo::Foo for S { <|> }"#,
338 " 360 r#"
339mod foo { 361mod 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}
343struct S; 365struct S;
344impl foo::Foo for S { 366impl 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#"
355mod foo { 379mod 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}
359struct S; 383struct S;
360impl foo::Foo for S { <|> }", 384impl foo::Foo for S { <|> }"#,
361 " 385 r#"
362mod foo { 386mod 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}
366struct S; 390struct S;
367impl foo::Foo for S { 391impl 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#"
378mod foo { 404mod 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}
382struct S; 408struct S;
383impl foo::Foo<u32> for S { <|> }", 409impl foo::Foo<u32> for S { <|> }"#,
384 " 410 r#"
385mod foo { 411mod 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}
389struct S; 415struct S;
390impl foo::Foo<u32> for S { 416impl 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#"
402mod foo { 430mod 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}
406struct Param; 434struct Param;
407struct S; 435struct S;
408impl foo::Foo<Param> for S { <|> }", 436impl foo::Foo<Param> for S { <|> }"#,
409 " 437 r#"
410mod foo { 438mod 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 {
414struct Param; 442struct Param;
415struct S; 443struct S;
416impl foo::Foo<Param> for S { 444impl 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#"
427mod foo { 457mod 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}
432struct S; 462struct S;
433impl foo::Foo for S { <|> }", 463impl foo::Foo for S { <|> }"#,
434 " 464 r#"
435mod foo { 465mod 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}
440struct S; 470struct S;
441impl foo::Foo for S { 471impl 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#"
452mod foo { 484mod 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}
457struct S; 489struct S;
458impl foo::Foo for S { <|> }", 490impl foo::Foo for S { <|> }"#,
459 " 491 r#"
460mod foo { 492mod 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}
465struct S; 497struct S;
466impl foo::Foo for S { 498impl 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#"
477mod foo { 511mod 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}
481struct S; 515struct S;
482impl foo::Foo for S { <|> }", 516impl foo::Foo for S { <|> }"#,
483 " 517 r#"
484mod foo { 518mod 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}
488struct S; 522struct S;
489impl foo::Foo for S { 523impl 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#"
500trait Foo; 536trait Foo;
501struct S; 537struct S;
502impl Foo for S { <|> }", 538impl 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#"
511trait Foo { 547trait 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}
515struct S; 551struct S;
516impl Foo for S { <|> }", 552impl Foo for S { <|> }"#,
517 ) 553 )
518 } 554 }
519 555
@@ -544,7 +580,9 @@ trait Foo {
544struct S; 580struct S;
545impl Foo for S { 581impl 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#"
557trait Foo { 595trait 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}
565struct S; 603struct S;
566impl Foo for S { <|> }", 604impl Foo for S { <|> }"#,
567 " 605 r#"
568trait Foo { 606trait Foo {
569 type Output; 607 type Output;
570 608
@@ -576,7 +614,7 @@ trait Foo {
576struct S; 614struct S;
577impl Foo for S { 615impl 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
69impl AutoImportAssets { 66impl 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
3use ra_syntax::{ 3use 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.
112fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { 112fn 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 @@
1use crate::{Assist, AssistCtx, AssistId};
2
3use ast::{BlockExpr, Expr, ForExpr, IfExpr, LoopBodyOwner, LoopExpr, WhileExpr};
4use ra_fmt::unwrap_trivial_block;
5use 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// ```
24pub(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
79fn 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)]
90mod 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};
12use rustc_hash::FxHashSet; 12use rustc_hash::FxHashSet;
13 13
14pub use insert_use::insert_use_statement; 14pub(crate) use insert_use::insert_use_statement;
15 15
16pub fn get_missing_impl_items( 16pub 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
5use crate::assist_ctx::ActionBuilder;
5use hir::{self, ModPath}; 6use hir::{self, ModPath};
6use ra_syntax::{ 7use 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.
17pub fn insert_use_statement( 18pub(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