about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs12
-rw-r--r--src/tools/rust-analyzer/crates/span/src/map.rs26
2 files changed, 33 insertions, 5 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index f55082de674..79fdf75b7f7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -149,14 +149,14 @@ fn expand_macro_recur(
         expanded.text_range().len(),
         &expansion_span_map,
     );
-    Some(expand(sema, expanded, result_span_map, offset_in_original_node))
+    Some(expand(sema, expanded, result_span_map, u32::from(offset_in_original_node) as i32))
 }
 
 fn expand(
     sema: &Semantics<'_, RootDatabase>,
     expanded: SyntaxNode,
     result_span_map: &mut SpanMap<SyntaxContextId>,
-    offset_in_original_node: TextSize,
+    mut offset_in_original_node: i32,
 ) -> SyntaxNode {
     let children = expanded.descendants().filter_map(ast::Item::cast);
     let mut replacements = Vec::new();
@@ -166,8 +166,14 @@ fn expand(
             sema,
             &child,
             result_span_map,
-            offset_in_original_node + child.syntax().text_range().start(),
+            TextSize::new(
+                (offset_in_original_node + (u32::from(child.syntax().text_range().start()) as i32))
+                    as u32,
+            ),
         ) {
+            offset_in_original_node = offset_in_original_node
+                + (u32::from(new_node.text_range().len()) as i32)
+                - (u32::from(child.syntax().text_range().len()) as i32);
             // check if the whole original syntax is replaced
             if expanded == *child.syntax() {
                 return new_node;
diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs
index 2680e5036c4..f80de05ec65 100644
--- a/src/tools/rust-analyzer/crates/span/src/map.rs
+++ b/src/tools/rust-analyzer/crates/span/src/map.rs
@@ -13,6 +13,7 @@ use crate::{
 /// Maps absolute text ranges for the corresponding file to the relevant span data.
 #[derive(Debug, PartialEq, Eq, Clone, Hash)]
 pub struct SpanMap<S> {
+    /// The offset stored here is the *end* of the node.
     spans: Vec<(TextSize, SpanData<S>)>,
     /// Index of the matched macro arm on successful expansion for declarative macros.
     // FIXME: Does it make sense to have this here?
@@ -109,11 +110,32 @@ where
     ///
     /// The length of the replacement node needs to be `other_size`.
     pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap<S>) {
+        // I find the following diagram helpful to illustrate the bounds and why we use `<` or `<=`:
+        // --------------------------------------------------------------------
+        //   1   3   5   6   7   10    11          <-- offsets we store
+        // 0-1 1-3 3-5 5-6 6-7 7-10 10-11          <-- ranges these offsets refer to
+        //       3   ..      7                     <-- other_range
+        //         3-5 5-6 6-7                     <-- ranges we replace (len = 7-3 = 4)
+        //         ^^^^^^^^^^^ ^^^^^^^^^^
+        //           remove       shift
+        //   2   3   5   9                         <-- offsets we insert
+        // 0-2 2-3 3-5 5-9                         <-- ranges we insert (other_size = 9-0 = 9)
+        // ------------------------------------
+        //   1   3
+        // 0-1 1-3                                 <-- these remain intact
+        //           5   6   8   12
+        //         3-5 5-6 6-8 8-12                <-- we shift these by other_range.start() and insert them
+        //                             15    16
+        //                          12-15 15-16    <-- we shift these by other_size-other_range.len() = 9-4 = 5
+        // ------------------------------------
+        //   1   3   5   6   8   12    15    16    <-- final offsets we store
+        // 0-1 1-3 3-5 5-6 6-8 8-12 12-15 15-16    <-- final ranges
+
         self.spans.retain_mut(|(offset, _)| {
-            if other_range.contains(*offset) {
+            if other_range.start() < *offset && *offset <= other_range.end() {
                 false
             } else {
-                if *offset >= other_range.end() {
+                if *offset > other_range.end() {
                     *offset += other_size;
                     *offset -= other_range.len();
                 }