fix: auto import trait if needed

This commit is contained in:
Young-Flash 2023-10-18 22:40:07 +08:00
parent d6afb4fa23
commit a7f77d89a9
2 changed files with 46 additions and 1 deletions

View file

@ -1,3 +1,4 @@
use ide_db::imports::insert_use::ImportScope;
use syntax::{ use syntax::{
ast::{self, make, AstNode, HasArgList}, ast::{self, make, AstNode, HasArgList},
TextRange, TextRange,
@ -17,6 +18,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
// ``` // ```
// -> // ->
// ``` // ```
// use std::ops::Add;
//
// fn main() { // fn main() {
// 1.add(2); // 1.add(2);
// } // }
@ -38,7 +41,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>)
let first_arg = args_iter.next()?; let first_arg = args_iter.next()?;
let second_arg = args_iter.next(); let second_arg = args_iter.next();
_ = path.qualifier()?; let qualifier = path.qualifier()?;
let method_name = path.segment()?.name_ref()?; let method_name = path.segment()?.name_ref()?;
let res = ctx.sema.resolve_path(&path)?; let res = ctx.sema.resolve_path(&path)?;
@ -76,10 +79,44 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>)
edit.insert(close, ")"); edit.insert(close, ")");
} }
edit.replace(replace_comma, format!(".{method_name}(")); 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,
) {
// for `<i32 as std::ops::Add>`
let path_type =
qualifier.segment().unwrap().syntax().children().filter_map(ast::PathType::cast).last();
let import = match path_type {
Some(it) => it.path().unwrap(),
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 { fn needs_parens_as_receiver(expr: &ast::Expr) -> bool {
// Make `(expr).dummy()` // Make `(expr).dummy()`
let dummy_call = make::expr_method_call( let dummy_call = make::expr_method_call(
@ -127,6 +164,8 @@ fn f() { S.f(S); }"#,
//- minicore: add //- minicore: add
fn f() { <u32 as core::ops::Add>::$0add(2, 2); }"#, fn f() { <u32 as core::ops::Add>::$0add(2, 2); }"#,
r#" r#"
use core::ops::Add;
fn f() { 2.add(2); }"#, fn f() { 2.add(2); }"#,
); );
@ -136,6 +175,8 @@ fn f() { 2.add(2); }"#,
//- minicore: add //- minicore: add
fn f() { core::ops::Add::$0add(2, 2); }"#, fn f() { core::ops::Add::$0add(2, 2); }"#,
r#" r#"
use core::ops::Add;
fn f() { 2.add(2); }"#, fn f() { 2.add(2); }"#,
); );
@ -179,6 +220,8 @@ impl core::ops::Deref for S {
} }
fn f() { core::ops::Deref::$0deref(&S); }"#, fn f() { core::ops::Deref::$0deref(&S); }"#,
r#" r#"
use core::ops::Deref;
struct S; struct S;
impl core::ops::Deref for S { impl core::ops::Deref for S {
type Target = S; type Target = S;

View file

@ -2948,6 +2948,8 @@ fn main() {
mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } }
"#####, "#####,
r#####" r#####"
use std::ops::Add;
fn main() { fn main() {
1.add(2); 1.add(2);
} }