Skip to content

Commit e7fc009

Browse files
committed
Prefer own references over indirect references when searching for resolved references
1 parent 31afb98 commit e7fc009

File tree

3 files changed

+158
-117
lines changed

3 files changed

+158
-117
lines changed

src/compiler/program.ts

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,11 @@ export function forEachResolvedProjectReference<T>(
11391139
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
11401140
cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined,
11411141
): T | undefined {
1142-
return forEachProjectReference(/*projectReferences*/ undefined, resolvedProjectReferences, (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent));
1142+
return forEachProjectReference(
1143+
/*projectReferences*/ undefined,
1144+
resolvedProjectReferences,
1145+
(resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent),
1146+
);
11431147
}
11441148

11451149
function forEachProjectReference<T>(
@@ -1149,7 +1153,6 @@ function forEachProjectReference<T>(
11491153
cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined,
11501154
): T | undefined {
11511155
let seenResolvedRefs: Set<Path> | undefined;
1152-
11531156
return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined);
11541157

11551158
function worker(
@@ -1162,19 +1165,26 @@ function forEachProjectReference<T>(
11621165
const result = cbRef(projectReferences, parent);
11631166
if (result) return result;
11641167
}
1165-
1166-
return forEach(resolvedProjectReferences, (resolvedRef, index) => {
1167-
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
1168-
// ignore recursives
1169-
return undefined;
1170-
}
1171-
1172-
const result = cbResolvedRef(resolvedRef, parent, index);
1173-
if (result || !resolvedRef) return result;
1174-
1175-
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
1176-
return worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef);
1177-
});
1168+
let skipChildren: Set<ResolvedProjectReference> | undefined;
1169+
return forEach(
1170+
resolvedProjectReferences,
1171+
(resolvedRef, index) => {
1172+
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
1173+
(skipChildren ??= new Set()).add(resolvedRef);
1174+
// ignore recursives
1175+
return undefined;
1176+
}
1177+
const result = cbResolvedRef(resolvedRef, parent, index);
1178+
if (result || !resolvedRef) return result;
1179+
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
1180+
},
1181+
) || forEach(
1182+
resolvedProjectReferences,
1183+
resolvedRef =>
1184+
resolvedRef && !skipChildren?.has(resolvedRef) ?
1185+
worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef) :
1186+
undefined,
1187+
);
11781188
}
11791189
}
11801190

@@ -1356,7 +1366,14 @@ export function isProgramUptoDate(
13561366
(seenResolvedRefs || (seenResolvedRefs = [])).push(oldResolvedRef);
13571367

13581368
// If child project references are upto date, this project reference is uptodate
1359-
return !forEach(oldResolvedRef.references, (childResolvedRef, index) => !resolvedProjectReferenceUptoDate(childResolvedRef, oldResolvedRef.commandLine.projectReferences![index]));
1369+
return !forEach(
1370+
oldResolvedRef.references,
1371+
(childResolvedRef, index) =>
1372+
!resolvedProjectReferenceUptoDate(
1373+
childResolvedRef,
1374+
oldResolvedRef.commandLine.projectReferences![index],
1375+
),
1376+
);
13601377
}
13611378

13621379
// In old program, not able to resolve project reference path,
@@ -4894,7 +4911,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
48944911
case FileIncludeKind.SourceFromProjectReference:
48954912
case FileIncludeKind.OutputFromProjectReference:
48964913
const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
4897-
const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined);
4914+
const referenceInfo = forEachProjectReference(
4915+
projectReferences,
4916+
resolvedProjectReferences,
4917+
(resolvedRef, parent, index) =>
4918+
resolvedRef === referencedResolvedRef ?
4919+
{ sourceFile: parent?.sourceFile || options.configFile!, index } :
4920+
undefined,
4921+
);
48984922
if (!referenceInfo) return undefined;
48994923
const { sourceFile, index } = referenceInfo;
49004924
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references", property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
@@ -4934,28 +4958,32 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
49344958

49354959
function verifyProjectReferences() {
49364960
const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined;
4937-
forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => {
4938-
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
4939-
const parentFile = parent && parent.sourceFile as JsonSourceFile;
4940-
verifyDeprecatedProjectReference(ref, parentFile, index);
4941-
if (!resolvedRef) {
4942-
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
4943-
return;
4944-
}
4945-
const options = resolvedRef.commandLine.options;
4946-
if (!options.composite || options.noEmit) {
4947-
// ok to not have composite if the current program is container only
4948-
const inputs = parent ? parent.commandLine.fileNames : rootNames;
4949-
if (inputs.length) {
4950-
if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
4951-
if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
4961+
forEachProjectReference(
4962+
projectReferences,
4963+
resolvedProjectReferences,
4964+
(resolvedRef, parent, index) => {
4965+
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
4966+
const parentFile = parent && parent.sourceFile as JsonSourceFile;
4967+
verifyDeprecatedProjectReference(ref, parentFile, index);
4968+
if (!resolvedRef) {
4969+
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
4970+
return;
49524971
}
4953-
}
4954-
if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
4955-
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
4956-
hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
4957-
}
4958-
});
4972+
const options = resolvedRef.commandLine.options;
4973+
if (!options.composite || options.noEmit) {
4974+
// ok to not have composite if the current program is container only
4975+
const inputs = parent ? parent.commandLine.fileNames : rootNames;
4976+
if (inputs.length) {
4977+
if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
4978+
if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
4979+
}
4980+
}
4981+
if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
4982+
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
4983+
hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
4984+
}
4985+
},
4986+
);
49594987
}
49604988

49614989
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {

src/server/editorServices.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -861,23 +861,36 @@ function forEachResolvedProjectReferenceProjectWorker<T>(
861861
seenResolvedRefs?: Map<string, ConfiguredProjectLoadKind>,
862862
): T | undefined {
863863
const loadKind = parentOptions.disableReferencedProjectLoad ? ConfiguredProjectLoadKind.Find : kind;
864-
return forEach(resolvedProjectReferences, ref => {
865-
if (!ref) return undefined;
866-
867-
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
868-
const canonicalPath = projectService.toCanonicalFileName(configFileName);
869-
const seenValue = seenResolvedRefs?.get(canonicalPath);
870-
if (seenValue !== undefined && seenValue >= loadKind) {
871-
return undefined;
872-
}
873-
const result = cb(ref, loadKind);
874-
if (result) {
875-
return result;
876-
}
877-
878-
(seenResolvedRefs || (seenResolvedRefs = new Map())).set(canonicalPath, loadKind);
879-
return ref.references && forEachResolvedProjectReferenceProjectWorker(ref.references, ref.commandLine.options, cb, loadKind, projectService, seenResolvedRefs);
880-
});
864+
let skipChildren: Set<ResolvedProjectReference> | undefined;
865+
return forEach(
866+
resolvedProjectReferences,
867+
ref => {
868+
if (!ref) return undefined;
869+
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
870+
const canonicalPath = projectService.toCanonicalFileName(configFileName);
871+
const seenValue = seenResolvedRefs?.get(canonicalPath);
872+
if (seenValue !== undefined && seenValue >= loadKind) {
873+
(skipChildren ??= new Set()).add(ref);
874+
return undefined;
875+
}
876+
const result = cb(ref, loadKind);
877+
if (result) return result;
878+
(seenResolvedRefs ??= new Map()).set(canonicalPath, loadKind);
879+
},
880+
) || forEach(
881+
resolvedProjectReferences,
882+
ref =>
883+
ref?.references && !skipChildren?.has(ref) ?
884+
forEachResolvedProjectReferenceProjectWorker(
885+
ref.references,
886+
ref.commandLine.options,
887+
cb,
888+
loadKind,
889+
projectService,
890+
seenResolvedRefs,
891+
) :
892+
undefined,
893+
);
881894
}
882895

883896
function forEachPotentialProjectReference<T>(

0 commit comments

Comments
 (0)