Skip to content

Commit 4c22bf7

Browse files
author
Andy
authored
getEditsForFileRename: Do fresh module resolution instead of relying on cache (microsoft#24211)
* getEditsForFileRename: Do fresh module resolution instead of relying on cache * Add host.resolveModuleNameWithFailedLookupLocations method * Make host.resolveModuleNameWithFailedLookupLocations mandatory, and implement for Project * Add test, and no need to check host.fileExists * Change method name and always use cache * Update name in string
1 parent 3eb66da commit 4c22bf7

File tree

7 files changed

+56
-6
lines changed

7 files changed

+56
-6
lines changed

src/compiler/resolutionCache.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace ts {
66
finishRecordingFilesWithChangedResolutions(): Path[];
77

88
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined): ResolvedModuleFull[];
9+
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
910
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
1011

1112
invalidateResolutionOfFile(filePath: Path): void;
@@ -73,7 +74,7 @@ namespace ts {
7374
export const maxNumberOfFilesToIterateForInvalidation = 256;
7475

7576
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
76-
(resolution: T) => R;
77+
(resolution: T) => R | undefined;
7778

7879
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string, logChangesWhenResolvingModule: boolean): ResolutionCache {
7980
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
@@ -124,6 +125,7 @@ namespace ts {
124125
startCachingPerDirectoryResolution: clearPerDirectoryResolutions,
125126
finishCachingPerDirectoryResolution,
126127
resolveModuleNames,
128+
getResolvedModuleWithFailedLookupLocationsFromCache,
127129
resolveTypeReferenceDirectives,
128130
removeResolutionsOfFile,
129131
invalidateResolutionOfFile,
@@ -320,7 +322,7 @@ namespace ts {
320322
}
321323

322324
function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
323-
return resolveNamesWithLocalCache(
325+
return resolveNamesWithLocalCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolvedTypeReferenceDirective>(
324326
typeDirectiveNames, containingFile,
325327
resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives,
326328
resolveTypeReferenceDirective, getResolvedTypeReferenceDirective,
@@ -329,14 +331,19 @@ namespace ts {
329331
}
330332

331333
function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined): ResolvedModuleFull[] {
332-
return resolveNamesWithLocalCache(
334+
return resolveNamesWithLocalCache<ResolvedModuleWithFailedLookupLocations, ResolvedModuleFull>(
333335
moduleNames, containingFile,
334336
resolvedModuleNames, perDirectoryResolvedModuleNames,
335337
resolveModuleName, getResolvedModule,
336338
reusedNames, logChangesWhenResolvingModule
337339
);
338340
}
339341

342+
function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined {
343+
const cache = resolvedModuleNames.get(resolutionHost.toPath(containingFile));
344+
return cache && cache.get(moduleName);
345+
}
346+
340347
function isNodeModulesDirectory(dirPath: Path) {
341348
return endsWith(dirPath, "/node_modules");
342349
}

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8383,4 +8383,35 @@ new C();`
83838383
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
83848384
});
83858385
});
8386+
8387+
describe("tsserverProjectSystem getEditsForFileRename", () => {
8388+
it("works for host implementing 'resolveModuleNames' and 'getResolvedModuleWithFailedLookupLocationsFromCache'", () => {
8389+
const userTs: File = {
8390+
path: "/user.ts",
8391+
content: 'import { x } from "./old";',
8392+
};
8393+
8394+
const host = createServerHost([userTs]);
8395+
const projectService = createProjectService(host);
8396+
projectService.openClientFile(userTs.path);
8397+
const project = first(projectService.inferredProjects);
8398+
8399+
Debug.assert(!!project.resolveModuleNames);
8400+
8401+
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatOptions);
8402+
assert.deepEqual<ReadonlyArray<FileTextChanges>>(edits, [{
8403+
fileName: "/user.ts",
8404+
textChanges: [{
8405+
span: textSpanFromSubstring(userTs.content, "./old"),
8406+
newText: "./new",
8407+
}],
8408+
}]);
8409+
});
8410+
});
8411+
8412+
function textSpanFromSubstring(str: string, substring: string): TextSpan {
8413+
const start = str.indexOf(substring);
8414+
Debug.assert(start !== -1);
8415+
return createTextSpan(start, substring.length);
8416+
}
83868417
}

src/server/project.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,10 @@ namespace ts.server {
358358
return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames);
359359
}
360360

361+
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations {
362+
return this.resolutionCache.getResolvedModuleWithFailedLookupLocationsFromCache(moduleName, containingFile);
363+
}
364+
361365
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
362366
return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
363367
}

src/services/getEditsForFileRename.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace ts {
44
const pathUpdater = getPathUpdater(oldFilePath, newFilePath, host);
55
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
66
updateTsconfigFiles(program, changeTracker, oldFilePath, newFilePath);
7-
for (const { sourceFile, toUpdate } of getImportsToUpdate(program, oldFilePath)) {
7+
for (const { sourceFile, toUpdate } of getImportsToUpdate(program, oldFilePath, host)) {
88
const newPath = pathUpdater(isRef(toUpdate) ? toUpdate.fileName : toUpdate.text);
99
if (newPath !== undefined) {
1010
const range = isRef(toUpdate) ? toUpdate : createStringRange(toUpdate, sourceFile);
@@ -30,7 +30,7 @@ namespace ts {
3030
return "fileName" in toUpdate;
3131
}
3232

33-
function getImportsToUpdate(program: Program, oldFilePath: string): ReadonlyArray<ToUpdate> {
33+
function getImportsToUpdate(program: Program, oldFilePath: string, host: LanguageServiceHost): ReadonlyArray<ToUpdate> {
3434
const checker = program.getTypeChecker();
3535
const result: ToUpdate[] = [];
3636
for (const sourceFile of program.getSourceFiles()) {
@@ -44,7 +44,9 @@ namespace ts {
4444
// If it resolved to something already, ignore.
4545
if (checker.getSymbolAtLocation(importStringLiteral)) continue;
4646

47-
const resolved = program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName);
47+
const resolved = host.resolveModuleNames
48+
? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName)
49+
: program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName);
4850
if (resolved && contains(resolved.failedLookupLocations, oldFilePath)) {
4951
result.push({ sourceFile, toUpdate: importStringLiteral });
5052
}

src/services/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,11 @@ namespace ts {
207207
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
208208
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
209209
* host specific questions using 'getScriptSnapshot'.
210+
*
211+
* If this is implemented, `getResolvedModuleWithFailedLookupLocationsFromCache` should be too.
210212
*/
211213
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
214+
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
212215
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
213216
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
214217
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4477,6 +4477,7 @@ declare namespace ts {
44774477
fileExists?(path: string): boolean;
44784478
getTypeRootsVersion?(): number;
44794479
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
4480+
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
44804481
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
44814482
getDirectories?(directoryName: string): string[];
44824483
/**
@@ -7864,6 +7865,7 @@ declare namespace ts.server {
78647865
readFile(fileName: string): string | undefined;
78657866
fileExists(file: string): boolean;
78667867
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[];
7868+
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
78677869
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
78687870
directoryExists(path: string): boolean;
78697871
getDirectories(path: string): string[];

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4477,6 +4477,7 @@ declare namespace ts {
44774477
fileExists?(path: string): boolean;
44784478
getTypeRootsVersion?(): number;
44794479
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
4480+
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
44804481
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
44814482
getDirectories?(directoryName: string): string[];
44824483
/**

0 commit comments

Comments
 (0)