Skip to content

Commit 3e67cf4

Browse files
committed
Verify errors on transitively referenced files
1 parent 94df516 commit 3e67cf4

File tree

2 files changed

+69
-47
lines changed

2 files changed

+69
-47
lines changed

src/compiler/program.ts

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,6 @@ namespace ts {
635635
// Map storing if there is emit blocking diagnostics for given input
636636
const hasEmitBlockingDiagnostics = createMap<boolean>();
637637
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression | null | undefined;
638-
let _referencesArrayLiteralSyntax: ArrayLiteralExpression | null | undefined;
639638

640639
let moduleResolutionCache: ModuleResolutionCache | undefined;
641640
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference) => ResolvedModuleFull[];
@@ -1084,7 +1083,9 @@ namespace ts {
10841083
if (!canReuseProjectReferences()) {
10851084
return oldProgram.structureIsReused = StructureIsReused.Not;
10861085
}
1087-
resolvedProjectReferences = oldProgram.getResolvedProjectReferences();
1086+
if (projectReferences) {
1087+
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1088+
}
10881089

10891090
// check if program source files has changed in the way that can affect structure of the program
10901091
const newSourceFiles: SourceFile[] = [];
@@ -1827,11 +1828,22 @@ namespace ts {
18271828
fileProcessingDiagnostics.getGlobalDiagnostics(),
18281829
concatenate(
18291830
programDiagnostics.getGlobalDiagnostics(),
1830-
options.configFile ? programDiagnostics.getDiagnostics(options.configFile.fileName) : []
1831+
getOptionsDiagnosticsOfConfigFile()
18311832
)
18321833
));
18331834
}
18341835

1836+
function getOptionsDiagnosticsOfConfigFile() {
1837+
if (!options.configFile) { return emptyArray; }
1838+
let diagnostics = programDiagnostics.getDiagnostics(options.configFile.fileName);
1839+
forEachResolvedProjectReference(resolvedRef => {
1840+
if (resolvedRef) {
1841+
diagnostics = concatenate(diagnostics, programDiagnostics.getDiagnostics(resolvedRef.sourceFile.fileName));
1842+
}
1843+
});
1844+
return diagnostics;
1845+
}
1846+
18351847
function getGlobalDiagnostics(): Diagnostic[] {
18361848
return sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice());
18371849
}
@@ -2558,31 +2570,7 @@ namespace ts {
25582570
}
25592571
}
25602572

2561-
//TODO:: Errors on transitive references
2562-
if (projectReferences) {
2563-
for (let i = 0; i < projectReferences.length; i++) {
2564-
const ref = projectReferences[i];
2565-
const resolvedRefOpts = resolvedProjectReferences![i] && resolvedProjectReferences![i]!.commandLine.options;
2566-
if (resolvedRefOpts === undefined) {
2567-
createDiagnosticForReference(i, Diagnostics.File_0_not_found, ref.path);
2568-
continue;
2569-
}
2570-
if (!resolvedRefOpts.composite) {
2571-
createDiagnosticForReference(i, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
2572-
}
2573-
if (ref.prepend) {
2574-
const out = resolvedRefOpts.outFile || resolvedRefOpts.out;
2575-
if (out) {
2576-
if (!host.fileExists(out)) {
2577-
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
2578-
}
2579-
}
2580-
else {
2581-
createDiagnosticForReference(i, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path);
2582-
}
2583-
}
2584-
}
2585-
}
2573+
verifyProjectReferences();
25862574

25872575
// List of collected files is complete; validate exhautiveness if this is a project with a file list
25882576
if (options.composite) {
@@ -2800,6 +2788,32 @@ namespace ts {
28002788
}
28012789
}
28022790

2791+
function verifyProjectReferences() {
2792+
forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, index, parent) => {
2793+
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
2794+
const parentFile = parent && parent.sourceFile as JsonSourceFile;
2795+
if (!resolvedRef) {
2796+
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
2797+
return;
2798+
}
2799+
const options = resolvedRef.commandLine.options;
2800+
if (!options.composite) {
2801+
createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
2802+
}
2803+
if (ref.prepend) {
2804+
const out = options.outFile || options.out;
2805+
if (out) {
2806+
if (!host.fileExists(out)) {
2807+
createDiagnosticForReference(parentFile, index, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
2808+
}
2809+
}
2810+
else {
2811+
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path);
2812+
}
2813+
}
2814+
});
2815+
}
2816+
28032817
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0: string | number, arg1: string | number, arg2?: string | number) {
28042818
let needCompilerDiagnostic = true;
28052819
const pathsSyntax = getOptionPathsSyntax();
@@ -2856,10 +2870,11 @@ namespace ts {
28562870
createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0);
28572871
}
28582872

2859-
function createDiagnosticForReference(index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
2860-
const referencesSyntax = getProjectReferencesSyntax();
2873+
function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
2874+
const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"),
2875+
property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
28612876
if (referencesSyntax && referencesSyntax.elements.length > index) {
2862-
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, referencesSyntax.elements[index], message, arg0, arg1));
2877+
programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, arg0, arg1));
28632878
}
28642879
else {
28652880
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
@@ -2876,22 +2891,6 @@ namespace ts {
28762891
}
28772892
}
28782893

2879-
function getProjectReferencesSyntax(): ArrayLiteralExpression | null {
2880-
if (_referencesArrayLiteralSyntax === undefined) {
2881-
_referencesArrayLiteralSyntax = null; // tslint:disable-line:no-null-keyword
2882-
if (options.configFile) {
2883-
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(options.configFile)!; // TODO: GH#18217
2884-
for (const prop of getPropertyAssignment(jsonObjectLiteral, "references")) {
2885-
if (isArrayLiteralExpression(prop.initializer)) {
2886-
_referencesArrayLiteralSyntax = prop.initializer;
2887-
break;
2888-
}
2889-
}
2890-
}
2891-
}
2892-
return _referencesArrayLiteralSyntax;
2893-
}
2894-
28952894
function getCompilerOptionsObjectLiteralSyntax() {
28962895
if (_compilerOptionsObjectLiteralSyntax === undefined) {
28972896
_compilerOptionsObjectLiteralSyntax = null; // tslint:disable-line:no-null-keyword

src/testRunner/unittests/tsbuildWatchMode.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,29 @@ export function gfoo() {
657657
checkOutputErrorsIncremental(host, emptyArray);
658658
verifyProgram(host, watch);
659659
});
660+
661+
it("deleting transitively referenced config file", () => {
662+
const { host, watch } = createSolutionAndWatchMode();
663+
host.deleteFile(aTsconfig.path);
664+
665+
host.checkTimeoutQueueLengthAndRun(1);
666+
checkOutputErrorsIncremental(host, [
667+
"tsconfig.b.json(10,21): error TS6053: File '/user/username/projects/transitiveReferences/tsconfig.a.json' not found.\n"
668+
]);
669+
670+
checkProgramActualFiles(watch().getProgram(), expectedProgramFiles.map(s => s.replace(aDts, aTs.path)));
671+
verifyWatchesOfProject(host, expectedWatchedFiles.map(s => s.replace(aDts.toLowerCase(), aTs.path.toLocaleLowerCase())), expectedWatchedDirectoriesRecursive);
672+
verifyDependencies(watch, aTs.path, [aTs.path]);
673+
verifyDependencies(watch, bDts, [bDts, aTs.path]);
674+
verifyDependencies(watch, refs.path, [refs.path]);
675+
verifyDependencies(watch, cTs.path, [cTs.path, refs.path, bDts]);
676+
677+
// revert the update
678+
host.writeFile(aTsconfig.path, aTsconfig.content);
679+
host.checkTimeoutQueueLengthAndRun(1);
680+
checkOutputErrorsIncremental(host, emptyArray);
681+
verifyProgram(host, watch);
682+
});
660683
});
661684
});
662685
});

0 commit comments

Comments
 (0)