From a1925515e28e919e16972b48f2cebb7b507581ba Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Wed, 12 Aug 2020 23:45:52 -0400 Subject: [PATCH] Cherry-pick PR #40026 into release-4.0 (#40028) Component commits: 8f442baa3c Revert to including only open files in partial semantic server mode Co-authored-by: Sheetal Nandi --- src/compiler/program.ts | 18 ----- src/compiler/resolutionCache.ts | 53 +------------ src/compiler/types.ts | 3 - src/compiler/watchPublic.ts | 1 - src/server/editorServices.ts | 14 +--- src/server/project.ts | 16 +--- src/services/services.ts | 1 - src/services/types.ts | 1 - .../tsserver/partialSemanticServer.ts | 75 ++----------------- 9 files changed, 13 insertions(+), 169 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 87f4637258cb0..304f89f56c3ff 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -807,8 +807,6 @@ namespace ts { let mapFromFileToProjectReferenceRedirects: ESMap | undefined; let mapFromToProjectReferenceRedirectSource: ESMap | undefined; - let skippedTrippleSlashReferences: Set | undefined; - const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() && !options.disableSourceOfProjectReferenceRedirect; const { onProgramCreateComplete, fileExists, directoryExists } = updateHostForUseSourceOfProjectReferenceRedirect({ @@ -931,7 +929,6 @@ namespace ts { getSourceFiles: () => files, getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217 getRefFileMap: () => refFileMap, - getSkippedTrippleSlashReferences: () => skippedTrippleSlashReferences, getFilesByNameMap: () => filesByName, getCompilerOptions: () => options, getSyntacticDiagnostics, @@ -1275,7 +1272,6 @@ namespace ts { const oldSourceFiles = oldProgram.getSourceFiles(); const enum SeenPackageName { Exists, Modified } const seenPackageNames = new Map(); - const oldSkippedTrippleSlashReferences = oldProgram.getSkippedTrippleSlashReferences(); for (const oldSourceFile of oldSourceFiles) { let newSourceFile = host.getSourceFileByPath @@ -1348,11 +1344,6 @@ namespace ts { oldProgram.structureIsReused = StructureIsReused.SafeModules; } - if (oldSkippedTrippleSlashReferences?.has(oldSourceFile.path) && includeTripleslashReferencesFrom(newSourceFile)) { - // tripleslash reference resolution is now allowed - oldProgram.structureIsReused = StructureIsReused.SafeModules; - } - // check imports and module augmentations collectExternalModuleReferences(newSourceFile); if (!arrayIsEqualTo(oldSourceFile.imports, newSourceFile.imports, moduleNameIsEqualTo)) { @@ -1440,7 +1431,6 @@ namespace ts { missingFilePaths = oldProgram.getMissingFilePaths(); refFileMap = oldProgram.getRefFileMap(); - skippedTrippleSlashReferences = oldSkippedTrippleSlashReferences; // update fileName -> file mapping Debug.assert(newSourceFiles.length === oldProgram.getSourceFiles().length); @@ -2660,15 +2650,7 @@ namespace ts { return projectReferenceRedirects.get(projectReferencePath) || undefined; } - function includeTripleslashReferencesFrom(file: SourceFile) { - return !host.includeTripleslashReferencesFrom || host.includeTripleslashReferencesFrom(file.originalFileName); - } - function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) { - if (!includeTripleslashReferencesFrom(file)) { - (skippedTrippleSlashReferences ||= new Set()).add(file.path); - return; - } forEach(file.referencedFiles, (ref, index) => { const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName); processSourceFile( diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 725f94c7799ef..6848ecb4bc911 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -11,7 +11,6 @@ namespace ts { invalidateResolutionsOfFailedLookupLocations(): boolean; invalidateResolutionOfFile(filePath: Path): void; - removeRelativeNoResolveResolutionsOfFile(filePath: Path): boolean; removeResolutionsOfFile(filePath: Path): void; removeResolutionsFromProjectReferenceRedirects(filePath: Path): void; setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: ESMap): void; @@ -142,21 +141,7 @@ namespace ts { type GetResolutionWithResolvedFileName = (resolution: T) => R | undefined; - export enum ResolutionKind { - All, - RelativeReferencesInOpenFileOnly - } - - const noResolveResolvedModule: ResolvedModuleWithFailedLookupLocations = { - resolvedModule: undefined, - failedLookupLocations: [] - }; - const noResolveResolvedTypeReferenceDirective: ResolvedTypeReferenceDirectiveWithFailedLookupLocations = { - resolvedTypeReferenceDirective: undefined, - failedLookupLocations: [] - }; - - export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, resolutionKind: ResolutionKind, logChangesWhenResolvingModule: boolean): ResolutionCache { + export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, logChangesWhenResolvingModule: boolean): ResolutionCache { let filesWithChangedSetOfUnresolvedImports: Path[] | undefined; let filesWithInvalidatedResolutions: Set | undefined; let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyESMap | undefined; @@ -221,7 +206,6 @@ namespace ts { hasChangedAutomaticTypeDirectiveNames: () => hasChangedAutomaticTypeDirectiveNames, invalidateResolutionOfFile, invalidateResolutionsOfFailedLookupLocations, - removeRelativeNoResolveResolutionsOfFile, setFilesWithInvalidatedNonRelativeUnresolvedImports, createHasInvalidatedResolution, updateTypeRootsWatch, @@ -357,12 +341,11 @@ namespace ts { shouldRetryResolution: (t: T) => boolean; reusedNames?: readonly string[]; logChanges?: boolean; - noResolveResolution: T; } function resolveNamesWithLocalCache({ names, containingFile, redirectedReference, cache, perDirectoryCacheWithRedirects, - loader, getResolutionWithResolvedFileName, noResolveResolution, + loader, getResolutionWithResolvedFileName, shouldRetryResolution, reusedNames, logChanges }: ResolveNamesWithLocalCacheInput): (R | undefined)[] { const path = resolutionHost.toPath(containingFile); @@ -399,10 +382,7 @@ namespace ts { resolution = resolutionInDirectory; } else { - resolution = resolutionKind === ResolutionKind.All || - (isExternalModuleNameRelative(name) && resolutionHost.fileIsOpen(path)) ? - loader(name, containingFile, compilerOptions, resolutionHost.getCompilerHost?.() || resolutionHost, redirectedReference) : - noResolveResolution; + resolution = loader(name, containingFile, compilerOptions, resolutionHost.getCompilerHost?.() || resolutionHost, redirectedReference); perDirectoryResolution.set(name, resolution); } resolutionsInFile.set(name, resolution); @@ -461,7 +441,6 @@ namespace ts { loader: resolveTypeReferenceDirective, getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective, shouldRetryResolution: resolution => resolution.resolvedTypeReferenceDirective === undefined, - noResolveResolution: noResolveResolvedTypeReferenceDirective, }); } @@ -477,7 +456,6 @@ namespace ts { shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension), reusedNames, logChanges: logChangesWhenResolvingModule, - noResolveResolution: noResolveResolvedModule, }); } @@ -763,31 +741,6 @@ namespace ts { } } - function removeRelativeNoResolveResolutionsOfFileFromCache( - cache: ESMap>, - filePath: Path, - noResolveResolution: T, - ) { - Debug.assert(resolutionKind === ResolutionKind.RelativeReferencesInOpenFileOnly); - // Deleted file, stop watching failed lookups for all the resolutions in the file - const resolutions = cache.get(filePath); - if (!resolutions) return false; - let invalidated = false; - resolutions.forEach((resolution, name) => { - if (resolution === noResolveResolution && isExternalModuleNameRelative(name)) { - resolutions.delete(name); - invalidated = true; - } - }); - return invalidated; - } - - function removeRelativeNoResolveResolutionsOfFile(filePath: Path) { - let invalidated = removeRelativeNoResolveResolutionsOfFileFromCache(resolvedModuleNames, filePath, noResolveResolvedModule); - invalidated = removeRelativeNoResolveResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, noResolveResolvedTypeReferenceDirective) || invalidated; - return invalidated; - } - function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyESMap) { Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined); filesWithInvalidatedNonRelativeUnresolvedImports = filesMap; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d9468bd51234e..69d3e9b3d94d9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3687,8 +3687,6 @@ namespace ts { /* @internal */ getRefFileMap(): MultiMap | undefined; /* @internal */ - getSkippedTrippleSlashReferences(): Set | undefined; - /* @internal */ getFilesByNameMap(): ESMap; /** @@ -6232,7 +6230,6 @@ namespace ts { * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[]; - /* @internal */ includeTripleslashReferencesFrom?(containingFile: string): boolean; getEnvironmentVariable?(name: string): string | undefined; /* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void; /* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution; diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index e5f7cb60eddf1..2673b11681050 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -320,7 +320,6 @@ namespace ts { configFileName ? getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) : currentDirectory, - ResolutionKind.All, /*logChangesWhenResolvingModule*/ false ); // Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 28c49a8d4609c..d0b4891c96324 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -3029,15 +3029,7 @@ namespace ts.server { let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined; let projectForConfigFileDiag: ConfiguredProject | undefined; let defaultConfigProjectIsCreated = false; - if (this.serverMode === LanguageServiceMode.PartialSemantic) { - // Invalidate resolutions in the file since this file is now open - info.containingProjects.forEach(project => { - if (project.resolutionCache.removeRelativeNoResolveResolutionsOfFile(info.path)) { - project.markAsDirty(); - } - }); - } - else if (!project && this.serverMode === LanguageServiceMode.Semantic) { // Checking semantic mode is an optimization + if (!project && this.serverMode === LanguageServiceMode.Semantic) { // Checking semantic mode is an optimization configFileName = this.getConfigFileNameForFile(info); if (configFileName) { project = this.findConfiguredProjectByProjectName(configFileName); @@ -3124,10 +3116,6 @@ namespace ts.server { Debug.assert(this.openFiles.has(info.path)); this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path)); } - else if (this.serverMode === LanguageServiceMode.PartialSemantic && info.cacheSourceFile?.sourceFile.referencedFiles.length) { - // This file was just opened and references in this file will previously not been resolved so schedule update - info.containingProjects.forEach(project => project.markAsDirty()); - } Debug.assert(!info.isOrphan()); return { configFileName, configFileErrors, retainProjects }; } diff --git a/src/server/project.ts b/src/server/project.ts index 8727bdcad5d9e..0e4f937552ea8 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -285,6 +285,7 @@ namespace ts.server { break; case LanguageServiceMode.PartialSemantic: this.languageServiceEnabled = true; + this.compilerOptions.noResolve = true; this.compilerOptions.types = []; break; case LanguageServiceMode.Syntactic: @@ -310,7 +311,6 @@ namespace ts.server { this.resolutionCache = createResolutionCache( this, currentDirectory && this.currentDirectory, - projectService.serverMode === LanguageServiceMode.Semantic ? ResolutionKind.All : ResolutionKind.RelativeReferencesInOpenFileOnly, /*logChangesWhenResolvingModule*/ true ); this.languageService = createLanguageService(this, this.documentRegistry, this.projectService.serverMode); @@ -466,20 +466,6 @@ namespace ts.server { return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference); } - /*@internal*/ - includeTripleslashReferencesFrom(containingFile: string) { - switch (this.projectService.serverMode) { - case LanguageServiceMode.Semantic: - return true; - case LanguageServiceMode.PartialSemantic: - return this.fileIsOpen(this.toPath(containingFile)); - case LanguageServiceMode.Syntactic: - return false; - default: - Debug.assertNever(this.projectService.serverMode); - } - } - directoryExists(path: string): boolean { return this.directoryStructureHost.directoryExists!(path); // TODO: GH#18217 } diff --git a/src/services/services.ts b/src/services/services.ts index 74cc421134efd..b8300aba0c34c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1344,7 +1344,6 @@ namespace ts { onReleaseOldSourceFile, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, - includeTripleslashReferencesFrom: maybeBind(host, host.includeTripleslashReferencesFrom), trace: maybeBind(host, host.trace), resolveModuleNames: maybeBind(host, host.resolveModuleNames), resolveTypeReferenceDirectives: maybeBind(host, host.resolveTypeReferenceDirectives), diff --git a/src/services/types.ts b/src/services/types.ts index ce2ab14dcd164..b750de98f239a 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -272,7 +272,6 @@ namespace ts { resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[]; getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined; resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[]; - /* @internal */ includeTripleslashReferencesFrom?(containingFile: string): boolean; /* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution; /* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames; /* @internal */ diff --git a/src/testRunner/unittests/tsserver/partialSemanticServer.ts b/src/testRunner/unittests/tsserver/partialSemanticServer.ts index b8c6668d3c1e1..d821ccc1a36bb 100644 --- a/src/testRunner/unittests/tsserver/partialSemanticServer.ts +++ b/src/testRunner/unittests/tsserver/partialSemanticServer.ts @@ -1,5 +1,5 @@ namespace ts.projectSystem { - describe("unittests:: tsserver:: Semantic operations on Approximate Semantic only server", () => { + describe("unittests:: tsserver:: Semantic operations on PartialSemantic server", () => { function setup() { const file1: File = { path: `${tscWatch.projectRoot}/a.ts`, @@ -31,38 +31,18 @@ import { something } from "something"; } it("open files are added to inferred project even if config file is present and semantic operations succeed", () => { - const { host, session, file1, file2, file3, something } = setup(); + const { host, session, file1, file2 } = setup(); const service = session.getProjectService(); openFilesForSession([file1], session); checkNumberOfProjects(service, { inferredProjects: 1 }); const project = service.inferredProjects[0]; - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); // Relative import from open file is resolves but not non relative + checkProjectActualFiles(project, [libFile.path, file1.path]); // no imports are resolved verifyCompletions(); - verifyGoToDefToB(); openFilesForSession([file2], session); checkNumberOfProjects(service, { inferredProjects: 1 }); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path]); + checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); verifyCompletions(); - verifyGoToDefToB(); - verifyGoToDefToC(); - - openFilesForSession([file3], session); - checkNumberOfProjects(service, { inferredProjects: 1 }); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path]); - - openFilesForSession([something], session); - checkNumberOfProjects(service, { inferredProjects: 1 }); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]); - - // Close open files and verify resolutions - closeFilesForSession([file3], session); - checkNumberOfProjects(service, { inferredProjects: 1 }); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]); - - closeFilesForSession([file2], session); - checkNumberOfProjects(service, { inferredProjects: 1 }); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]); function verifyCompletions() { assert.isTrue(project.languageServiceEnabled); @@ -93,34 +73,6 @@ import { something } from "something"; source: undefined }; } - - function verifyGoToDefToB() { - const response = session.executeCommandSeq({ - command: protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(file1, "y") - }).response as protocol.DefinitionInfoAndBoundSpan; - assert.deepEqual(response, { - definitions: [{ - file: file2.path, - ...protocolTextSpanWithContextFromSubstring({ fileText: file2.content, text: "y", contextText: "export const y = 10;" }) - }], - textSpan: protocolTextSpanWithContextFromSubstring({ fileText: file1.content, text: "y" }) - }); - } - - function verifyGoToDefToC() { - const response = session.executeCommandSeq({ - command: protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(file1, "cc") - }).response as protocol.DefinitionInfoAndBoundSpan; - assert.deepEqual(response, { - definitions: [{ - file: file3.path, - ...protocolTextSpanWithContextFromSubstring({ fileText: file3.content, text: "cc", contextText: "export const cc = 10;" }) - }], - textSpan: protocolTextSpanWithContextFromSubstring({ fileText: file1.content, text: "cc" }) - }); - } }); it("throws on unsupported commands", () => { @@ -156,7 +108,7 @@ import { something } from "something"; }); it("should not include auto type reference directives", () => { - const { host, session, file1, file2 } = setup(); + const { host, session, file1 } = setup(); const atTypes: File = { path: `/node_modules/@types/somemodule/index.d.ts`, content: "export const something = 10;" @@ -166,7 +118,7 @@ import { something } from "something"; openFilesForSession([file1], session); checkNumberOfProjects(service, { inferredProjects: 1 }); const project = service.inferredProjects[0]; - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); // Should not contain atTypes + checkProjectActualFiles(project, [libFile.path, file1.path]); // Should not contain atTypes }); it("should not include referenced files from unopened files", () => { @@ -200,18 +152,7 @@ function fooB() { }` openFilesForSession([file1], session); checkNumberOfProjects(service, { inferredProjects: 1 }); const project = service.inferredProjects[0]; - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, something.path]); // Should not contains c - - openFilesForSession([file2], session); - checkNumberOfProjects(service, { inferredProjects: 1 }); - assert.isTrue(project.dirty); - project.updateGraph(); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]); - - closeFilesForSession([file2], session); - checkNumberOfProjects(service, { inferredProjects: 1 }); - assert.isFalse(project.dirty); - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, file3.path, something.path]); + checkProjectActualFiles(project, [libFile.path, file1.path]); // no resolve }); it("should not crash when external module name resolution is reused", () => { @@ -220,7 +161,7 @@ function fooB() { }` openFilesForSession([file1], session); checkNumberOfProjects(service, { inferredProjects: 1 }); const project = service.inferredProjects[0]; - checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); + checkProjectActualFiles(project, [libFile.path, file1.path]); // Close the file that contains non relative external module name and open some file that doesnt have non relative external module import closeFilesForSession([file1], session);