From 0e2d399c493712289df4a22dea1817a060dc379d Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 29 Aug 2017 13:29:56 -0700 Subject: [PATCH] Don't crash when a JS file appears in an inferred context --- .../unittests/tsserverProjectSystem.ts | 28 +++++++++++++++++-- src/server/editorServices.ts | 2 +- src/services/documentRegistry.ts | 20 ++++++------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index fa0eef12919..c9a74310977 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1774,6 +1774,28 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path, file3.path]); }); + it("regression test for crash in acquireOrUpdateDocument", () => { + const tsFile = { + fileName: "/a/b/file1.ts", + path: "/a/b/file1.ts", + content: "" + }; + const jsFile = { + path: "/a/b/file1.js", + content: "var x = 10;", + fileName: "/a/b/file1.js", + scriptKind: "JS" as "JS" + }; + + const host = createServerHost([]); + const projectService = createProjectService(host); + projectService.applyChangesInOpenFiles([tsFile], [], []); + const projs = projectService.synchronizeProjectList([]); + projectService.findProject(projs[0].info.projectName).getLanguageService().getNavigationBarItems(tsFile.fileName); + projectService.synchronizeProjectList([projs[0].info]); + projectService.applyChangesInOpenFiles([jsFile], [], []); + }); + it("config file is deleted", () => { const file1 = { path: "/a/b/f1.ts", @@ -1874,7 +1896,7 @@ namespace ts.projectSystem { // Open HTML file projectService.applyChangesInOpenFiles( - /*openFiles*/ [{ fileName: file2.path, hasMixedContent: true, scriptKind: ScriptKind.JS, content: `var hello = "hello";` }], + /*openFiles*/[{ fileName: file2.path, hasMixedContent: true, scriptKind: ScriptKind.JS, content: `var hello = "hello";` }], /*changedFiles*/ undefined, /*closedFiles*/ undefined); @@ -1891,7 +1913,7 @@ namespace ts.projectSystem { projectService.applyChangesInOpenFiles( /*openFiles*/ undefined, /*changedFiles*/ undefined, - /*closedFiles*/ [file2.path]); + /*closedFiles*/[file2.path]); // HTML file is still included in project checkNumberOfProjects(projectService, { configuredProjects: 1 }); @@ -3322,7 +3344,7 @@ namespace ts.projectSystem { const error1Result = session.executeCommand(dTsFile1GetErrRequest).response; assert.isTrue(error1Result.length === 0); - const dTsFile2GetErrRequest = makeSessionRequest( + const dTsFile2GetErrRequest = makeSessionRequest( CommandNames.SemanticDiagnosticsSync, { file: dTsFile2.path } ); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 22a025ae68f..d849226a35b 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1648,7 +1648,7 @@ namespace ts.server { if (openFiles) { for (const file of openFiles) { const scriptInfo = this.getScriptInfo(file.fileName); - Debug.assert(!scriptInfo || !scriptInfo.isScriptOpen()); + Debug.assert(!scriptInfo || !scriptInfo.isScriptOpen(), "Script should not exist and not be open already"); const normalizedPath = scriptInfo ? scriptInfo.fileName : toNormalizedPath(file.fileName); this.openClientFileWithNormalizedPath(normalizedPath, file.content, tryConvertScriptKindName(file.scriptKind), file.hasMixedContent); } diff --git a/src/services/documentRegistry.ts b/src/services/documentRegistry.ts index bc01f2a96a6..0c3d4d1cb48 100644 --- a/src/services/documentRegistry.ts +++ b/src/services/documentRegistry.ts @@ -173,14 +173,12 @@ namespace ts { const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/ true); let entry = bucket.get(path); if (!entry) { - Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?"); - // Have never seen this file with these settings. Create a new source file for it. const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, compilationSettings.target, version, /*setNodeParents*/ false, scriptKind); entry = { sourceFile, - languageServiceRefCount: 0, + languageServiceRefCount: 1, owners: [] }; bucket.set(path, entry); @@ -193,15 +191,15 @@ namespace ts { entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot)); } - } - // If we're acquiring, then this is the first time this LS is asking for this document. - // Increase our ref count so we know there's another LS using the document. If we're - // not acquiring, then that means the LS is 'updating' the file instead, and that means - // it has already acquired the document previously. As such, we do not need to increase - // the ref count. - if (acquiring) { - entry.languageServiceRefCount++; + // If we're acquiring, then this is the first time this LS is asking for this document. + // Increase our ref count so we know there's another LS using the document. If we're + // not acquiring, then that means the LS is 'updating' the file instead, and that means + // it has already acquired the document previously. As such, we do not need to increase + // the ref count. + if (acquiring) { + entry.languageServiceRefCount++; + } } return entry.sourceFile;