Skip to content

Commit e4ef0e5

Browse files
committed
addressed #12536
1 parent 8ee23f4 commit e4ef0e5

File tree

1 file changed

+74
-12
lines changed

1 file changed

+74
-12
lines changed

crates/ide-assists/src/handlers/inline_call.rs

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::BTreeSet;
2+
13
use ast::make;
24
use either::Either;
35
use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
@@ -373,8 +375,44 @@ fn inline(
373375
})
374376
}
375377
}
378+
379+
let mut func_let_vars: BTreeSet<String> = BTreeSet::new();
380+
381+
// grab all of the local variable declarations in the function
382+
for stmt in fn_body.statements() {
383+
if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) {
384+
for has_token in let_stmt.syntax().children_with_tokens() {
385+
if let Some(node) = has_token.as_node() {
386+
if let Some(ident_pat) = ast::IdentPat::cast(node.to_owned()) {
387+
func_let_vars.insert(ident_pat.syntax().text().to_string());
388+
}
389+
}
390+
}
391+
}
392+
}
393+
376394
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
377395
for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
396+
// izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
397+
let usages: &[ast::PathExpr] = &*usages;
398+
let expr: &ast::Expr = expr;
399+
400+
let insert_let_stmt = || {
401+
let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
402+
if let Some(stmt_list) = body.stmt_list() {
403+
stmt_list.push_front(
404+
make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
405+
)
406+
}
407+
};
408+
409+
// check if there is a local var in the function that conflicts with parameter
410+
// if it does then emit a let statement and continue
411+
if func_let_vars.contains(&expr.syntax().text().to_string()) {
412+
insert_let_stmt();
413+
continue;
414+
}
415+
378416
let inline_direct = |usage, replacement: &ast::Expr| {
379417
if let Some(field) = path_expr_as_record_field(usage) {
380418
cov_mark::hit!(inline_call_inline_direct_field);
@@ -383,9 +421,7 @@ fn inline(
383421
ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
384422
}
385423
};
386-
// izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
387-
let usages: &[ast::PathExpr] = &*usages;
388-
let expr: &ast::Expr = expr;
424+
389425
match usages {
390426
// inline single use closure arguments
391427
[usage]
@@ -408,18 +444,11 @@ fn inline(
408444
}
409445
// can't inline, emit a let statement
410446
_ => {
411-
let ty =
412-
sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
413-
if let Some(stmt_list) = body.stmt_list() {
414-
stmt_list.push_front(
415-
make::let_stmt(pat.clone(), ty, Some(expr.clone()))
416-
.clone_for_update()
417-
.into(),
418-
)
419-
}
447+
insert_let_stmt();
420448
}
421449
}
422450
}
451+
423452
if let Some(generic_arg_list) = generic_arg_list.clone() {
424453
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
425454
{
@@ -1256,4 +1285,37 @@ impl A {
12561285
"#,
12571286
)
12581287
}
1288+
1289+
#[test]
1290+
fn local_variable_shadowing_callers_argument() {
1291+
check_assist(
1292+
inline_call,
1293+
r#"
1294+
fn foo(bar: u32, baz: u32) -> u32 {
1295+
let a = 1;
1296+
bar * baz * a * 6
1297+
}
1298+
fn main() {
1299+
let a = 7;
1300+
let b = 1;
1301+
let res = foo$0(a, b);
1302+
}
1303+
"#,
1304+
r#"
1305+
fn foo(bar: u32, baz: u32) -> u32 {
1306+
let a = 1;
1307+
bar * baz * a * 6
1308+
}
1309+
fn main() {
1310+
let a = 7;
1311+
let b = 1;
1312+
let res = {
1313+
let bar = a;
1314+
let a = 1;
1315+
bar * b * a * 6
1316+
};
1317+
}
1318+
"#,
1319+
);
1320+
}
12591321
}

0 commit comments

Comments
 (0)