From 15e7112da31b8ffd246620831b3dc2b70a858af5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 9 Apr 2022 00:55:45 +0200 Subject: [PATCH] fix: Check whether a parameter can be converted to a local --- crates/hir/src/lib.rs | 9 +++- crates/ide/src/rename.rs | 9 +++- .../ide_assists/src/handlers/inline_call.rs | 47 +++++++++++-------- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8bab7c1f3e..37bb2e1997 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -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 { 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 { diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 83bc299adc..1bb3cdb907 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -219,8 +219,13 @@ fn rename_to_self(sema: &Semantics, 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 diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs index af2cb332e5..c857adf876 100644 --- a/crates/ide_assists/src/handlers/inline_call.rs +++ b/crates/ide_assists/src/handlers/inline_call.rs @@ -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::>>() - .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::>>() + .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() {