Skip to content

Commit d44779f

Browse files
bors[bot]iDawer
andauthored
Merge #10260
10260: fix: fix names generation in `Generate function` r=Veykril a=iDawer - Improve fn name computation (close #10176). - Handle tuple indexing expressions in argument position (should close #10241) Co-authored-by: Dawer <[email protected]>
2 parents 5964750 + 1d94e23 commit d44779f

File tree

2 files changed

+67
-27
lines changed

2 files changed

+67
-27
lines changed

crates/ide_assists/src/handlers/generate_function.rs

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,13 @@ 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)?;
7373
let path = path_expr.path()?;
74-
let fn_name = fn_name(&path)?;
74+
let name_ref = path.segment()?.name_ref()?;
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 fn_name = &*name_ref.text();
8081
let target_module;
8182
let mut adt_name = None;
8283

@@ -93,7 +94,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
9394
if current_module.krate() != module.krate() {
9495
return None;
9596
}
96-
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
97+
let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
9798
let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
9899
adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
99100
(target, file, insert_offset)
@@ -107,7 +108,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
107108
get_fn_target(ctx, &target_module, call.clone())?
108109
}
109110
};
110-
let function_builder = FunctionBuilder::from_call(ctx, &call, &path, target_module, target)?;
111+
let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
111112
let text_range = call.syntax().text_range();
112113
let label = format!("Generate {} function", function_builder.fn_name);
113114
add_func_to_accumulator(
@@ -241,13 +242,13 @@ impl FunctionBuilder {
241242
fn from_call(
242243
ctx: &AssistContext,
243244
call: &ast::CallExpr,
244-
path: &ast::Path,
245+
fn_name: &str,
245246
target_module: Option<hir::Module>,
246247
target: GeneratedFunctionTarget,
247248
) -> Option<Self> {
248249
let needs_pub = target_module.is_some();
249250
let target_module = target_module.or_else(|| current_module(target.syntax(), ctx))?;
250-
let fn_name = fn_name(path)?;
251+
let fn_name = make::name(fn_name);
251252
let (type_params, params) = fn_args(ctx, target_module, FuncExpr::Func(call.clone()))?;
252253

253254
let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
@@ -428,11 +429,6 @@ impl GeneratedFunctionTarget {
428429
}
429430
}
430431

431-
fn fn_name(call: &ast::Path) -> Option<ast::Name> {
432-
let name = call.segment()?.syntax().to_string();
433-
Some(make::name(&name))
434-
}
435-
436432
/// Computes the type variables and arguments required for the generated function
437433
fn fn_args(
438434
ctx: &AssistContext,
@@ -442,10 +438,7 @@ fn fn_args(
442438
let mut arg_names = Vec::new();
443439
let mut arg_types = Vec::new();
444440
for arg in call.arg_list()?.args() {
445-
arg_names.push(match fn_arg_name(&arg) {
446-
Some(name) => name,
447-
None => String::from("arg"),
448-
});
441+
arg_names.push(fn_arg_name(&arg));
449442
arg_types.push(match fn_arg_type(ctx, target_module, &arg) {
450443
Some(ty) => {
451444
if !ty.is_empty() && ty.starts_with('&') {
@@ -510,18 +503,21 @@ fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
510503
}
511504
}
512505

513-
fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
514-
match fn_arg {
515-
ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
516-
_ => {
517-
let s = fn_arg
518-
.syntax()
519-
.descendants()
520-
.filter(|d| ast::NameRef::can_cast(d.kind()))
521-
.last()?
522-
.to_string();
506+
fn fn_arg_name(arg_expr: &ast::Expr) -> String {
507+
let name = (|| match arg_expr {
508+
ast::Expr::CastExpr(cast_expr) => Some(fn_arg_name(&cast_expr.expr()?)),
509+
expr => {
510+
let s = expr.syntax().descendants().filter_map(ast::NameRef::cast).last()?.to_string();
523511
Some(to_lower_snake_case(&s))
524512
}
513+
})();
514+
match name {
515+
Some(mut name) if name.starts_with(|c: char| c.is_ascii_digit()) => {
516+
name.insert_str(0, "arg");
517+
name
518+
}
519+
Some(name) => name,
520+
None => "arg".to_string(),
525521
}
526522
}
527523

@@ -1643,6 +1639,50 @@ fn bar() ${0:-> _} {
16431639
todo!()
16441640
}
16451641
}
1642+
",
1643+
)
1644+
}
1645+
1646+
#[test]
1647+
fn no_panic_on_invalid_global_path() {
1648+
check_assist(
1649+
generate_function,
1650+
r"
1651+
fn main() {
1652+
::foo$0();
1653+
}
1654+
",
1655+
r"
1656+
fn main() {
1657+
::foo();
1658+
}
1659+
1660+
fn foo() ${0:-> _} {
1661+
todo!()
1662+
}
1663+
",
1664+
)
1665+
}
1666+
1667+
#[test]
1668+
fn handle_tuple_indexing() {
1669+
check_assist(
1670+
generate_function,
1671+
r"
1672+
fn main() {
1673+
let a = ((),);
1674+
foo$0(a.0);
1675+
}
1676+
",
1677+
r"
1678+
fn main() {
1679+
let a = ((),);
1680+
foo(a.0);
1681+
}
1682+
1683+
fn foo(arg0: ()) ${0:-> _} {
1684+
todo!()
1685+
}
16461686
",
16471687
)
16481688
}

crates/syntax/src/token_text.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ impl<'a> TokenText<'a> {
2121
}
2222

2323
pub fn as_str(&self) -> &str {
24-
match self.0 {
25-
Repr::Borrowed(it) => it,
26-
Repr::Owned(ref green) => green.text(),
24+
match &self.0 {
25+
&Repr::Borrowed(it) => it,
26+
Repr::Owned(green) => green.text(),
2727
}
2828
}
2929
}

0 commit comments

Comments
 (0)