From bcbb19e06ebd0bbc2b1dde5f0ffe9840fdf23d23 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 24 Feb 2025 20:10:45 -0700 Subject: [PATCH] Fix leaked editor (#25530) Closes #ISSUE Release Notes: - Fixed a bug that would prevent rejoining projects sometimes --- crates/gpui/Cargo.toml | 3 ++- crates/gpui/src/app/entity_map.rs | 26 +++++++++---------- .../zed/src/zed/inline_completion_registry.rs | 2 +- crates/zeta/src/zeta.rs | 18 +++++-------- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 1ea6fba95e5726a0be8738678f3ea2929c4afc73..2ef7c5b2bc7715f49ace10b73795e5c9ff4bc89a 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [features] default = ["http_client", "font-kit", "wayland", "x11"] test-support = [ - "backtrace", + "leak-detection", "collections/test-support", "rand", "util/test-support", @@ -21,6 +21,7 @@ test-support = [ "wayland", "x11", ] +leak-detection = ["backtrace"] runtime_shaders = [] macos-blade = [ "blade-graphics", diff --git a/crates/gpui/src/app/entity_map.rs b/crates/gpui/src/app/entity_map.rs index afdb99b0586e958bd36c8f7b96ac5b2cb6f5721d..69037f9eef8e459243d635d829e6144cb2b9e627 100644 --- a/crates/gpui/src/app/entity_map.rs +++ b/crates/gpui/src/app/entity_map.rs @@ -19,7 +19,7 @@ use std::{ thread::panicking, }; -#[cfg(any(test, feature = "test-support"))] +#[cfg(any(test, feature = "leak-detection"))] use collections::HashMap; use super::Context; @@ -62,7 +62,7 @@ pub(crate) struct EntityMap { struct EntityRefCounts { counts: SlotMap, dropped_entity_ids: Vec, - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] leak_detector: LeakDetector, } @@ -74,7 +74,7 @@ impl EntityMap { ref_counts: Arc::new(RwLock::new(EntityRefCounts { counts: SlotMap::with_key(), dropped_entity_ids: Vec::new(), - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] leak_detector: LeakDetector { next_handle_id: 0, entity_handles: HashMap::default(), @@ -221,7 +221,7 @@ pub struct AnyEntity { pub(crate) entity_id: EntityId, pub(crate) entity_type: TypeId, entity_map: Weak>, - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] handle_id: HandleId, } @@ -231,7 +231,7 @@ impl AnyEntity { entity_id: id, entity_type, entity_map: entity_map.clone(), - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] handle_id: entity_map .upgrade() .unwrap() @@ -290,7 +290,7 @@ impl Clone for AnyEntity { entity_id: self.entity_id, entity_type: self.entity_type, entity_map: self.entity_map.clone(), - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] handle_id: self .entity_map .upgrade() @@ -319,7 +319,7 @@ impl Drop for AnyEntity { } } - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] if let Some(entity_map) = self.entity_map.upgrade() { entity_map .write() @@ -535,7 +535,7 @@ impl AnyWeakEntity { entity_id: self.entity_id, entity_type: self.entity_type, entity_map: self.entity_ref_counts.clone(), - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] handle_id: self .entity_ref_counts .upgrade() @@ -547,7 +547,7 @@ impl AnyWeakEntity { } /// Assert that entity referenced by this weak handle has been released. - #[cfg(any(test, feature = "test-support"))] + #[cfg(any(test, feature = "leak-detection"))] pub fn assert_released(&self) { self.entity_ref_counts .upgrade() @@ -710,23 +710,23 @@ impl PartialEq> for WeakEntity { } } -#[cfg(any(test, feature = "test-support"))] +#[cfg(any(test, feature = "leak-detection"))] static LEAK_BACKTRACE: std::sync::LazyLock = std::sync::LazyLock::new(|| std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty())); -#[cfg(any(test, feature = "test-support"))] +#[cfg(any(test, feature = "leak-detection"))] #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)] pub(crate) struct HandleId { id: u64, // id of the handle itself, not the pointed at object } -#[cfg(any(test, feature = "test-support"))] +#[cfg(any(test, feature = "leak-detection"))] pub(crate) struct LeakDetector { next_handle_id: u64, entity_handles: HashMap>>, } -#[cfg(any(test, feature = "test-support"))] +#[cfg(any(test, feature = "leak-detection"))] impl LeakDetector { #[track_caller] pub fn handle_created(&mut self, entity_id: EntityId) -> HandleId { diff --git a/crates/zed/src/zed/inline_completion_registry.rs b/crates/zed/src/zed/inline_completion_registry.rs index d6c3d2d7ef5472c769f11b75eb3a03987e352d0a..edd1624033a54027a6a5bd3bf7fdb89d84478fd5 100644 --- a/crates/zed/src/zed/inline_completion_registry.rs +++ b/crates/zed/src/zed/inline_completion_registry.rs @@ -267,7 +267,7 @@ fn assign_edit_prediction_provider( } let zeta = zeta::Zeta::register( - Some(cx.entity()), + editor.workspace().map(|w| w.downgrade()), worktree, client.clone(), user_store, diff --git a/crates/zeta/src/zeta.rs b/crates/zeta/src/zeta.rs index e6cda8e7e5f26e2056a0ae4b732e00a3558e0a62..7b91a5a09fe7de68bafd031cfedf4b47bffae159 100644 --- a/crates/zeta/src/zeta.rs +++ b/crates/zeta/src/zeta.rs @@ -9,7 +9,6 @@ mod rate_completion_modal; pub(crate) use completion_diff_element::*; use db::kvp::KEY_VALUE_STORE; -use editor::Editor; pub use init::*; use inline_completion::DataCollectionState; pub use license_detection::is_license_eligible_for_data_collection; @@ -24,7 +23,7 @@ use collections::{HashMap, HashSet, VecDeque}; use futures::AsyncReadExt; use gpui::{ actions, App, AppContext as _, AsyncApp, Context, Entity, EntityId, Global, SemanticVersion, - Subscription, Task, + Subscription, Task, WeakEntity, }; use http_client::{HttpClient, Method}; use input_excerpt::excerpt_for_cursor_position; @@ -186,7 +185,7 @@ impl std::fmt::Debug for InlineCompletion { } pub struct Zeta { - editor: Option>, + workspace: Option>, client: Arc, events: VecDeque, registered_buffers: HashMap, @@ -209,14 +208,14 @@ impl Zeta { } pub fn register( - editor: Option>, + workspace: Option>, worktree: Option>, client: Arc, user_store: Entity, cx: &mut App, ) -> Entity { let this = Self::global(cx).unwrap_or_else(|| { - let entity = cx.new(|cx| Self::new(editor, client, user_store, cx)); + let entity = cx.new(|cx| Self::new(workspace, client, user_store, cx)); cx.set_global(ZetaGlobal(entity.clone())); entity }); @@ -239,7 +238,7 @@ impl Zeta { } fn new( - editor: Option>, + workspace: Option>, client: Arc, user_store: Entity, cx: &mut Context, @@ -250,7 +249,7 @@ impl Zeta { let data_collection_choice = cx.new(|_| data_collection_choice); Self { - editor, + workspace, client, events: VecDeque::new(), shown_completions: VecDeque::new(), @@ -705,10 +704,7 @@ and then another can_collect_data: bool, cx: &mut Context, ) -> Task>> { - let workspace = self - .editor - .as_ref() - .and_then(|editor| editor.read(cx).workspace()); + let workspace = self.workspace.as_ref().and_then(|w| w.upgrade()); self.request_completion_impl( workspace, project,