Skip to content

Commit 9bce4d6

Browse files
author
Anatol Ulrich
committed
accept identical Indels when merging; add rename test case
1 parent 1ac3553 commit 9bce4d6

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

crates/ide/src/rename.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub(crate) fn rename(
100100
def.rename(&sema, new_name)
101101
})
102102
.collect();
103+
103104
ops?.into_iter()
104105
.reduce(|acc, elem| acc.merge(elem))
105106
.ok_or_else(|| format_err!("No references found at position"))
@@ -186,13 +187,14 @@ fn find_definitions(
186187
res
187188
});
188189

189-
let res: RenameResult<Vec<(ast::NameLike, Definition)>> = symbols.collect();
190+
let res: RenameResult<Vec<_>> = symbols.collect();
190191
match res {
191-
// remove duplicates
192192
Ok(v) => {
193193
if v.is_empty() {
194+
// FIXME: some semantic duplication between "empty vec" and "Err()"
194195
Err(format_err!("No references found at position"))
195196
} else {
197+
// remove duplicates, comparing `Definition`s
196198
Ok(v.into_iter().unique_by(|t| t.1))
197199
}
198200
}
@@ -569,6 +571,36 @@ fn main() {
569571
);
570572
}
571573

574+
#[test]
575+
fn test_rename_macro_multiple_occurrences() {
576+
check(
577+
"Baaah",
578+
r#"macro_rules! foo {
579+
($ident:ident) => {
580+
const $ident: () = ();
581+
struct $ident {}
582+
};
583+
}
584+
585+
foo!($0Foo);
586+
const _: () = Foo;
587+
const _: Foo = Foo {};
588+
"#,
589+
r#"
590+
macro_rules! foo {
591+
($ident:ident) => {
592+
const $ident: () = ();
593+
struct $ident {}
594+
};
595+
}
596+
597+
foo!(Baaah);
598+
const _: () = Baaah;
599+
const _: Baaah = Baaah {};
600+
"#,
601+
)
602+
}
603+
572604
#[test]
573605
fn test_rename_for_macro_args() {
574606
check(

crates/text_edit/src/lib.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
44
//! so `TextEdit` is the ultimate representation of the work done by
55
//! rust-analyzer.
6+
use std::collections::HashSet;
7+
68
pub use text_size::{TextRange, TextSize};
79

810
/// `InsertDelete` -- a single "atomic" change to text
911
///
1012
/// Must not overlap with other `InDel`s
11-
#[derive(Debug, Clone)]
13+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1214
pub struct Indel {
1315
pub insert: String,
1416
/// Refers to offsets in the original text
@@ -114,13 +116,20 @@ impl TextEdit {
114116
}
115117

116118
pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
119+
dbg!(&self, &other);
117120
// FIXME: can be done without allocating intermediate vector
118121
let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
119-
if !check_disjoint(&mut all) {
122+
if !check_disjoint_or_equal(&mut all) {
120123
return Err(other);
121124
}
122-
self.indels.extend(other.indels);
123-
assert_disjoint(&mut self.indels);
125+
126+
// remove duplicates
127+
// FIXME: maybe make indels a HashSet instead to get rid of this?
128+
let our_indels = self.indels.clone();
129+
let our_indels = our_indels.iter().collect::<HashSet<_>>();
130+
let other_indels = other.indels.into_iter().filter(|i| !our_indels.contains(i));
131+
132+
self.indels.extend(other_indels);
124133
Ok(())
125134
}
126135

@@ -173,7 +182,7 @@ impl TextEditBuilder {
173182
}
174183
pub fn finish(self) -> TextEdit {
175184
let mut indels = self.indels;
176-
assert_disjoint(&mut indels);
185+
assert_disjoint_or_equal(&mut indels);
177186
TextEdit { indels }
178187
}
179188
pub fn invalidates_offset(&self, offset: TextSize) -> bool {
@@ -182,18 +191,19 @@ impl TextEditBuilder {
182191
fn indel(&mut self, indel: Indel) {
183192
self.indels.push(indel);
184193
if self.indels.len() <= 16 {
185-
assert_disjoint(&mut self.indels);
194+
assert_disjoint_or_equal(&mut self.indels);
186195
}
187196
}
188197
}
189198

190-
fn assert_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) {
191-
assert!(check_disjoint(indels));
199+
fn assert_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) {
200+
assert!(check_disjoint_or_equal(indels));
192201
}
193-
fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
202+
fn check_disjoint_or_equal(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
194203
indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
195-
indels
196-
.iter()
197-
.zip(indels.iter().skip(1))
198-
.all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start())
204+
indels.iter().zip(indels.iter().skip(1)).all(|(l, r)| {
205+
let l = l.borrow();
206+
let r = r.borrow();
207+
l.delete.end() <= r.delete.start() || l == r
208+
})
199209
}

0 commit comments

Comments
 (0)