This commit is contained in:
Lukas Wirth 2021-03-23 17:39:43 +01:00
parent 065a8e87cd
commit 6bdf505d7c
2 changed files with 56 additions and 40 deletions

View File

@ -973,6 +973,14 @@ impl SelfParam {
Access::Owned => "self", Access::Owned => "self",
} }
} }
pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
let InFile { file_id, value } = Function::from(self.func).source(db)?;
value
.param_list()
.and_then(|params| params.self_param())
.map(|value| InFile { file_id, value })
}
} }
impl HasVisibility for Function { impl HasVisibility for Function {
@ -1348,6 +1356,13 @@ impl Local {
} }
} }
pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
match self.parent {
DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
_ => None,
}
}
// FIXME: why is this an option? It shouldn't be? // FIXME: why is this an option? It shouldn't be?
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
let body = db.body(self.parent); let body = db.body(self.parent);

View File

@ -219,40 +219,44 @@ fn rename_reference(
) -> RenameResult<SourceChange> { ) -> RenameResult<SourceChange> {
let ident_kind = check_identifier(new_name)?; let ident_kind = check_identifier(new_name)?;
let def_is_lbl_or_lt = matches!( if matches!(
def, def, // is target a lifetime?
Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
); ) {
match (ident_kind, def) { match ident_kind {
(IdentifierKind::ToSelf, _) IdentifierKind::Ident | IdentifierKind::ToSelf | IdentifierKind::Underscore => {
| (IdentifierKind::Underscore, _) cov_mark::hit!(rename_not_a_lifetime_ident_ref);
| (IdentifierKind::Ident, _) bail!("Invalid name `{}`: not a lifetime identifier", new_name);
if def_is_lbl_or_lt => }
{ IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
cov_mark::hit!(rename_not_a_lifetime_ident_ref);
bail!("Invalid name `{}`: not a lifetime identifier", new_name)
} }
(IdentifierKind::Lifetime, _) if def_is_lbl_or_lt => cov_mark::hit!(rename_lifetime), } else {
(IdentifierKind::Lifetime, _) => { match (ident_kind, def) {
cov_mark::hit!(rename_not_an_ident_ref); (IdentifierKind::Lifetime, _) => {
bail!("Invalid name `{}`: not an identifier", new_name) cov_mark::hit!(rename_not_an_ident_ref);
} bail!("Invalid name `{}`: not an identifier", new_name);
(IdentifierKind::ToSelf, Definition::Local(local)) if local.is_self(sema.db) => { }
// no-op (IdentifierKind::ToSelf, Definition::Local(local)) => {
cov_mark::hit!(rename_self_to_self); if local.is_self(sema.db) {
return Ok(SourceChange::default()); // no-op
} cov_mark::hit!(rename_self_to_self);
(ident_kind, Definition::Local(local)) if local.is_self(sema.db) => { return Ok(SourceChange::default());
cov_mark::hit!(rename_self_to_param); } else {
return rename_self_to_param(sema, local, new_name, ident_kind); cov_mark::hit!(rename_to_self);
} return rename_to_self(sema, local);
(IdentifierKind::ToSelf, Definition::Local(local)) => { }
cov_mark::hit!(rename_to_self); }
return rename_to_self(sema, local); (ident_kind, Definition::Local(local)) => {
} if let Some(self_param) = local.as_self_param(sema.db) {
(IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name), cov_mark::hit!(rename_self_to_param);
(IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => { return rename_self_to_param(sema, local, self_param, new_name, ident_kind);
cov_mark::hit!(rename_ident) } else {
cov_mark::hit!(rename_local);
}
}
(IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name),
(IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local),
(IdentifierKind::Underscore, _) => (),
} }
} }
@ -336,16 +340,12 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
fn rename_self_to_param( fn rename_self_to_param(
sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
local: hir::Local, local: hir::Local,
self_param: hir::SelfParam,
new_name: &str, new_name: &str,
identifier_kind: IdentifierKind, identifier_kind: IdentifierKind,
) -> RenameResult<SourceChange> { ) -> RenameResult<SourceChange> {
let (file_id, self_param) = match local.source(sema.db) { let InFile { file_id, value: self_param } =
InFile { file_id, value: Either::Right(self_param) } => (file_id, self_param), self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?;
_ => {
never!(true, "rename_self_to_param invoked on a non-self local");
bail!("rename_self_to_param invoked on a non-self local");
}
};
let def = Definition::Local(local); let def = Definition::Local(local);
let usages = def.usages(sema).all(); let usages = def.usages(sema).all();
@ -701,7 +701,7 @@ foo!(Foo$0);",
#[test] #[test]
fn test_rename_for_local() { fn test_rename_for_local() {
cov_mark::check!(rename_ident); cov_mark::check!(rename_local);
check( check(
"k", "k",
r#" r#"
@ -1242,6 +1242,7 @@ pub mod foo$0;
#[test] #[test]
fn test_enum_variant_from_module_1() { fn test_enum_variant_from_module_1() {
cov_mark::check!(rename_non_local);
check( check(
"Baz", "Baz",
r#" r#"