mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 04:23:25 +00:00
Merge #10602
10602: Add qualify method call assist r=Veykril a=qepasa This adds `qualify_method_call` assist that allows to replace a method (or trait) call that resolves with its fully qualified path. For example, for stuct method: ```rust struct Foo; impl Foo { fn foo(&self) {} } ``` ``` let foo = Foo {}; foo.fo$0o(); ``` becomes ```rust let foo = Foo {}; Foo::foo(&foo); ``` for a trait method: ```rust struct Foo; trait FooTrait { fn foo(&self) {} } impl FooTrait for Foo { fn foo(&self) {} } ``` following call: ```rust let foo = Foo {}; foo.fo$0o(); ``` becomes: ```rust let foo = Foo {}; FooTrait::foo(&foo); ``` fixes #10453 Co-authored-by: Paweł Palenica <pawelpalenica11@gmail.com>
This commit is contained in:
commit
fe7c516084
5 changed files with 586 additions and 11 deletions
531
crates/ide_assists/src/handlers/qualify_method_call.rs
Normal file
531
crates/ide_assists/src/handlers/qualify_method_call.rs
Normal file
|
@ -0,0 +1,531 @@
|
||||||
|
use hir::{ItemInNs, ModuleDef};
|
||||||
|
use ide_db::{
|
||||||
|
assists::{AssistId, AssistKind},
|
||||||
|
helpers::import_assets::item_for_path_search,
|
||||||
|
};
|
||||||
|
use syntax::{ast, AstNode};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
assist_context::{AssistContext, Assists},
|
||||||
|
handlers::qualify_path::QualifyCandidate,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assist: qualify_method_call
|
||||||
|
//
|
||||||
|
// Replaces the method call with a qualified function call.
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// 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 name: ast::NameRef = ctx.find_node_at_offset()?;
|
||||||
|
let call = name.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
|
||||||
|
|
||||||
|
let ident = name.ident_token()?;
|
||||||
|
|
||||||
|
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 `{}` method call", ident.text()),
|
||||||
|
range,
|
||||||
|
|builder| {
|
||||||
|
qualify_candidate.qualify(
|
||||||
|
|replace_with: String| builder.replace(range, replace_with),
|
||||||
|
&receiver_path,
|
||||||
|
item_in_ns,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||||
|
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn struct_method_over_stuct_instance() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
qualify_method_call,
|
||||||
|
r#"
|
||||||
|
struct Foo;
|
||||||
|
impl Foo {
|
||||||
|
fn foo(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo {};
|
||||||
|
f$0oo.foo()
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trait_method_over_stuct_instance() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
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 {};
|
||||||
|
tes$0t_struct.test_method()
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,16 +91,16 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
pub(crate) enum QualifyCandidate<'db> {
|
||||||
enum QualifyCandidate<'db> {
|
|
||||||
QualifierStart(ast::PathSegment, Option<ast::GenericArgList>),
|
QualifierStart(ast::PathSegment, Option<ast::GenericArgList>),
|
||||||
UnqualifiedName(Option<ast::GenericArgList>),
|
UnqualifiedName(Option<ast::GenericArgList>),
|
||||||
TraitAssocItem(ast::Path, ast::PathSegment),
|
TraitAssocItem(ast::Path, ast::PathSegment),
|
||||||
TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
|
TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
|
||||||
|
ImplMethod(&'db RootDatabase, ast::MethodCallExpr, hir::Function),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QualifyCandidate<'_> {
|
impl QualifyCandidate<'_> {
|
||||||
fn qualify(
|
pub(crate) fn qualify(
|
||||||
&self,
|
&self,
|
||||||
mut replacer: impl FnMut(String),
|
mut replacer: impl FnMut(String),
|
||||||
import: &hir::ModPath,
|
import: &hir::ModPath,
|
||||||
|
@ -122,24 +122,26 @@ impl QualifyCandidate<'_> {
|
||||||
QualifyCandidate::TraitMethod(db, mcall_expr) => {
|
QualifyCandidate::TraitMethod(db, mcall_expr) => {
|
||||||
Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
|
Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
|
||||||
}
|
}
|
||||||
|
QualifyCandidate::ImplMethod(db, mcall_expr, hir_fn) => {
|
||||||
|
Self::qualify_fn_call(db, mcall_expr, replacer, import, hir_fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qualify_trait_method(
|
fn qualify_fn_call(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
mcall_expr: &ast::MethodCallExpr,
|
mcall_expr: &ast::MethodCallExpr,
|
||||||
mut replacer: impl FnMut(String),
|
mut replacer: impl FnMut(String),
|
||||||
import: ast::Path,
|
import: ast::Path,
|
||||||
item: hir::ItemInNs,
|
hir_fn: &hir::Function,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let receiver = mcall_expr.receiver()?;
|
let receiver = mcall_expr.receiver()?;
|
||||||
let trait_method_name = mcall_expr.name_ref()?;
|
let method_name = mcall_expr.name_ref()?;
|
||||||
let generics =
|
let generics =
|
||||||
mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
|
mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
|
||||||
let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
|
let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
|
||||||
let trait_ = item_as_trait(db, item)?;
|
|
||||||
let method = find_trait_method(db, trait_, &trait_method_name)?;
|
if let Some(self_access) = hir_fn.self_param(db).map(|sp| sp.access(db)) {
|
||||||
if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
|
|
||||||
let receiver = match self_access {
|
let receiver = match self_access {
|
||||||
hir::Access::Shared => make::expr_ref(receiver, false),
|
hir::Access::Shared => make::expr_ref(receiver, false),
|
||||||
hir::Access::Exclusive => make::expr_ref(receiver, true),
|
hir::Access::Exclusive => make::expr_ref(receiver, true),
|
||||||
|
@ -148,7 +150,7 @@ impl QualifyCandidate<'_> {
|
||||||
replacer(format!(
|
replacer(format!(
|
||||||
"{}::{}{}{}",
|
"{}::{}{}{}",
|
||||||
import,
|
import,
|
||||||
trait_method_name,
|
method_name,
|
||||||
generics,
|
generics,
|
||||||
match arg_list {
|
match arg_list {
|
||||||
Some(args) => make::arg_list(iter::once(receiver).chain(args)),
|
Some(args) => make::arg_list(iter::once(receiver).chain(args)),
|
||||||
|
@ -158,6 +160,19 @@ impl QualifyCandidate<'_> {
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn qualify_trait_method(
|
||||||
|
db: &RootDatabase,
|
||||||
|
mcall_expr: &ast::MethodCallExpr,
|
||||||
|
replacer: impl FnMut(String),
|
||||||
|
import: ast::Path,
|
||||||
|
item: hir::ItemInNs,
|
||||||
|
) -> Option<()> {
|
||||||
|
let trait_method_name = mcall_expr.name_ref()?;
|
||||||
|
let trait_ = item_as_trait(db, item)?;
|
||||||
|
let method = find_trait_method(db, trait_, &trait_method_name)?;
|
||||||
|
Self::qualify_fn_call(db, mcall_expr, replacer, import, &method)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_trait_method(
|
fn find_trait_method(
|
||||||
|
|
|
@ -161,6 +161,7 @@ mod handlers {
|
||||||
mod promote_local_to_const;
|
mod promote_local_to_const;
|
||||||
mod pull_assignment_up;
|
mod pull_assignment_up;
|
||||||
mod qualify_path;
|
mod qualify_path;
|
||||||
|
mod qualify_method_call;
|
||||||
mod raw_string;
|
mod raw_string;
|
||||||
mod remove_dbg;
|
mod remove_dbg;
|
||||||
mod remove_mut;
|
mod remove_mut;
|
||||||
|
@ -242,6 +243,7 @@ mod handlers {
|
||||||
pull_assignment_up::pull_assignment_up,
|
pull_assignment_up::pull_assignment_up,
|
||||||
promote_local_to_const::promote_local_to_const,
|
promote_local_to_const::promote_local_to_const,
|
||||||
qualify_path::qualify_path,
|
qualify_path::qualify_path,
|
||||||
|
qualify_method_call::qualify_method_call,
|
||||||
raw_string::add_hash,
|
raw_string::add_hash,
|
||||||
raw_string::make_usual_string,
|
raw_string::make_usual_string,
|
||||||
raw_string::remove_hash,
|
raw_string::remove_hash,
|
||||||
|
|
|
@ -1531,6 +1531,33 @@ fn main() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doctest_qualify_method_call() {
|
||||||
|
check_doc_test(
|
||||||
|
"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]
|
#[test]
|
||||||
fn doctest_qualify_path() {
|
fn doctest_qualify_path() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
|
|
|
@ -372,7 +372,7 @@ fn import_for_item(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
|
pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
|
||||||
Some(match item {
|
Some(match item {
|
||||||
ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) {
|
ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) {
|
||||||
Some(assoc_item) => match assoc_item.container(db) {
|
Some(assoc_item) => match assoc_item.container(db) {
|
||||||
|
|
Loading…
Reference in a new issue