Skip to content

Commit d65cb21

Browse files
committed
Keep the original configured project alive created during findAllReferences
1 parent f3b0a2d commit d65cb21

File tree

3 files changed

+148
-41
lines changed

3 files changed

+148
-41
lines changed

src/server/editorServices.ts

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ namespace ts.server {
707707

708708
/* @internal */
709709
private forEachProject(cb: (project: Project) => void) {
710-
for (const p of this.inferredProjects) cb(p);
710+
this.inferredProjects.forEach(cb);
711711
this.configuredProjects.forEach(cb);
712712
this.externalProjects.forEach(cb);
713713
}
@@ -2110,19 +2110,34 @@ namespace ts.server {
21102110
if (!originalLocation) return undefined;
21112111

21122112
const { fileName } = originalLocation;
2113-
const originalScriptInfo = this.getScriptInfo(fileName);
2114-
if (originalScriptInfo && originalScriptInfo.containingProjects.length) {
2115-
return originalLocation;
2116-
}
2113+
if (!this.getScriptInfo(fileName) && !this.host.fileExists(fileName)) return undefined;
21172114

2118-
const info: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) };
2119-
const configFileName = this.getConfigFileNameForFile(info);
2115+
const originalFileInfo: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) };
2116+
const configFileName = this.getConfigFileNameForFile(originalFileInfo);
21202117
if (!configFileName) return undefined;
21212118

21222119
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
21232120
updateProjectIfDirty(configuredProject);
2121+
// Keep this configured project as referenced from project
2122+
addOriginalConfiguredProject(configuredProject);
2123+
2124+
const originalScriptInfo = this.getScriptInfo(fileName);
2125+
if (!originalScriptInfo || !originalScriptInfo.containingProjects.length) return undefined;
21242126

2125-
return configuredProject.containsFile(info.fileName) ? originalLocation : undefined;
2127+
// Add configured projects as referenced
2128+
originalScriptInfo.containingProjects.forEach(project => {
2129+
if (project.projectKind === ProjectKind.Configured) {
2130+
addOriginalConfiguredProject(project as ConfiguredProject);
2131+
}
2132+
});
2133+
return originalLocation;
2134+
2135+
function addOriginalConfiguredProject(originalProject: ConfiguredProject) {
2136+
if (!project.originalConfiguredProjects) {
2137+
project.originalConfiguredProjects = createMap<true>();
2138+
}
2139+
project.originalConfiguredProjects.set(originalProject.canonicalConfigFilePath, true);
2140+
}
21262141
}
21272142

21282143
/** @internal */
@@ -2185,14 +2200,9 @@ namespace ts.server {
21852200
}
21862201
Debug.assert(!info.isOrphan());
21872202

2188-
// Remove the configured projects that have zero references from open files.
21892203
// This was postponed from closeOpenFile to after opening next file,
21902204
// so that we can reuse the project if we need to right away
2191-
this.configuredProjects.forEach(project => {
2192-
if (!project.hasOpenRef()) {
2193-
this.removeProject(project);
2194-
}
2195-
});
2205+
this.removeOrphanConfiguredProjects();
21962206

21972207
// Remove orphan inferred projects now that we have reused projects
21982208
// We need to create a duplicate because we cant guarantee order after removal
@@ -2220,6 +2230,30 @@ namespace ts.server {
22202230
return { configFileName, configFileErrors };
22212231
}
22222232

2233+
private removeOrphanConfiguredProjects() {
2234+
const toRemoveConfiguredProjects = cloneMap(this.configuredProjects);
2235+
2236+
// Do not remove configured projects that are used as original projects of other
2237+
this.inferredProjects.forEach(markOriginalProjectsAsUsed);
2238+
this.externalProjects.forEach(markOriginalProjectsAsUsed);
2239+
this.configuredProjects.forEach(project => {
2240+
// If project has open ref (there are more than zero references from external project/open file), keep it alive as well as any project it references
2241+
if (project.hasOpenRef()) {
2242+
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
2243+
markOriginalProjectsAsUsed(project);
2244+
}
2245+
});
2246+
2247+
// Remove all the non marked projects
2248+
toRemoveConfiguredProjects.forEach(project => this.removeProject(project));
2249+
2250+
function markOriginalProjectsAsUsed(project: Project) {
2251+
if (!project.isOrphan() && project.originalConfiguredProjects) {
2252+
project.originalConfiguredProjects.forEach((_value, configuredProjectPath) => toRemoveConfiguredProjects.delete(configuredProjectPath));
2253+
}
2254+
}
2255+
}
2256+
22232257
private telemetryOnOpenFile(scriptInfo: ScriptInfo): void {
22242258
if (this.syntaxOnly || !this.eventHandler || !scriptInfo.isJavaScript() || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path)) {
22252259
return;

src/server/project.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ namespace ts.server {
158158
/*@internal*/
159159
typingFiles: SortedReadonlyArray<string> = emptyArray;
160160

161+
/*@internal*/
162+
originalConfiguredProjects: Map<true> | undefined;
163+
161164
private readonly cancellationToken: ThrottledCancellationToken;
162165

163166
public isNonTsProject() {

0 commit comments

Comments
 (0)