diff options
| author | Orkun Tokdemir <orkun.tokdemir@qt.io> | 2024-11-22 11:16:31 +0100 |
|---|---|---|
| committer | Orkun Tokdemir <orkun.tokdemir@qt.io> | 2024-11-28 10:06:06 +0000 |
| commit | 582654890f809cbea73c5a37758f847c1526ae73 (patch) | |
| tree | 56764af2fc9268b232c5cfa4d7032753dbc06e4e | |
| parent | cf43334de14a49e5ec419fcf25655821c5ba3da6 (diff) | |
Dispose event handlers and language client when the project is closed
Since event handlers are not disposed properly, they are still active
when the project is closed. This can cause those handlers to be called
after the project is closed, which can lead to errors.
* Dispose project managers inside `Deactivate()`
Change-Id: Idd7b8548f7c16c41c0e4fd7052fa7ae988678bc4
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
| -rw-r--r-- | qt-core/src/extension.ts | 1 | ||||
| -rw-r--r-- | qt-core/src/project.ts | 68 | ||||
| -rw-r--r-- | qt-cpp/src/project.ts | 73 | ||||
| -rw-r--r-- | qt-lib/src/project.ts | 4 | ||||
| -rw-r--r-- | qt-qml/src/project.ts | 2 | ||||
| -rw-r--r-- | qt-qml/src/qmlls.ts | 11 | ||||
| -rw-r--r-- | qt-ui/src/extension.ts | 1 | ||||
| -rw-r--r-- | qt-ui/src/project.ts | 7 |
8 files changed, 99 insertions, 68 deletions
diff --git a/qt-core/src/extension.ts b/qt-core/src/extension.ts index 7762444..5384c3e 100644 --- a/qt-core/src/extension.ts +++ b/qt-core/src/extension.ts @@ -74,6 +74,7 @@ export async function activate(context: vscode.ExtensionContext) { export function deactivate() { logger.info(`Deactivating ${EXTENSION_ID}`); telemetry.dispose(); + projectManager.dispose(); } export function initCoreValues() { diff --git a/qt-core/src/project.ts b/qt-core/src/project.ts index 5c5f4dc..0a354ca 100644 --- a/qt-core/src/project.ts +++ b/qt-core/src/project.ts @@ -35,6 +35,7 @@ export async function createCoreProject( // Project class represents a workspace folder in the extension. export class CoreProject implements Project { + private readonly _disposables: vscode.Disposable[] = []; private readonly _stateManager: WorkspaceStateManager; private _qtInstallationRoot: string | undefined; constructor( @@ -42,7 +43,7 @@ export class CoreProject implements Project { readonly _context: vscode.ExtensionContext ) { this._stateManager = new WorkspaceStateManager(_context, _folder); - this.watchWorkspaceFolderConfig(_context, _folder); + this.watchWorkspaceFolderConfig(_folder); } set qtInstallationRoot(value: string) { this._qtInstallationRoot = value; @@ -61,44 +62,41 @@ export class CoreProject implements Project { return this.stateManager.reset(); } - private watchWorkspaceFolderConfig( - context: vscode.ExtensionContext, - folder: vscode.WorkspaceFolder - ) { - context.subscriptions.push( - vscode.workspace.onDidChangeConfiguration( - (e: vscode.ConfigurationChangeEvent) => { - void e; - const previousQtInsRoot = this.stateManager.getQtInstallationRoot(); - const currentQtInsRoot = - CoreProjectManager.getWorkspaceFolderQtInsRoot(folder); - if (currentQtInsRoot !== previousQtInsRoot) { - void this.stateManager.setQtInstallationRoot(currentQtInsRoot); - onQtInsRootUpdated(currentQtInsRoot, folder); - } - const previousAdditionalQtPaths = - this.stateManager.getAdditionalQtPaths(); - const currentAdditionalQtPaths = - CoreProjectManager.getWorkspaceFolderAdditionalQtPaths(folder); + private watchWorkspaceFolderConfig(folder: vscode.WorkspaceFolder) { + const eventHandler = vscode.workspace.onDidChangeConfiguration( + (e: vscode.ConfigurationChangeEvent) => { + void e; + const previousQtInsRoot = this.stateManager.getQtInstallationRoot(); + const currentQtInsRoot = + CoreProjectManager.getWorkspaceFolderQtInsRoot(folder); + if (currentQtInsRoot !== previousQtInsRoot) { + void this.stateManager.setQtInstallationRoot(currentQtInsRoot); + onQtInsRootUpdated(currentQtInsRoot, folder); + } + const previousAdditionalQtPaths = + this.stateManager.getAdditionalQtPaths(); + const currentAdditionalQtPaths = + CoreProjectManager.getWorkspaceFolderAdditionalQtPaths(folder); - if ( - !isEqual( - currentAdditionalQtPaths.sort(), - previousAdditionalQtPaths.sort() - ) - ) { - void this.stateManager.setAdditionalQtPaths( - currentAdditionalQtPaths - ); - onAdditionalQtPathsUpdated(currentAdditionalQtPaths, folder); - } + if ( + !isEqual( + currentAdditionalQtPaths.sort(), + previousAdditionalQtPaths.sort() + ) + ) { + void this.stateManager.setAdditionalQtPaths(currentAdditionalQtPaths); + onAdditionalQtPathsUpdated(currentAdditionalQtPaths, folder); } - ) + } ); + this._disposables.push(eventHandler); } dispose() { logger.info('Disposing project:', this._folder.uri.fsPath); + for (const d of this._disposables) { + d.dispose(); + } } } @@ -108,14 +106,14 @@ export class CoreProjectManager extends ProjectManager<CoreProject> { constructor(override readonly context: vscode.ExtensionContext) { super(context, createCoreProject); this.globalStateManager = new GlobalStateManager(context); - this.watchGlobalConfig(context); + this.watchGlobalConfig(); this.onProjectAdded((project: CoreProject) => { logger.info('Adding project:', project.folder.uri.fsPath); }); } - private watchGlobalConfig(context: vscode.ExtensionContext) { - context.subscriptions.push( + private watchGlobalConfig() { + this._disposables.push( vscode.workspace.onDidChangeConfiguration( (e: vscode.ConfigurationChangeEvent) => { void e; diff --git a/qt-cpp/src/project.ts b/qt-cpp/src/project.ts index a7037a2..762d00f 100644 --- a/qt-cpp/src/project.ts +++ b/qt-cpp/src/project.ts @@ -34,6 +34,7 @@ export async function createCppProject( // Project class represents a workspace folder in the extension. export class CppProject implements Project { + private readonly _disposables: vscode.Disposable[] = []; private readonly _stateManager: WorkspaceStateManager; private readonly _cmakeProject: cmakeApi.Project | undefined; private _buildDir: string | undefined; @@ -48,34 +49,39 @@ export class CppProject implements Project { this._buildDir = buildDir; if (this._cmakeProject) { - this._cmakeProject.onSelectedConfigurationChanged( - async (configurationType: cmakeApi.ConfigurationType) => { - if (configurationType === cmakeApi.ConfigurationType.Kit) { - const kit = await getSelectedKit(this.folder); - const selectedKitPath = kit ? getQtInsRoot(kit) : undefined; - const message = new QtWorkspaceConfigMessage(this.folder); - message.config.set('selectedKitPath', selectedKitPath); + const onSelectedConfigurationChangedHandler = + this._cmakeProject.onSelectedConfigurationChanged( + async (configurationType: cmakeApi.ConfigurationType) => { + if (configurationType === cmakeApi.ConfigurationType.Kit) { + const kit = await getSelectedKit(this.folder); + const selectedKitPath = kit ? getQtInsRoot(kit) : undefined; + const message = new QtWorkspaceConfigMessage(this.folder); + message.config.set('selectedKitPath', selectedKitPath); - const selectedQtPaths = kit ? getQtPathsExe(kit) : undefined; - message.config.set('selectedQtPaths', selectedQtPaths); + const selectedQtPaths = kit ? getQtPathsExe(kit) : undefined; + message.config.set('selectedQtPaths', selectedQtPaths); + coreAPI?.update(message); + } + } + ); + const onCodeModelChangedHandler = this._cmakeProject.onCodeModelChanged( + async () => { + const prevbuildDir = this._buildDir; + const currentBuildDir = await this._cmakeProject?.getBuildDirectory(); + if (prevbuildDir !== currentBuildDir) { + logger.info( + 'Build directory changed:', + currentBuildDir ?? 'undefined' + ); + this._buildDir = currentBuildDir; + const message = new QtWorkspaceConfigMessage(this.folder); + message.config.set('buildDir', currentBuildDir); coreAPI?.update(message); } } ); - this._cmakeProject.onCodeModelChanged(async () => { - const prevbuildDir = this._buildDir; - const currentBuildDir = await this._cmakeProject?.getBuildDirectory(); - if (prevbuildDir !== currentBuildDir) { - logger.info( - 'Build directory changed:', - currentBuildDir ?? 'undefined' - ); - this._buildDir = currentBuildDir; - const message = new QtWorkspaceConfigMessage(this.folder); - message.config.set('buildDir', currentBuildDir); - coreAPI?.update(message); - } - }); + this._disposables.push(onCodeModelChangedHandler); + this._disposables.push(onSelectedConfigurationChangedHandler); } } @@ -91,6 +97,9 @@ export class CppProject implements Project { dispose() { logger.info('Disposing project:', this._folder.uri.fsPath); + for (const d of this._disposables) { + d.dispose(); + } } } @@ -98,13 +107,17 @@ export class CppProjectManager extends ProjectManager<CppProject> { constructor(override readonly context: vscode.ExtensionContext) { super(context, createCppProject); - this.onProjectAdded((project: CppProject) => { - logger.info('Adding project:', project.folder.uri.fsPath); - kitManager.addProject(project); - }); + this._disposables.push( + this.onProjectAdded((project: CppProject) => { + logger.info('Adding project:', project.folder.uri.fsPath); + kitManager.addProject(project); + }) + ); - this.onProjectRemoved((project: CppProject) => { - kitManager.removeProject(project); - }); + this._disposables.push( + this.onProjectRemoved((project: CppProject) => { + kitManager.removeProject(project); + }) + ); } } diff --git a/qt-lib/src/project.ts b/qt-lib/src/project.ts index 02f2ba6..5e37e4f 100644 --- a/qt-lib/src/project.ts +++ b/qt-lib/src/project.ts @@ -9,6 +9,7 @@ export interface Project { } export class ProjectManager<ProjectType extends Project> { + protected readonly _disposables: vscode.Disposable[] = []; projects = new Set<ProjectType>(); private readonly _addEmitter = new vscode.EventEmitter<ProjectType>(); private readonly _removeEmitter = new vscode.EventEmitter<ProjectType>(); @@ -99,5 +100,8 @@ export class ProjectManager<ProjectType extends Project> { project.dispose(); } this.projects.clear(); + for (const d of this._disposables) { + d.dispose(); + } } } diff --git a/qt-qml/src/project.ts b/qt-qml/src/project.ts index f896841..08eb7dd 100644 --- a/qt-qml/src/project.ts +++ b/qt-qml/src/project.ts @@ -101,6 +101,6 @@ export class QMLProject implements Project { } dispose() { logger.info('Disposing project:', this.folder.uri.fsPath); - void this.qmlls.stop(); + this.qmlls.dispose(); } } diff --git a/qt-qml/src/qmlls.ts b/qt-qml/src/qmlls.ts index dfa5423..1ffd2a5 100644 --- a/qt-qml/src/qmlls.ts +++ b/qt-qml/src/qmlls.ts @@ -112,17 +112,26 @@ export async function fetchAssetAndDecide(options?: { } export class Qmlls { + private readonly _disposables: vscode.Disposable[] = []; private readonly _importPaths = new Set<string>(); private _client: LanguageClient | undefined; private _channel: vscode.OutputChannel | undefined; private _buildDir: string | undefined; constructor(readonly _folder: vscode.WorkspaceFolder) { - vscode.workspace.onDidChangeConfiguration((event) => { + const eventHandler = vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration(QMLLS_CONFIG, _folder)) { void this.restart(); } }); + this._disposables.push(eventHandler); + } + dispose() { + for (const d of this._disposables) { + d.dispose(); + } + void this._client?.dispose(); + this._channel?.dispose(); } set buildDir(buildDir: string | undefined) { this._buildDir = buildDir; diff --git a/qt-ui/src/extension.ts b/qt-ui/src/extension.ts index f7e831a..265961a 100644 --- a/qt-ui/src/extension.ts +++ b/qt-ui/src/extension.ts @@ -94,6 +94,7 @@ export async function activate(context: vscode.ExtensionContext) { export function deactivate() { logger.info(`Deactivating ${EXTENSION_ID}`); telemetry.dispose(); + projectManager.dispose(); } function processMessage(message: QtWorkspaceConfigMessage) { diff --git a/qt-ui/src/project.ts b/qt-ui/src/project.ts index cb8bc43..2749f8e 100644 --- a/qt-ui/src/project.ts +++ b/qt-ui/src/project.ts @@ -27,6 +27,7 @@ export async function createUIProject( // Project class represents a workspace folder in the extension. export class UIProject implements Project { + private readonly _disposables: vscode.Disposable[] = []; private _workspaceType: QtWorkspaceType | undefined; private _binDir: string | undefined; private _designerClient: DesignerClient | undefined; @@ -52,7 +53,7 @@ export class UIProject implements Project { ); } } - vscode.workspace.onDidChangeConfiguration((event) => { + const eventHandler = vscode.workspace.onDidChangeConfiguration((event) => { if ( affectsConfig( event, @@ -87,6 +88,7 @@ export class UIProject implements Project { } } }); + this._disposables.push(eventHandler); } getQtCustomDesignerPath() { return untildify( @@ -184,5 +186,8 @@ export class UIProject implements Project { dispose() { this._designerServer.dispose(); this._designerClient?.dispose(); + for (const d of this._disposables) { + d.dispose(); + } } } |
