Unnamed repository; edit this file 'description' to name the repository.
Anatol Ulrich 2021-10-27
parent 8d3ac32 · commit 6cd15c2
-rw-r--r--crates/ide/src/rename.rs42
1 files changed, 30 insertions, 12 deletions
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 59ba2b867a..76f694aa51 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -12,7 +12,7 @@ use ide_db::{
RootDatabase,
};
use itertools::Itertools;
-use stdx::{always, never};
+use stdx::never;
use syntax::{ast, AstNode, SyntaxNode};
use text_edit::TextEdit;
@@ -33,17 +33,35 @@ pub(crate) fn prepare_rename(
let source_file = sema.parse(position.file_id);
let syntax = source_file.syntax();
- let mut defs = find_definitions(&sema, syntax, position)?;
-
- // TODO:
- // - `find_definitions` is implemented so that it returns a non-empty vec
- // in the `Ok` case. But that's not expressed by the type signature, hence `unwrap()`
- // here which ... wart.
- // - is "just take the first `name_like`" correct? If not, what do?
- let (name_like, _def) = defs.next().unwrap();
- let frange = sema.original_range(name_like.syntax());
- always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id);
- Ok(RangeInfo::new(frange.range, ()))
+ let res = find_definitions(&sema, syntax, position)?
+ .map(|(name_like, def)| {
+ // ensure all ranges are valid
+
+ if def.range_for_rename(&sema).is_none() {
+ bail!("No references found at position")
+ }
+ let frange = sema.original_range(name_like.syntax());
+ if frange.range.contains_inclusive(position.offset)
+ && frange.file_id == position.file_id
+ {
+ Ok(frange.range)
+ } else {
+ bail!("invalid text range")
+ }
+ })
+ .reduce(|acc, cur| match acc {
+ // ensure all ranges are the same
+ Ok(acc_inner) if cur.is_ok() && acc_inner == cur.unwrap() => acc,
+ Err(e) => Err(e),
+ _ => bail!("inconsistent text range"),
+ });
+
+ match res {
+ // ensure at least one definition was found
+ // TODO this duplicates work done at the end of `find_definitions`
+ Some(res) => res.map(|range| RangeInfo::new(range, ())),
+ None => bail!("No references found at position"),
+ }
}
// Feature: Rename