diff options
| author | Anatol Ulrich <anatol.ulrich@ferrous-systems.com> | 2021-11-02 21:38:38 +0100 |
|---|---|---|
| committer | Anatol Ulrich <anatol.ulrich@ferrous-systems.com> | 2021-11-02 21:38:38 +0100 |
| commit | 9bce4d669647c11c87be39fd08db5a68bf324c12 (patch) | |
| tree | 967bf34a96320e6f519224e3a577422dd3bbb986 | |
| parent | 1ac35532c4f934b2453501ec39efa87bf1e5724d (diff) | |
| download | rust-9bce4d669647c11c87be39fd08db5a68bf324c12.tar.gz rust-9bce4d669647c11c87be39fd08db5a68bf324c12.zip | |
accept identical Indels when merging; add rename test case
| -rw-r--r-- | crates/ide/src/rename.rs | 36 | ||||
| -rw-r--r-- | crates/text_edit/src/lib.rs | 36 |
2 files changed, 57 insertions, 15 deletions
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 1f85480b16c..9ce0dd7404a 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -100,6 +100,7 @@ pub(crate) fn rename( def.rename(&sema, new_name) }) .collect(); + ops?.into_iter() .reduce(|acc, elem| acc.merge(elem)) .ok_or_else(|| format_err!("No references found at position")) @@ -186,13 +187,14 @@ fn find_definitions( res }); - let res: RenameResult<Vec<(ast::NameLike, Definition)>> = symbols.collect(); + let res: RenameResult<Vec<_>> = symbols.collect(); match res { - // remove duplicates Ok(v) => { if v.is_empty() { + // FIXME: some semantic duplication between "empty vec" and "Err()" Err(format_err!("No references found at position")) } else { + // remove duplicates, comparing `Definition`s Ok(v.into_iter().unique_by(|t| t.1)) } } @@ -570,6 +572,36 @@ fn main() { } #[test] + fn test_rename_macro_multiple_occurrences() { + check( + "Baaah", + r#"macro_rules! foo { + ($ident:ident) => { + const $ident: () = (); + struct $ident {} + }; +} + +foo!($0Foo); +const _: () = Foo; +const _: Foo = Foo {}; + "#, + r#" +macro_rules! foo { + ($ident:ident) => { + const $ident: () = (); + struct $ident {} + }; +} + +foo!(Baaah); +const _: () = Baaah; +const _: Baaah = Baaah {}; + "#, + ) + } + + #[test] fn test_rename_for_macro_args() { check( "b", diff --git a/crates/text_edit/src/lib.rs b/crates/text_edit/src/lib.rs index e9700c560ad..c4000d80522 100644 --- a/crates/text_edit/src/lib.rs +++ b/crates/text_edit/src/lib.rs @@ -3,12 +3,14 @@ //! `rust-analyzer` never mutates text itself and only sends diffs to clients, //! so `TextEdit` is the ultimate representation of the work done by //! rust-analyzer. +use std::collections::HashSet; + pub use text_size::{TextRange, TextSize}; /// `InsertDelete` -- a single "atomic" change to text /// /// Must not overlap with other `InDel`s -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Indel { pub insert: String, /// Refers to offsets in the original text @@ -114,13 +116,20 @@ impl TextEdit { } pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> { + dbg!(&self, &other); // FIXME: can be done without allocating intermediate vector let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>(); - if !check_disjoint(&mut all) { + if !check_disjoint_or_equal(&mut all) { return Err(other); } - self.indels.extend(other.indels); - assert_disjoint(&mut self.indels); + + // remove duplicates + // FIXME: maybe make indels a HashSet instead to get rid of this? + let our_indels = self.indels.clone(); + let our_indels = our_indels.iter().collect::<HashSet<_>>(); + let other_indels = other.indels.into_iter().filter(|i| !our_indels.contains(i)); + + self.indels.extend(other_indels); Ok(()) } @@ -173,7 +182,7 @@ impl TextEditBuilder { } pub fn finish(self) -> TextEdit { let mut indels = self.indels; - assert_disjoint(&mut indels); + assert_disjoint_or_equal(&mut indels); TextEdit { indels } } pub fn invalidates_offset(&self, offset: TextSize) -> bool { @@ -182,18 +191,19 @@ impl TextEditBuilder { fn indel(&mut self, indel: Indel) { self.indels.push(indel); if self.indels.len() <= 16 { - assert_disjoint(&mut self.indels); + assert_disjoint_or_equal(&mut self.indels); } } } -fn assert_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) { - assert!(check_disjoint(indels)); +fn assert_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) { + assert!(check_disjoint_or_equal(indels)); } -fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool { +fn check_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool { indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end())); - indels - .iter() - .zip(indels.iter().skip(1)) - .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start()) + indels.iter().zip(indels.iter().skip(1)).all(|(l, r)| { + let l = l.borrow(); + let r = r.borrow(); + l.delete.end() <= r.delete.start() || l == r + }) } |
