Fix anchor-related panic when gathering applicable inlay chunks (#41002)

Kirill Bulatov created

Before, inlay chunks were retrieved from the cache based on actualized
anchor ranges, but using an old buffer snapshot. Now, update all chunks
and snapshot to the actual before returning the applicable ones.

Follow-up of https://github.com/zed-industries/zed/pull/40183

Release Notes:

- N/A

Change summary

crates/editor/src/editor.rs                  | 15 +++++++--------
crates/editor/src/inlays/inlay_hints.rs      |  6 +++++-
crates/editor/src/proposed_changes_editor.rs |  6 +++---
crates/project/src/lsp_store.rs              | 19 ++++++++-----------
4 files changed, 23 insertions(+), 23 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -22603,9 +22603,9 @@ pub trait SemanticsProvider {
 
     fn applicable_inlay_chunks(
         &self,
-        buffer_id: BufferId,
+        buffer: &Entity<Buffer>,
         ranges: &[Range<text::Anchor>],
-        cx: &App,
+        cx: &mut App,
     ) -> Vec<Range<BufferRow>>;
 
     fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
@@ -23112,14 +23112,13 @@ impl SemanticsProvider for Entity<Project> {
 
     fn applicable_inlay_chunks(
         &self,
-        buffer_id: BufferId,
+        buffer: &Entity<Buffer>,
         ranges: &[Range<text::Anchor>],
-        cx: &App,
+        cx: &mut App,
     ) -> Vec<Range<BufferRow>> {
-        self.read(cx)
-            .lsp_store()
-            .read(cx)
-            .applicable_inlay_chunks(buffer_id, ranges)
+        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
+            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
+        })
     }
 
     fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {

crates/editor/src/inlays/inlay_hints.rs 🔗

@@ -330,6 +330,7 @@ impl Editor {
             }
         };
 
+        let multi_buffer = self.buffer().clone();
         let Some(inlay_hints) = self.inlay_hints.as_mut() else {
             return;
         };
@@ -365,6 +366,9 @@ impl Editor {
 
         let all_affected_buffers = Arc::new(Mutex::new(all_affected_buffers));
         for (buffer_id, visible_excerpts) in buffers_to_query {
+            let Some(buffer) = multi_buffer.read(cx).buffer(buffer_id) else {
+                continue;
+            };
             let fetched_tasks = inlay_hints.hint_chunk_fetched.entry(buffer_id).or_default();
             if visible_excerpts
                 .buffer_version
@@ -376,7 +380,7 @@ impl Editor {
             }
 
             let applicable_chunks =
-                semantics_provider.applicable_inlay_chunks(buffer_id, &visible_excerpts.ranges, cx);
+                semantics_provider.applicable_inlay_chunks(&buffer, &visible_excerpts.ranges, cx);
 
             match inlay_hints
                 .hint_refresh_tasks

crates/editor/src/proposed_changes_editor.rs 🔗

@@ -436,11 +436,11 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
 
     fn applicable_inlay_chunks(
         &self,
-        buffer_id: BufferId,
+        buffer: &Entity<Buffer>,
         ranges: &[Range<text::Anchor>],
-        cx: &App,
+        cx: &mut App,
     ) -> Vec<Range<BufferRow>> {
-        self.0.applicable_inlay_chunks(buffer_id, ranges, cx)
+        self.0.applicable_inlay_chunks(buffer, ranges, cx)
     }
 
     fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {

crates/project/src/lsp_store.rs 🔗

@@ -6499,19 +6499,16 @@ impl LspStore {
     }
 
     pub fn applicable_inlay_chunks(
-        &self,
-        buffer_id: BufferId,
+        &mut self,
+        buffer: &Entity<Buffer>,
         ranges: &[Range<text::Anchor>],
+        cx: &mut Context<Self>,
     ) -> Vec<Range<BufferRow>> {
-        self.lsp_data
-            .get(&buffer_id)
-            .map(|data| {
-                data.inlay_hints
-                    .applicable_chunks(ranges)
-                    .map(|chunk| chunk.start..chunk.end)
-                    .collect()
-            })
-            .unwrap_or_default()
+        self.latest_lsp_data(buffer, cx)
+            .inlay_hints
+            .applicable_chunks(ranges)
+            .map(|chunk| chunk.start..chunk.end)
+            .collect()
     }
 
     pub fn invalidate_inlay_hints<'a>(