482 lines
8.7 KiB
Rust
482 lines
8.7 KiB
Rust
|
use hir::{ItemInNs, ModuleDef};
|
||
|
use ide_db::{assists::{AssistId, AssistKind}, helpers::import_assets::item_for_path_search};
|
||
|
use syntax::{AstNode, ast};
|
||
|
|
||
|
use crate::{assist_context::{AssistContext, Assists}, handlers::qualify_path::QualifyCandidate};
|
||
|
|
||
|
// Assist: qualify_method_call
|
||
|
//
|
||
|
// If the name is resolvable, provides fully qualified path for it.
|
||
|
//
|
||
|
// ```
|
||
|
// struct Foo;
|
||
|
// impl Foo {
|
||
|
// fn foo(&self) {}
|
||
|
// }
|
||
|
// fn main() {
|
||
|
// let foo = Foo;
|
||
|
// foo.fo$0o();
|
||
|
// }
|
||
|
// ```
|
||
|
// ->
|
||
|
// ```
|
||
|
// struct Foo;
|
||
|
// impl Foo {
|
||
|
// fn foo(&self) {}
|
||
|
// }
|
||
|
// fn main() {
|
||
|
// let foo = Foo;
|
||
|
// Foo::foo(&foo);
|
||
|
// }
|
||
|
// ```
|
||
|
pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||
|
let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
|
||
|
let fn_name = &call.name_ref()?;
|
||
|
|
||
|
// let callExpr = path_expr.syntax();
|
||
|
let range = call.syntax().text_range();
|
||
|
let resolved_call = ctx.sema.resolve_method_call(&call)?;
|
||
|
|
||
|
let current_module = ctx.sema.scope(&call.syntax()).module()?;
|
||
|
let target_module_def = ModuleDef::from(resolved_call);
|
||
|
let item_in_ns = ItemInNs::from(target_module_def);
|
||
|
let receiver_path = current_module.find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
|
||
|
|
||
|
let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
|
||
|
|
||
|
acc.add(
|
||
|
AssistId("qualify_method_call", AssistKind::RefactorInline),
|
||
|
format!("Qualify call `{}`", fn_name),
|
||
|
range,
|
||
|
|builder| {
|
||
|
qualify_candidate.qualify(
|
||
|
|replace_with: String| builder.replace(range, replace_with),
|
||
|
&receiver_path,
|
||
|
item_in_ns
|
||
|
)
|
||
|
}
|
||
|
);
|
||
|
Some(())
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use crate::tests::{check_assist};
|
||
|
use super::*;
|
||
|
|
||
|
#[test]
|
||
|
fn struct_method() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(&self) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
foo.fo$0o()
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(&self) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
Foo::foo(&foo)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn struct_method_multi_params() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(&self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
foo.fo$0o(9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(&self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
Foo::foo(&foo, 9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn struct_method_consume() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
foo.fo$0o(9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
Foo::foo(foo, 9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn struct_method_exclusive() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(&mut self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
foo.fo$0o(9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo(&mut self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
Foo::foo(&mut foo, 9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn struct_method_cross_crate() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
//- /main.rs crate:main deps:dep
|
||
|
fn main() {
|
||
|
let foo = dep::test_mod::Foo {};
|
||
|
foo.fo$0o(9, 9u)
|
||
|
}
|
||
|
//- /dep.rs crate:dep
|
||
|
pub mod test_mod {
|
||
|
pub struct Foo;
|
||
|
impl Foo {
|
||
|
pub fn foo(&mut self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
fn main() {
|
||
|
let foo = dep::test_mod::Foo {};
|
||
|
dep::test_mod::Foo::foo(&mut foo, 9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn struct_method_generic() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo<T>(&self) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
foo.fo$0o::<()>()
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
struct Foo;
|
||
|
impl Foo {
|
||
|
fn foo<T>(&self) {}
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let foo = Foo {};
|
||
|
Foo::foo::<()>(&foo)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn trait_method() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(&self);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(&self) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
test_struct.test_meth$0od()
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(&self);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(&self) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
TestTrait::test_method(&test_struct)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn trait_method_multi_params() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(&self, p1: i32, p2: u32);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(&self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
test_struct.test_meth$0od(12, 32u)
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(&self, p1: i32, p2: u32);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(&self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
TestTrait::test_method(&test_struct, 12, 32u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn trait_method_consume() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(self, p1: i32, p2: u32);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
test_struct.test_meth$0od(12, 32u)
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(self, p1: i32, p2: u32);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
TestTrait::test_method(test_struct, 12, 32u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn trait_method_exclusive() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(&mut self, p1: i32, p2: u32);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(&mut self, p1: i32, p2: u32);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
test_struct.test_meth$0od(12, 32u)
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method(&mut self, p1: i32, p2: u32);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method(&mut self, p1: i32, p2: u32);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = test_mod::TestStruct {};
|
||
|
TestTrait::test_method(&mut test_struct, 12, 32u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn trait_method_cross_crate() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
//- /main.rs crate:main deps:dep
|
||
|
fn main() {
|
||
|
let foo = dep::test_mod::Foo {};
|
||
|
foo.fo$0o(9, 9u)
|
||
|
}
|
||
|
//- /dep.rs crate:dep
|
||
|
pub mod test_mod {
|
||
|
pub struct Foo;
|
||
|
impl Foo {
|
||
|
pub fn foo(&mut self, p1: i32, p2: u32) {}
|
||
|
}
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
fn main() {
|
||
|
let foo = dep::test_mod::Foo {};
|
||
|
dep::test_mod::Foo::foo(&mut foo, 9, 9u)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn trait_method_generic() {
|
||
|
check_assist(
|
||
|
qualify_method_call,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method<T>(&self);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method<T>(&self) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = TestStruct {};
|
||
|
test_struct.test_meth$0od::<()>()
|
||
|
}
|
||
|
"#,
|
||
|
r#"
|
||
|
mod test_mod {
|
||
|
pub trait TestTrait {
|
||
|
fn test_method<T>(&self);
|
||
|
}
|
||
|
pub struct TestStruct {}
|
||
|
impl TestTrait for TestStruct {
|
||
|
fn test_method<T>(&self) {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
use test_mod::*;
|
||
|
|
||
|
fn main() {
|
||
|
let test_struct = TestStruct {};
|
||
|
TestTrait::test_method::<()>(&test_struct)
|
||
|
}
|
||
|
"#,
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|