Skip to content

Commit 247a983

Browse files
authored
In project, instead of iterating over program files to determine if file needs to be detached, do it through existing mechanism of releasing oldSourceFile (#59181)
1 parent eb23677 commit 247a983

File tree

8 files changed

+47
-45
lines changed

8 files changed

+47
-45
lines changed

src/compiler/program.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,13 +1860,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
18601860
// old file wasn't redirect but new file is
18611861
(oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path)
18621862
) {
1863-
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path));
1863+
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path), newFile);
18641864
}
18651865
}
18661866
if (!host.getParsedCommandLine) {
18671867
oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
18681868
if (!getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
1869-
host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false);
1869+
host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false, /*newSourceFileByResolvedPath*/ undefined);
18701870
}
18711871
});
18721872
}

src/compiler/resolutionCache.ts

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export interface ResolutionCache {
141141

142142
invalidateResolutionsOfFailedLookupLocations(): boolean;
143143
invalidateResolutionOfFile(filePath: Path): void;
144-
removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean): void;
144+
removeResolutionsOfFile(filePath: Path): void;
145145
removeResolutionsFromProjectReferenceRedirects(filePath: Path): void;
146146
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: Map<Path, readonly string[]>): void;
147147
createHasInvalidatedResolutions(
@@ -1273,7 +1273,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
12731273
else if (packageDirWatcher.isSymlink !== isSymlink) {
12741274
// Handle the change
12751275
packageDirWatcher.dirPathToWatcher.forEach(watcher => {
1276-
removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath, /*syncDirWatcherRemove*/ false);
1276+
removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath);
12771277
watcher.watcher = createDirPathToWatcher();
12781278
});
12791279
packageDirWatcher.isSymlink = isSymlink;
@@ -1329,7 +1329,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
13291329
return dirWatcher;
13301330
}
13311331

1332-
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean, syncDirWatcherRemove: boolean | undefined) {
1332+
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean) {
13331333
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
13341334
const toWatch = getDirectoryToWatchFailedLookupLocation(
13351335
failedLookupLocation,
@@ -1350,7 +1350,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
13501350
const forDirPath = packageDirWatcher.dirPathToWatcher.get(dirPath)!;
13511351
forDirPath.refCount--;
13521352
if (forDirPath.refCount === 0) {
1353-
removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath, syncDirWatcherRemove);
1353+
removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath);
13541354
packageDirWatcher.dirPathToWatcher.delete(dirPath);
13551355
if (packageDirWatcher.isSymlink) {
13561356
const refCount = dirPathToSymlinkPackageRefCount.get(dirPath)! - 1;
@@ -1361,11 +1361,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
13611361
dirPathToSymlinkPackageRefCount.set(dirPath, refCount);
13621362
}
13631363
}
1364-
if (syncDirWatcherRemove) closePackageDirWatcher(packageDirWatcher, packageDirPath);
13651364
}
13661365
}
13671366
else {
1368-
removeDirectoryWatcher(dirPath, syncDirWatcherRemove);
1367+
removeDirectoryWatcher(dirPath);
13691368
}
13701369
}
13711370
return removeAtRoot;
@@ -1375,7 +1374,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
13751374
resolution: T,
13761375
filePath: Path,
13771376
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
1378-
syncDirWatcherRemove?: boolean,
13791377
) {
13801378
Debug.checkDefined(resolution.files).delete(filePath);
13811379
if (resolution.files!.size) return;
@@ -1392,11 +1390,11 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
13921390
let removeAtRoot = false;
13931391
if (failedLookupLocations) {
13941392
for (const failedLookupLocation of failedLookupLocations) {
1395-
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot, syncDirWatcherRemove);
1393+
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot);
13961394
}
13971395
}
1398-
if (alternateResult) removeAtRoot = stopWatchFailedLookupLocation(alternateResult, removeAtRoot, syncDirWatcherRemove);
1399-
if (removeAtRoot) removeDirectoryWatcher(rootPath, syncDirWatcherRemove);
1396+
if (alternateResult) removeAtRoot = stopWatchFailedLookupLocation(alternateResult, removeAtRoot);
1397+
if (removeAtRoot) removeDirectoryWatcher(rootPath);
14001398
}
14011399
else if (affectingLocations?.length) {
14021400
resolutionsWithOnlyAffectingLocations.delete(resolution);
@@ -1406,16 +1404,14 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
14061404
for (const affectingLocation of affectingLocations) {
14071405
const watcher = fileWatchesOfAffectingLocations.get(affectingLocation)!;
14081406
watcher.resolutions--;
1409-
if (syncDirWatcherRemove) closeFileWatcherOfAffectingLocation(watcher, affectingLocation);
14101407
}
14111408
}
14121409
}
14131410

1414-
function removeDirectoryWatcher(dirPath: Path, syncDirWatcherRemove: boolean | undefined) {
1411+
function removeDirectoryWatcher(dirPath: Path) {
14151412
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath)!;
14161413
// Do not close the watcher yet since it might be needed by other failed lookup locations.
14171414
dirWatcher.refCount--;
1418-
if (syncDirWatcherRemove) closeDirectoryWatchesOfFailedLookup(dirWatcher, dirPath);
14191415
}
14201416

14211417
function createDirectoryWatcher(directory: string, dirPath: Path, nonRecursive: boolean | undefined) {
@@ -1434,7 +1430,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
14341430
cache: Map<string, ModeAwareCache<T>>,
14351431
filePath: Path,
14361432
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
1437-
syncDirWatcherRemove: boolean | undefined,
14381433
) {
14391434
// Deleted file, stop watching failed lookups for all the resolutions in the file
14401435
const resolutions = cache.get(filePath);
@@ -1444,7 +1439,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
14441439
resolution,
14451440
filePath,
14461441
getResolutionWithResolvedFileName,
1447-
syncDirWatcherRemove,
14481442
)
14491443
);
14501444
cache.delete(filePath);
@@ -1465,9 +1459,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
14651459
resolvedProjectReference.commandLine.fileNames.forEach(f => removeResolutionsOfFile(resolutionHost.toPath(f)));
14661460
}
14671461

1468-
function removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean) {
1469-
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModuleFromResolution, syncDirWatcherRemove);
1470-
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirectiveFromResolution, syncDirWatcherRemove);
1462+
function removeResolutionsOfFile(filePath: Path) {
1463+
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModuleFromResolution);
1464+
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirectiveFromResolution);
14711465
}
14721466

14731467
function invalidateResolutions(resolutions: Set<ResolutionWithFailedLookupLocations> | Map<string, ResolutionWithFailedLookupLocations> | undefined, canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean | undefined) {

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7963,7 +7963,7 @@ export interface CompilerHost extends ModuleResolutionHost {
79637963
*/
79647964
hasInvalidatedLibResolutions?(libFileName: string): boolean;
79657965
getEnvironmentVariable?(name: string): string | undefined;
7966-
/** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void;
7966+
/** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined): void;
79677967
/** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void;
79687968
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
79697969
hasInvalidatedResolutions?(filePath: Path): boolean;

src/server/project.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,24 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
13931393
this.hasAddedOrRemovedSymlinks = true;
13941394
}
13951395

1396+
/** @internal */
1397+
onReleaseOldSourceFile(
1398+
oldSourceFile: SourceFile,
1399+
_oldOptions: CompilerOptions,
1400+
hasSourceFileByPath: boolean,
1401+
newSourceFileByResolvedPath: SourceFile | undefined,
1402+
) {
1403+
if (
1404+
!newSourceFileByResolvedPath ||
1405+
(oldSourceFile.resolvedPath === oldSourceFile.path && newSourceFileByResolvedPath.resolvedPath !== oldSourceFile.path)
1406+
) {
1407+
// new program does not contain this file - detach it from the project
1408+
// - remove resolutions only if the new program doesnt contain source file by the path
1409+
// (not resolvedPath since path is used for resolution)
1410+
this.detachScriptInfoFromProject(oldSourceFile.fileName, hasSourceFileByPath);
1411+
}
1412+
}
1413+
13961414
/** @internal */
13971415
updateFromProjectInProgress = false;
13981416

@@ -1639,22 +1657,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
16391657
let hasNewProgram = false;
16401658
if (this.program && (!oldProgram || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely))) {
16411659
hasNewProgram = true;
1642-
if (oldProgram) {
1643-
for (const f of oldProgram.getSourceFiles()) {
1644-
const newFile = this.program.getSourceFileByPath(f.resolvedPath);
1645-
if (!newFile || (f.resolvedPath === f.path && newFile.resolvedPath !== f.path)) {
1646-
// new program does not contain this file - detach it from the project
1647-
// - remove resolutions only if the new program doesnt contain source file by the path (not resolvedPath since path is used for resolution)
1648-
this.detachScriptInfoFromProject(f.fileName, !!this.program.getSourceFileByPath(f.path), /*syncDirWatcherRemove*/ true);
1649-
}
1650-
}
1651-
1652-
oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
1653-
if (!this.program!.getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
1654-
this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName, /*noRemoveResolution*/ undefined, /*syncDirWatcherRemove*/ true);
1655-
}
1656-
});
1657-
}
16581660

16591661
// Update roots
16601662
this.rootFilesMap.forEach((value, path) => {
@@ -1791,12 +1793,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
17911793
this.projectService.sendPerformanceEvent(kind, durationMs);
17921794
}
17931795

1794-
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean, syncDirWatcherRemove?: boolean) {
1796+
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean) {
17951797
const scriptInfoToDetach = this.projectService.getScriptInfo(uncheckedFileName);
17961798
if (scriptInfoToDetach) {
17971799
scriptInfoToDetach.detachFromProject(this);
17981800
if (!noRemoveResolution) {
1799-
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path, syncDirWatcherRemove);
1801+
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path);
18001802
}
18011803
}
18021804
}

src/services/services.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,17 +1866,22 @@ export function createLanguageService(
18661866
host.onReleaseParsedCommandLine?.(configFileName, oldResolvedRef, oldOptions);
18671867
}
18681868
else if (oldResolvedRef) {
1869-
onReleaseOldSourceFile(oldResolvedRef.sourceFile, oldOptions);
1869+
releaseOldSourceFile(oldResolvedRef.sourceFile, oldOptions);
18701870
}
18711871
}
18721872

18731873
// Release any files we have acquired in the old program but are
18741874
// not part of the new program.
1875-
function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) {
1875+
function releaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) {
18761876
const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldOptions);
18771877
documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, oldSettingsKey, oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat);
18781878
}
18791879

1880+
function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined) {
1881+
releaseOldSourceFile(oldSourceFile, oldOptions);
1882+
host.onReleaseOldSourceFile?.(oldSourceFile, oldOptions, hasSourceFileByPath, newSourceFileByResolvedPath);
1883+
}
1884+
18801885
function getOrCreateSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined {
18811886
return getOrCreateSourceFileByPath(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), languageVersionOrOptions, onError, shouldCreateNewSourceFile);
18821887
}

src/services/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR
430430
/** @internal */ sendPerformanceEvent?(kind: PerformanceEvent["kind"], durationMs: number): void;
431431
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
432432
/** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void;
433+
/** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined): void;
433434
/** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache;
434435
/** @internal */ runWithTemporaryFileUpdate?(rootFile: string, updatedText: string, cb: (updatedProgram: Program, originalProgram: Program | undefined, updatedPastedText: SourceFile) => void): void;
435436
jsDocParsingMode?: JSDocParsingMode | undefined;

tests/baselines/reference/tsserver/moduleResolution/using-referenced-project-built.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,13 +879,13 @@ Info seq [hh:mm:ss:mss] ======== Module name 'package-aX' was not resolved. ===
879879
Info seq [hh:mm:ss:mss] Reusing resolution of module '@typescript/lib-es2021' from '/home/src/projects/project/packages/package-b/__lib_node_modules_lookup_lib.es2021.d.ts__.ts' of old program, it was not resolved.
880880
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /home/src/projects/project/packages/package-b/package-aX 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
881881
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /home/src/projects/project/packages/package-b/package-aX 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
882+
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
883+
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
882884
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-b/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
883885
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-b/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
884886
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/node_modules/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
885887
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/node_modules/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
886888
Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a/package.json 2000 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: File location affecting resolution
887-
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
888-
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations
889889
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /home/src/projects/project/packages/package-b/tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: true structureIsReused:: SafeModules Elapsed:: *ms
890890
Info seq [hh:mm:ss:mss] Project '/home/src/projects/project/packages/package-b/tsconfig.json' (Configured)
891891
Info seq [hh:mm:ss:mss] Files (2)

0 commit comments

Comments
 (0)