Auto merge of #15573 - alibektas:15539/into_to_from, r=Veykril
assist : `into_to_qualified_from` fixes #15539. This assist converts an `.into()` call into an explicit fully qualified `from()` call.
This commit is contained in:
commit
47e0d07eb0
205
crates/ide-assists/src/handlers/into_to_qualified_from.rs
Normal file
205
crates/ide-assists/src/handlers/into_to_qualified_from.rs
Normal file
@ -0,0 +1,205 @@
|
||||
use hir::{AsAssocItem, HirDisplay};
|
||||
use ide_db::{
|
||||
assists::{AssistId, AssistKind},
|
||||
famous_defs::FamousDefs,
|
||||
};
|
||||
use syntax::{ast, AstNode};
|
||||
|
||||
use crate::assist_context::{AssistContext, Assists};
|
||||
|
||||
// Assist: into_to_qualified_from
|
||||
//
|
||||
// Convert an `into` method call to a fully qualified `from` call.
|
||||
//
|
||||
// ```
|
||||
// //- minicore: from
|
||||
// struct B;
|
||||
// impl From<i32> for B {
|
||||
// fn from(a: i32) -> Self {
|
||||
// B
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn main() -> () {
|
||||
// let a = 3;
|
||||
// let b: B = a.in$0to();
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// struct B;
|
||||
// impl From<i32> for B {
|
||||
// fn from(a: i32) -> Self {
|
||||
// B
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn main() -> () {
|
||||
// let a = 3;
|
||||
// let b: B = B::from(a);
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||
let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
|
||||
let nameref = method_call.name_ref()?;
|
||||
let receiver = method_call.receiver()?;
|
||||
let db = ctx.db();
|
||||
let sema = &ctx.sema;
|
||||
let fnc = sema.resolve_method_call(&method_call)?;
|
||||
let scope = sema.scope(method_call.syntax())?;
|
||||
// Check if the method call refers to Into trait.
|
||||
if fnc.as_assoc_item(db)?.containing_trait_impl(db)?
|
||||
== FamousDefs(sema, scope.krate()).core_convert_Into()?
|
||||
{
|
||||
let type_call = sema.type_of_expr(&method_call.clone().into())?;
|
||||
let type_call_disp =
|
||||
type_call.adjusted().display_source_code(db, scope.module().into(), true).ok()?;
|
||||
|
||||
acc.add(
|
||||
AssistId("into_to_qualified_from", AssistKind::Generate),
|
||||
"Convert `into` to fully qualified `from`",
|
||||
nameref.syntax().text_range(),
|
||||
|edit| {
|
||||
edit.replace(
|
||||
method_call.syntax().text_range(),
|
||||
format!("{}::from({})", type_call_disp, receiver),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::check_assist;
|
||||
|
||||
use super::into_to_qualified_from;
|
||||
|
||||
#[test]
|
||||
fn two_types_in_same_mod() {
|
||||
check_assist(
|
||||
into_to_qualified_from,
|
||||
r#"
|
||||
//- minicore: from
|
||||
struct A;
|
||||
struct B;
|
||||
impl From<A> for B {
|
||||
fn from(a: A) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a: A = A;
|
||||
let b: B = a.in$0to();
|
||||
}"#,
|
||||
r#"
|
||||
struct A;
|
||||
struct B;
|
||||
impl From<A> for B {
|
||||
fn from(a: A) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a: A = A;
|
||||
let b: B = B::from(a);
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fromed_in_child_mod_imported() {
|
||||
check_assist(
|
||||
into_to_qualified_from,
|
||||
r#"
|
||||
//- minicore: from
|
||||
use C::B;
|
||||
|
||||
struct A;
|
||||
|
||||
mod C {
|
||||
use crate::A;
|
||||
|
||||
pub(super) struct B;
|
||||
impl From<A> for B {
|
||||
fn from(a: A) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a: A = A;
|
||||
let b: B = a.in$0to();
|
||||
}"#,
|
||||
r#"
|
||||
use C::B;
|
||||
|
||||
struct A;
|
||||
|
||||
mod C {
|
||||
use crate::A;
|
||||
|
||||
pub(super) struct B;
|
||||
impl From<A> for B {
|
||||
fn from(a: A) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a: A = A;
|
||||
let b: B = B::from(a);
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fromed_in_child_mod_not_imported() {
|
||||
check_assist(
|
||||
into_to_qualified_from,
|
||||
r#"
|
||||
//- minicore: from
|
||||
struct A;
|
||||
|
||||
mod C {
|
||||
use crate::A;
|
||||
|
||||
pub(super) struct B;
|
||||
impl From<A> for B {
|
||||
fn from(a: A) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a: A = A;
|
||||
let b: C::B = a.in$0to();
|
||||
}"#,
|
||||
r#"
|
||||
struct A;
|
||||
|
||||
mod C {
|
||||
use crate::A;
|
||||
|
||||
pub(super) struct B;
|
||||
impl From<A> for B {
|
||||
fn from(a: A) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a: A = A;
|
||||
let b: C::B = C::B::from(a);
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
}
|
@ -211,6 +211,7 @@ mod handlers {
|
||||
mod unwrap_result_return_type;
|
||||
mod unqualify_method_call;
|
||||
mod wrap_return_type_in_result;
|
||||
mod into_to_qualified_from;
|
||||
|
||||
pub(crate) fn all() -> &'static [Handler] {
|
||||
&[
|
||||
@ -274,6 +275,7 @@ pub(crate) fn all() -> &'static [Handler] {
|
||||
inline_local_variable::inline_local_variable,
|
||||
inline_type_alias::inline_type_alias,
|
||||
inline_type_alias::inline_type_alias_uses,
|
||||
into_to_qualified_from::into_to_qualified_from,
|
||||
introduce_named_generic::introduce_named_generic,
|
||||
introduce_named_lifetime::introduce_named_lifetime,
|
||||
invert_if::invert_if,
|
||||
|
@ -1741,6 +1741,40 @@ fn foo() {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_into_to_qualified_from() {
|
||||
check_doc_test(
|
||||
"into_to_qualified_from",
|
||||
r#####"
|
||||
//- minicore: from
|
||||
struct B;
|
||||
impl From<i32> for B {
|
||||
fn from(a: i32) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a = 3;
|
||||
let b: B = a.in$0to();
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
struct B;
|
||||
impl From<i32> for B {
|
||||
fn from(a: i32) -> Self {
|
||||
B
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> () {
|
||||
let a = 3;
|
||||
let b: B = B::from(a);
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_introduce_named_generic() {
|
||||
check_doc_test(
|
||||
|
Loading…
Reference in New Issue
Block a user