Auto merge of #15780 - Young-Flash:auto_import, r=lnicola
fix: import trait if needed for `unqualify_method_call` assist
before:
![before](https://github.com/rust-lang/rust-analyzer/assets/71162630/66fda67d-afcb-453f-91a9-7e85993c3d2a)
after:
![after](https://github.com/rust-lang/rust-analyzer/assets/71162630/72ffbda4-1615-4413-836e-480eb52e9728)
follow up https://github.com/rust-lang/rust-analyzer/pull/13825
diff --git a/crates/ide-assists/src/handlers/unqualify_method_call.rs b/crates/ide-assists/src/handlers/unqualify_method_call.rs
index e9d4e27..0bf1782 100644
--- a/crates/ide-assists/src/handlers/unqualify_method_call.rs
+++ b/crates/ide-assists/src/handlers/unqualify_method_call.rs
@@ -1,3 +1,4 @@
+use ide_db::imports::insert_use::ImportScope;
use syntax::{
ast::{self, make, AstNode, HasArgList},
TextRange,
@@ -17,6 +18,8 @@
// ```
// ->
// ```
+// use std::ops::Add;
+//
// fn main() {
// 1.add(2);
// }
@@ -38,7 +41,7 @@
let first_arg = args_iter.next()?;
let second_arg = args_iter.next();
- _ = path.qualifier()?;
+ let qualifier = path.qualifier()?;
let method_name = path.segment()?.name_ref()?;
let res = ctx.sema.resolve_path(&path)?;
@@ -76,10 +79,51 @@
edit.insert(close, ")");
}
edit.replace(replace_comma, format!(".{method_name}("));
+ add_import(qualifier, ctx, edit);
},
)
}
+fn add_import(
+ qualifier: ast::Path,
+ ctx: &AssistContext<'_>,
+ edit: &mut ide_db::source_change::SourceChangeBuilder,
+) {
+ if let Some(path_segment) = qualifier.segment() {
+ // for `<i32 as std::ops::Add>`
+ let path_type = path_segment.syntax().children().filter_map(ast::PathType::cast).last();
+ let import = match path_type {
+ Some(it) => {
+ if let Some(path) = it.path() {
+ path
+ } else {
+ return;
+ }
+ }
+ None => qualifier,
+ };
+
+ // in case for `<_>`
+ if import.coloncolon_token().is_none() {
+ return;
+ }
+
+ let scope = ide_db::imports::insert_use::ImportScope::find_insert_use_container(
+ import.syntax(),
+ &ctx.sema,
+ );
+
+ if let Some(scope) = scope {
+ let scope = match scope {
+ ImportScope::File(it) => ImportScope::File(edit.make_mut(it)),
+ ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)),
+ ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)),
+ };
+ ide_db::imports::insert_use::insert_use(&scope, import, &ctx.config.insert_use);
+ }
+ }
+}
+
fn needs_parens_as_receiver(expr: &ast::Expr) -> bool {
// Make `(expr).dummy()`
let dummy_call = make::expr_method_call(
@@ -127,6 +171,8 @@
//- minicore: add
fn f() { <u32 as core::ops::Add>::$0add(2, 2); }"#,
r#"
+use core::ops::Add;
+
fn f() { 2.add(2); }"#,
);
@@ -136,6 +182,8 @@
//- minicore: add
fn f() { core::ops::Add::$0add(2, 2); }"#,
r#"
+use core::ops::Add;
+
fn f() { 2.add(2); }"#,
);
@@ -179,6 +227,8 @@
}
fn f() { core::ops::Deref::$0deref(&S); }"#,
r#"
+use core::ops::Deref;
+
struct S;
impl core::ops::Deref for S {
type Target = S;
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index e9d0d37..8523632 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -2948,6 +2948,8 @@
mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } }
"#####,
r#####"
+use std::ops::Add;
+
fn main() {
1.add(2);
}