mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
fix: Check whether a parameter can be converted to a local
This commit is contained in:
parent
399559e597
commit
15e7112da3
3 changed files with 41 additions and 24 deletions
|
@ -1506,10 +1506,15 @@ impl Param {
|
|||
db.function_data(self.func.id).params[self.idx].0.clone()
|
||||
}
|
||||
|
||||
pub fn as_local(&self, db: &dyn HirDatabase) -> Local {
|
||||
pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
|
||||
let parent = DefWithBodyId::FunctionId(self.func.into());
|
||||
let body = db.body(parent);
|
||||
Local { parent, pat_id: body.params[self.idx] }
|
||||
let pat_id = body.params[self.idx];
|
||||
if let Pat::Bind { .. } = &body[pat_id] {
|
||||
Some(Local { parent, pat_id: body.params[self.idx] })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
|
||||
|
|
|
@ -219,8 +219,13 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
|
|||
let first_param = params
|
||||
.first()
|
||||
.ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?;
|
||||
if first_param.as_local(sema.db) != local {
|
||||
bail!("Only the first parameter may be renamed to self");
|
||||
match first_param.as_local(sema.db) {
|
||||
Some(plocal) => {
|
||||
if plocal != local {
|
||||
bail!("Only the first parameter may be renamed to self");
|
||||
}
|
||||
}
|
||||
None => bail!("rename_to_self invoked on destructuring parameter"),
|
||||
}
|
||||
|
||||
let assoc_item = fn_def
|
||||
|
|
|
@ -317,30 +317,37 @@ fn inline(
|
|||
if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {
|
||||
return Vec::new();
|
||||
}
|
||||
usages_for_locals(param.as_local(sema.db))
|
||||
.map(|FileReference { name, range, .. }| match name {
|
||||
ast::NameLike::NameRef(_) => body
|
||||
.syntax()
|
||||
.covering_element(range)
|
||||
.ancestors()
|
||||
.nth(3)
|
||||
.and_then(ast::PathExpr::cast),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_default()
|
||||
// FIXME: we need to fetch all locals declared in the parameter here
|
||||
// not only the local if it is a simple binding
|
||||
match param.as_local(sema.db) {
|
||||
Some(l) => usages_for_locals(l)
|
||||
.map(|FileReference { name, range, .. }| match name {
|
||||
ast::NameLike::NameRef(_) => body
|
||||
.syntax()
|
||||
.covering_element(range)
|
||||
.ancestors()
|
||||
.nth(3)
|
||||
.and_then(ast::PathExpr::cast),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_default(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if function.self_param(sema.db).is_some() {
|
||||
let this = || make::name_ref("this").syntax().clone_for_update();
|
||||
usages_for_locals(params[0].2.as_local(sema.db))
|
||||
.flat_map(|FileReference { name, range, .. }| match name {
|
||||
ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
|
||||
_ => None,
|
||||
})
|
||||
.for_each(|it| {
|
||||
ted::replace(it, &this());
|
||||
})
|
||||
if let Some(self_local) = params[0].2.as_local(sema.db) {
|
||||
usages_for_locals(self_local)
|
||||
.flat_map(|FileReference { name, range, .. }| match name {
|
||||
ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
|
||||
_ => None,
|
||||
})
|
||||
.for_each(|it| {
|
||||
ted::replace(it, &this());
|
||||
})
|
||||
}
|
||||
}
|
||||
// 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() {
|
||||
|
|
Loading…
Reference in a new issue