From 1bf1209f7ea045602507cc3f5915c99142a6ebff Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 12 Jun 2017 16:31:49 -0700 Subject: [PATCH] Cleanup script infos that are not part of any project when the project is closed or inferred projects are refreshed Also dispose some pointers so that the closures get disposed with project and script infos --- src/harness/unittests/tsserverProjectSystem.ts | 3 ++- src/server/editorServices.ts | 18 +++++++++++++++--- src/server/lsHost.ts | 11 ++++++++--- src/server/project.ts | 11 +++++++++-- src/services/services.ts | 2 ++ 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 7a19aa9167f..37bc454d614 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -2205,8 +2205,9 @@ namespace ts.projectSystem { projectService.checkNumberOfProjects({}); for (const f of [f2, f3]) { + // There shouldnt be any script info as we closed the file that resulted in creation of it const scriptInfo = projectService.getScriptInfoForNormalizedPath(server.toNormalizedPath(f.path)); - assert.equal(scriptInfo.containingProjects.length, 0, `expect 0 containing projects for '${f.path}'`); + assert.equal(scriptInfo, undefined, `expected script info to be closed: '${f.path}'`); } }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 7c0e0a0fb92..ad237bc0337 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -827,10 +827,20 @@ namespace ts.server { this.assignScriptInfoToInferredProjectIfNecessary(f, /*addToListOfOpenFiles*/ false); } } + + // Cleanup script infos that are not open and not part of any project + this.deleteOrphanScriptInfoNotInAnyProject(); } - if (info.containingProjects.length === 0) { - // if there are not projects that include this script info - delete it - this.filenameToScriptInfo.remove(info.path); + } + + private deleteOrphanScriptInfoNotInAnyProject() { + for (const path of this.filenameToScriptInfo.getKeys()) { + const info = this.filenameToScriptInfo.get(path); + if (!info.isScriptOpen() && info.containingProjects.length === 0) { + // if there are not projects that include this script info - delete it + info.stopWatcher(); + this.filenameToScriptInfo.remove(info.path); + } } } @@ -1418,6 +1428,8 @@ namespace ts.server { for (const p of this.inferredProjects) { p.updateGraph(); } + + this.deleteOrphanScriptInfoNotInAnyProject(); this.printProjects(); } diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index ec655c545ea..79429737240 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -11,11 +11,11 @@ namespace ts.server { private filesWithChangedSetOfUnresolvedImports: Path[]; - private readonly resolveModuleName: typeof resolveModuleName; + private resolveModuleName: typeof resolveModuleName; readonly trace: (s: string) => void; readonly realpath?: (path: string) => string; - constructor(private readonly host: ServerHost, private readonly project: Project, private readonly cancellationToken: HostCancellationToken) { + constructor(private readonly host: ServerHost, private project: Project, private readonly cancellationToken: HostCancellationToken) { this.cancellationToken = new ThrottledCancellationToken(cancellationToken, project.projectService.throttleWaitMilliseconds); this.getCanonicalFileName = ts.createGetCanonicalFileName(this.host.useCaseSensitiveFileNames); @@ -47,6 +47,11 @@ namespace ts.server { } } + dispose() { + this.project = undefined; + this.resolveModuleName = undefined; + } + public startRecordingFilesWithChangedResolutions() { this.filesWithChangedSetOfUnresolvedImports = []; } @@ -238,4 +243,4 @@ namespace ts.server { this.compilationSettings = opt; } } -} \ No newline at end of file +} diff --git a/src/server/project.ts b/src/server/project.ts index be854f948ea..33b345af833 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -116,7 +116,7 @@ namespace ts.server { public languageServiceEnabled = true; - protected readonly lsHost: LSHost; + protected lsHost: LSHost; builder: Builder; /** @@ -297,9 +297,15 @@ namespace ts.server { this.rootFiles = undefined; this.rootFilesMap = undefined; this.program = undefined; + this.builder = undefined; + this.cachedUnresolvedImportsPerFile = undefined; + this.projectErrors = undefined; + this.lsHost.dispose(); + this.lsHost = undefined; // signal language service to release source files acquired from document registry this.languageService.dispose(); + this.languageService = undefined; } getCompilerOptions() { @@ -1043,6 +1049,7 @@ namespace ts.server { if (this.projectFileWatcher) { this.projectFileWatcher.close(); + this.projectFileWatcher = undefined; } if (this.typeRootsWatchers) { @@ -1132,4 +1139,4 @@ namespace ts.server { this.typeAcquisition = newTypeAcquisition; } } -} \ No newline at end of file +} diff --git a/src/services/services.ts b/src/services/services.ts index 9e17e9a45e1..7adce648a62 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1311,7 +1311,9 @@ namespace ts { if (program) { forEach(program.getSourceFiles(), f => documentRegistry.releaseDocument(f.fileName, program.getCompilerOptions())); + program = undefined; } + host = undefined; } /// Diagnostics