Allow assist edit for converting structs to appear also on struct keyword and on visibility
This commit is contained in:
parent
01a1908a46
commit
e3d26cdbb6
3 changed files with 192 additions and 6 deletions
|
|
@ -7,7 +7,7 @@ use syntax::{
|
|||
match_ast, ted,
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
|
||||
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::find_struct_definition_from_cursor};
|
||||
|
||||
// Assist: convert_named_struct_to_tuple_struct
|
||||
//
|
||||
|
|
@ -56,8 +56,7 @@ pub(crate) fn convert_named_struct_to_tuple_struct(
|
|||
// XXX: We don't currently provide this assist for struct definitions inside macros, but if we
|
||||
// are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files
|
||||
// too.
|
||||
let name = ctx.find_node_at_offset::<ast::Name>()?;
|
||||
let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
|
||||
let strukt = find_struct_definition_from_cursor(ctx)?;
|
||||
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
||||
let record_fields = match field_list {
|
||||
ast::FieldList::RecordFieldList(it) => it,
|
||||
|
|
@ -293,6 +292,89 @@ impl A {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_simple_struct_cursor_on_struct_keyword() {
|
||||
check_assist(
|
||||
convert_named_struct_to_tuple_struct,
|
||||
r#"
|
||||
struct Inner;
|
||||
struct$0 A { inner: Inner }
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A { inner }
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.inner
|
||||
}
|
||||
}"#,
|
||||
r#"
|
||||
struct Inner;
|
||||
struct A(Inner);
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A(inner)
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_simple_struct_cursor_on_visibility_keyword() {
|
||||
check_assist(
|
||||
convert_named_struct_to_tuple_struct,
|
||||
r#"
|
||||
struct Inner;
|
||||
pub$0 struct A { inner: Inner }
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A { inner }
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.inner
|
||||
}
|
||||
}"#,
|
||||
r#"
|
||||
struct Inner;
|
||||
struct A(Inner);
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A(inner)
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn convert_struct_referenced_via_self_kw() {
|
||||
check_assist(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use syntax::{
|
|||
match_ast, ted,
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
|
||||
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::find_struct_definition_from_cursor};
|
||||
|
||||
// Assist: convert_tuple_struct_to_named_struct
|
||||
//
|
||||
|
|
@ -51,8 +51,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
|
|||
acc: &mut Assists,
|
||||
ctx: &AssistContext<'_>,
|
||||
) -> Option<()> {
|
||||
let name = ctx.find_node_at_offset::<ast::Name>()?;
|
||||
let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
|
||||
let strukt = find_struct_definition_from_cursor(ctx)?;
|
||||
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
||||
let tuple_fields = match field_list {
|
||||
ast::FieldList::TupleFieldList(it) => it,
|
||||
|
|
@ -300,6 +299,88 @@ impl A {
|
|||
struct Inner;
|
||||
struct A { field1: Inner }
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A { field1: inner }
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.field1
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_simple_struct_cursor_on_struct_keyword() {
|
||||
check_assist(
|
||||
convert_tuple_struct_to_named_struct,
|
||||
r#"
|
||||
struct Inner;
|
||||
struct$0 A(Inner);
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A(inner)
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.0
|
||||
}
|
||||
}"#,
|
||||
r#"
|
||||
struct Inner;
|
||||
struct A { field1: Inner }
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A { field1: inner }
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.field1
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_simple_struct_cursor_on_visibility_keyword() {
|
||||
check_assist(
|
||||
convert_tuple_struct_to_named_struct,
|
||||
r#"
|
||||
struct Inner;
|
||||
pub$0 struct A(Inner);
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A(inner)
|
||||
}
|
||||
|
||||
fn new_with_default() -> A {
|
||||
A::new(Inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Inner {
|
||||
self.0
|
||||
}
|
||||
}"#,
|
||||
r#"
|
||||
struct Inner;
|
||||
pub struct A { field1: Inner }
|
||||
|
||||
impl A {
|
||||
fn new(inner: Inner) -> A {
|
||||
A { field1: inner }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
//! Assorted functions shared by several assists.
|
||||
|
||||
use either::Either;
|
||||
|
||||
pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
|
||||
use hir::{
|
||||
DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution,
|
||||
|
|
@ -1146,3 +1148,24 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo
|
|||
});
|
||||
is_const
|
||||
}
|
||||
|
||||
/// Gets the struct definition from a context
|
||||
pub(crate) fn find_struct_definition_from_cursor(ctx: &AssistContext<'_>)
|
||||
-> Option<Either<ast::Struct, ast::Variant>>
|
||||
{
|
||||
ctx.find_node_at_offset::<ast::Name>().and_then(|name| name.syntax().parent())
|
||||
.or(find_struct_keyword(ctx).and_then(|kw| kw.parent()))
|
||||
.or(ctx.find_node_at_offset::<ast::Visibility>().and_then(|visibility| visibility.syntax().parent()))
|
||||
.and_then(<Either<ast::Struct, ast::Variant>>::cast)
|
||||
}
|
||||
|
||||
fn find_struct_keyword(ctx: &AssistContext<'_>) -> Option<SyntaxToken> {
|
||||
// Attempt to find the token at the current cursor offset
|
||||
ctx
|
||||
.token_at_offset()
|
||||
.find(|leaf| match leaf.kind() {
|
||||
STRUCT_KW => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue