Skip to content

Commit 4302152

Browse files
bors[bot]mahdifrmz
andauthored
Merge #9994
9994: add static method generation assist r=matklad a=mahdi-frms Adds feature: #9948 Will soon send a GIF for the changelog. Co-authored-by: mahdi-frms <[email protected]>
2 parents fa6a4a0 + cf5f1c1 commit 4302152

File tree

1 file changed

+146
-17
lines changed

1 file changed

+146
-17
lines changed

crates/ide_assists/src/handlers/generate_function.rs

Lines changed: 146 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,26 +70,56 @@ impl FuncExpr {
7070
fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
7171
let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
7272
let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
73-
7473
let path = path_expr.path()?;
74+
let fn_name = fn_name(&path)?;
7575
if ctx.sema.resolve_path(&path).is_some() {
7676
// The function call already resolves, no need to add a function
7777
return None;
7878
}
7979

80-
let target_module = match path.qualifier() {
80+
let target_module;
81+
let mut adt_name = None;
82+
83+
let (target, file, insert_offset) = match path.qualifier() {
8184
Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
82-
Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => Some(module),
83-
_ => return None,
85+
Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
86+
target_module = Some(module);
87+
get_fn_target(ctx, &target_module, call.clone())?
88+
}
89+
Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
90+
let current_module = current_module(call.syntax(), ctx)?;
91+
let module = adt.module(ctx.sema.db);
92+
target_module = if current_module == module { None } else { Some(module) };
93+
if current_module.krate() != module.krate() {
94+
return None;
95+
}
96+
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
97+
let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
98+
adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
99+
(target, file, insert_offset)
100+
}
101+
_ => {
102+
return None;
103+
}
84104
},
85-
None => None,
105+
_ => {
106+
target_module = None;
107+
get_fn_target(ctx, &target_module, call.clone())?
108+
}
86109
};
87-
88-
let (target, file, insert_offset) = get_fn_target(ctx, &target_module, call.clone())?;
89110
let function_builder = FunctionBuilder::from_call(ctx, &call, &path, target_module, target)?;
90-
let target = call.syntax().text_range();
111+
let text_range = call.syntax().text_range();
91112
let label = format!("Generate {} function", function_builder.fn_name.clone());
92-
add_func_to_accumulator(acc, ctx, target, function_builder, insert_offset, file, None, label)
113+
add_func_to_accumulator(
114+
acc,
115+
ctx,
116+
text_range,
117+
function_builder,
118+
insert_offset,
119+
file,
120+
adt_name,
121+
label,
122+
)
93123
}
94124

95125
fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -103,13 +133,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
103133
if current_module.krate() != target_module.krate() {
104134
return None;
105135
}
106-
107-
let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
108-
let file = ctx.sema.parse(range.file_id);
109-
let adt_source =
110-
ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
111-
let impl_ = find_struct_impl(ctx, &adt_source, fn_name.text().as_str())?;
112-
136+
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
113137
let (target, insert_offset) = get_method_target(ctx, &target_module, &impl_)?;
114138
let function_builder =
115139
FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
@@ -122,7 +146,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
122146
text_range,
123147
function_builder,
124148
insert_offset,
125-
range.file_id,
149+
file,
126150
adt_name,
127151
label,
128152
)
@@ -156,6 +180,18 @@ fn current_module(current_node: &SyntaxNode, ctx: &AssistContext) -> Option<Modu
156180
ctx.sema.scope(current_node).module()
157181
}
158182

183+
fn get_adt_source(
184+
ctx: &AssistContext,
185+
adt: &hir::Adt,
186+
fn_name: &str,
187+
) -> Option<(Option<ast::Impl>, FileId)> {
188+
let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
189+
let file = ctx.sema.parse(range.file_id);
190+
let adt_source =
191+
ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
192+
find_struct_impl(ctx, &adt_source, fn_name).map(|impl_| (impl_, range.file_id))
193+
}
194+
159195
struct FunctionTemplate {
160196
leading_ws: String,
161197
fn_def: ast::Fn,
@@ -1514,6 +1550,99 @@ fn bar(&self) ${0:-> ()} {
15141550
todo!()
15151551
}
15161552
}
1553+
",
1554+
)
1555+
}
1556+
1557+
#[test]
1558+
fn create_static_method() {
1559+
check_assist(
1560+
generate_function,
1561+
r"
1562+
struct S;
1563+
fn foo() {S::bar$0();}
1564+
",
1565+
r"
1566+
struct S;
1567+
fn foo() {S::bar();}
1568+
impl S {
1569+
1570+
1571+
fn bar() ${0:-> ()} {
1572+
todo!()
1573+
}
1574+
}
1575+
",
1576+
)
1577+
}
1578+
1579+
#[test]
1580+
fn create_static_method_within_an_impl() {
1581+
check_assist(
1582+
generate_function,
1583+
r"
1584+
struct S;
1585+
fn foo() {S::bar$0();}
1586+
impl S {}
1587+
1588+
",
1589+
r"
1590+
struct S;
1591+
fn foo() {S::bar();}
1592+
impl S {
1593+
fn bar() ${0:-> ()} {
1594+
todo!()
1595+
}
1596+
}
1597+
1598+
",
1599+
)
1600+
}
1601+
1602+
#[test]
1603+
fn create_static_method_from_different_module() {
1604+
check_assist(
1605+
generate_function,
1606+
r"
1607+
mod s {
1608+
pub struct S;
1609+
}
1610+
fn foo() {s::S::bar$0();}
1611+
",
1612+
r"
1613+
mod s {
1614+
pub struct S;
1615+
impl S {
1616+
1617+
1618+
pub(crate) fn bar() ${0:-> ()} {
1619+
todo!()
1620+
}
1621+
}
1622+
}
1623+
fn foo() {s::S::bar();}
1624+
",
1625+
)
1626+
}
1627+
1628+
#[test]
1629+
fn create_static_method_with_cursor_anywhere_on_call_expresion() {
1630+
check_assist(
1631+
generate_function,
1632+
r"
1633+
struct S;
1634+
fn foo() {$0S::bar();}
1635+
",
1636+
r"
1637+
struct S;
1638+
fn foo() {S::bar();}
1639+
impl S {
1640+
1641+
1642+
fn bar() ${0:-> ()} {
1643+
todo!()
1644+
}
1645+
}
15171646
",
15181647
)
15191648
}

0 commit comments

Comments
 (0)