Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/rename.rs')
-rw-r--r--crates/ide-db/src/rename.rs93
1 files changed, 61 insertions, 32 deletions
diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs
index 353a9749a3..d2b6a73268 100644
--- a/crates/ide-db/src/rename.rs
+++ b/crates/ide-db/src/rename.rs
@@ -22,10 +22,10 @@
//! Our current behavior is ¯\_(ツ)_/¯.
use std::fmt;
-use base_db::{AnchoredPathBuf, FileId, FileRange};
+use base_db::{span::SyntaxContextId, AnchoredPathBuf, FileId, FileRange};
use either::Either;
-use hir::{FieldSource, HasSource, InFile, ModuleSource, Semantics};
-use stdx::never;
+use hir::{FieldSource, HasSource, HirFileIdExt, InFile, ModuleSource, Semantics};
+use stdx::{never, TupleExt};
use syntax::{
ast::{self, HasName},
AstNode, SyntaxKind, TextRange, T,
@@ -34,7 +34,7 @@ use text_edit::{TextEdit, TextEditBuilder};
use crate::{
defs::Definition,
- search::FileReference,
+ search::{FileReference, FileReferenceNode},
source_change::{FileSystemEdit, SourceChange},
syntax_helpers::node_ext::expr_as_name_ref,
traits::convert_to_def_in_trait,
@@ -103,6 +103,7 @@ impl Definition {
/// renamed and extern crate names will report its range, though a rename will introduce
/// an alias instead.
pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange> {
+ let syn_ctx_is_root = |(range, ctx): (_, SyntaxContextId)| ctx.is_root().then(|| range);
let res = match self {
Definition::Macro(mac) => {
let src = mac.source(sema.db)?;
@@ -110,14 +111,18 @@ impl Definition {
Either::Left(it) => it.name()?,
Either::Right(it) => it.name()?,
};
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ src.with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
Definition::Field(field) => {
let src = field.source(sema.db)?;
match &src.value {
FieldSource::Named(record_field) => {
let name = record_field.name()?;
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ src.with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
FieldSource::Pos(_) => None,
}
@@ -125,25 +130,31 @@ impl Definition {
Definition::Module(module) => {
let src = module.declaration_source(sema.db)?;
let name = src.value.name()?;
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ src.with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
- Definition::Function(it) => name_range(it, sema),
+ Definition::Function(it) => name_range(it, sema).and_then(syn_ctx_is_root),
Definition::Adt(adt) => match adt {
- hir::Adt::Struct(it) => name_range(it, sema),
- hir::Adt::Union(it) => name_range(it, sema),
- hir::Adt::Enum(it) => name_range(it, sema),
+ hir::Adt::Struct(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ hir::Adt::Union(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ hir::Adt::Enum(it) => name_range(it, sema).and_then(syn_ctx_is_root),
},
- Definition::Variant(it) => name_range(it, sema),
- Definition::Const(it) => name_range(it, sema),
- Definition::Static(it) => name_range(it, sema),
- Definition::Trait(it) => name_range(it, sema),
- Definition::TraitAlias(it) => name_range(it, sema),
- Definition::TypeAlias(it) => name_range(it, sema),
- Definition::Local(it) => name_range(it.primary_source(sema.db), sema),
+ Definition::Variant(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ Definition::Const(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ Definition::Static(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ Definition::Trait(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ Definition::TraitAlias(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ Definition::TypeAlias(it) => name_range(it, sema).and_then(syn_ctx_is_root),
+ Definition::Local(it) => {
+ name_range(it.primary_source(sema.db), sema).and_then(syn_ctx_is_root)
+ }
Definition::GenericParam(generic_param) => match generic_param {
hir::GenericParam::LifetimeParam(lifetime_param) => {
let src = lifetime_param.source(sema.db)?;
- src.with_value(src.value.lifetime()?.syntax()).original_file_range_opt(sema.db)
+ src.with_value(src.value.lifetime()?.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
_ => {
let x = match generic_param {
@@ -156,22 +167,30 @@ impl Definition {
Either::Left(x) => x.name()?,
Either::Right(_) => return None,
};
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ src.with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
},
Definition::Label(label) => {
let src = label.source(sema.db);
let lifetime = src.value.lifetime()?;
- src.with_value(lifetime.syntax()).original_file_range_opt(sema.db)
+ src.with_value(lifetime.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
Definition::ExternCrateDecl(it) => {
let src = it.source(sema.db)?;
if let Some(rename) = src.value.rename() {
let name = rename.name()?;
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ src.with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
} else {
let name = src.value.name_ref()?;
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ src.with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .and_then(syn_ctx_is_root)
}
}
Definition::BuiltinType(_) => return None,
@@ -183,7 +202,10 @@ impl Definition {
};
return res;
- fn name_range<D>(def: D, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange>
+ fn name_range<D>(
+ def: D,
+ sema: &Semantics<'_, RootDatabase>,
+ ) -> Option<(FileRange, SyntaxContextId)>
where
D: HasSource,
D::Ast: ast::HasName,
@@ -256,8 +278,10 @@ fn rename_mod(
let file_id = src.file_id.original_file(sema.db);
match src.value.name() {
Some(name) => {
- if let Some(file_range) =
- src.with_value(name.syntax()).original_file_range_opt(sema.db)
+ if let Some(file_range) = src
+ .with_value(name.syntax())
+ .original_file_range_opt(sema.db)
+ .map(TupleExt::head)
{
source_change.insert_source_edit(
file_id,
@@ -337,7 +361,7 @@ pub fn source_edit_from_references(
// macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far
let mut edited_ranges = Vec::new();
for &FileReference { range, ref name, .. } in references {
- let name_range = name.syntax().text_range();
+ let name_range = name.text_range();
if name_range.len() != range.len() {
// This usage comes from a different token kind that was downmapped to a NameLike in a macro
// Renaming this will most likely break things syntax-wise
@@ -347,17 +371,17 @@ pub fn source_edit_from_references(
// if the ranges differ then the node is inside a macro call, we can't really attempt
// to make special rewrites like shorthand syntax and such, so just rename the node in
// the macro input
- ast::NameLike::NameRef(name_ref) if name_range == range => {
+ FileReferenceNode::NameRef(name_ref) if name_range == range => {
source_edit_from_name_ref(&mut edit, name_ref, new_name, def)
}
- ast::NameLike::Name(name) if name_range == range => {
+ FileReferenceNode::Name(name) if name_range == range => {
source_edit_from_name(&mut edit, name, new_name)
}
_ => false,
};
if !has_emitted_edit && !edited_ranges.contains(&range.start()) {
let (range, new_name) = match name {
- ast::NameLike::Lifetime(_) => (
+ FileReferenceNode::Lifetime(_) => (
TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(),
),
@@ -493,7 +517,12 @@ fn source_edit_from_def(
for source in local.sources(sema.db) {
let source = match source.source.clone().original_ast_node(sema.db) {
Some(source) => source,
- None => match source.source.syntax().original_file_range_opt(sema.db) {
+ None => match source
+ .source
+ .syntax()
+ .original_file_range_opt(sema.db)
+ .map(TupleExt::head)
+ {
Some(FileRange { file_id: file_id2, range }) => {
file_id = Some(file_id2);
edit.replace(range, new_name.to_owned());
@@ -504,7 +533,7 @@ fn source_edit_from_def(
}
},
};
- file_id = source.file_id.file_id();
+ file_id = Some(source.file_id);
if let Either::Left(pat) = source.value {
let name_range = pat.name().unwrap().syntax().text_range();
// special cases required for renaming fields/locals in Record patterns