mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 15:15:24 +00:00
Auto merge of #13454 - justinmmott:master, r=flodiebold
Fixed local shadowing the caller's argument issue fix https://github.com/rust-lang/rust-analyzer/issues/12536
This commit is contained in:
commit
df3877037e
1 changed files with 74 additions and 12 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use ast::make;
|
use ast::make;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
|
use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
|
||||||
|
@ -373,8 +375,44 @@ fn inline(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut func_let_vars: BTreeSet<String> = BTreeSet::new();
|
||||||
|
|
||||||
|
// grab all of the local variable declarations in the function
|
||||||
|
for stmt in fn_body.statements() {
|
||||||
|
if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) {
|
||||||
|
for has_token in let_stmt.syntax().children_with_tokens() {
|
||||||
|
if let Some(node) = has_token.as_node() {
|
||||||
|
if let Some(ident_pat) = ast::IdentPat::cast(node.to_owned()) {
|
||||||
|
func_let_vars.insert(ident_pat.syntax().text().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
|
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
|
||||||
for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
|
for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
|
||||||
|
// izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
|
||||||
|
let usages: &[ast::PathExpr] = &*usages;
|
||||||
|
let expr: &ast::Expr = expr;
|
||||||
|
|
||||||
|
let insert_let_stmt = || {
|
||||||
|
let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
|
||||||
|
if let Some(stmt_list) = body.stmt_list() {
|
||||||
|
stmt_list.push_front(
|
||||||
|
make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if there is a local var in the function that conflicts with parameter
|
||||||
|
// if it does then emit a let statement and continue
|
||||||
|
if func_let_vars.contains(&expr.syntax().text().to_string()) {
|
||||||
|
insert_let_stmt();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let inline_direct = |usage, replacement: &ast::Expr| {
|
let inline_direct = |usage, replacement: &ast::Expr| {
|
||||||
if let Some(field) = path_expr_as_record_field(usage) {
|
if let Some(field) = path_expr_as_record_field(usage) {
|
||||||
cov_mark::hit!(inline_call_inline_direct_field);
|
cov_mark::hit!(inline_call_inline_direct_field);
|
||||||
|
@ -383,9 +421,7 @@ fn inline(
|
||||||
ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
|
ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
|
|
||||||
let usages: &[ast::PathExpr] = &*usages;
|
|
||||||
let expr: &ast::Expr = expr;
|
|
||||||
match usages {
|
match usages {
|
||||||
// inline single use closure arguments
|
// inline single use closure arguments
|
||||||
[usage]
|
[usage]
|
||||||
|
@ -408,18 +444,11 @@ fn inline(
|
||||||
}
|
}
|
||||||
// can't inline, emit a let statement
|
// can't inline, emit a let statement
|
||||||
_ => {
|
_ => {
|
||||||
let ty =
|
insert_let_stmt();
|
||||||
sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
|
|
||||||
if let Some(stmt_list) = body.stmt_list() {
|
|
||||||
stmt_list.push_front(
|
|
||||||
make::let_stmt(pat.clone(), ty, Some(expr.clone()))
|
|
||||||
.clone_for_update()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(generic_arg_list) = generic_arg_list.clone() {
|
if let Some(generic_arg_list) = generic_arg_list.clone() {
|
||||||
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
|
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
|
||||||
{
|
{
|
||||||
|
@ -1256,4 +1285,37 @@ impl A {
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn local_variable_shadowing_callers_argument() {
|
||||||
|
check_assist(
|
||||||
|
inline_call,
|
||||||
|
r#"
|
||||||
|
fn foo(bar: u32, baz: u32) -> u32 {
|
||||||
|
let a = 1;
|
||||||
|
bar * baz * a * 6
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let a = 7;
|
||||||
|
let b = 1;
|
||||||
|
let res = foo$0(a, b);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn foo(bar: u32, baz: u32) -> u32 {
|
||||||
|
let a = 1;
|
||||||
|
bar * baz * a * 6
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let a = 7;
|
||||||
|
let b = 1;
|
||||||
|
let res = {
|
||||||
|
let bar = a;
|
||||||
|
let a = 1;
|
||||||
|
bar * b * a * 6
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue