Skip to content

Commit d419968

Browse files
committed
Refresh semantic diagnostics when compiler options affecting semantic diagnostics generation changes
Fixes #26195
1 parent c6ca96b commit d419968

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

src/compiler/builder.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ namespace ts {
6565
}
6666
state.changedFilesSet = createMap<true>();
6767
const useOldState = BuilderState.canReuseOldState(state.referencedMap, oldState);
68-
const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile;
68+
const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile &&
69+
!compilerOptionsAffectSemanticDiagnostics(compilerOptions, oldState!.program.getCompilerOptions());
6970
if (useOldState) {
7071
// Verify the sanity of old state
7172
if (!oldState!.currentChangedFilePath) {

src/compiler/utilities.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6967,6 +6967,49 @@ namespace ts {
69676967
return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag];
69686968
}
69696969

6970+
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) {
6971+
if (oldOptions === newOptions) {
6972+
return false;
6973+
}
6974+
6975+
return changedCompileOptionValueOf(newOptions, oldOptions, [
6976+
"noImplicitReturns",
6977+
"strict",
6978+
"suppressExcessPropertyErrors",
6979+
"suppressImplicitAnyIndexErrors",
6980+
"noFallthroughCasesInSwitch",
6981+
"noStrictGenericChecks",
6982+
"noUnusedLocals",
6983+
"noUnusedParameters",
6984+
"noImplicitUseStrict"
6985+
]) || changedStrictOptionValueOf(newOptions, oldOptions, [
6986+
"noImplicitAny",
6987+
"noImplicitThis",
6988+
"strictNullChecks",
6989+
"strictFunctionTypes",
6990+
"strictPropertyInitialization",
6991+
"alwaysStrict"
6992+
]);
6993+
}
6994+
6995+
function changedStrictOptionValueOf(newOptions: CompilerOptions, oldOptions: CompilerOptions, flags: StrictOptionName[]) {
6996+
for (const flag of flags) {
6997+
if (getStrictOptionValue(newOptions, flag) !== getStrictOptionValue(oldOptions, flag)) {
6998+
return true;
6999+
}
7000+
}
7001+
return false;
7002+
}
7003+
7004+
function changedCompileOptionValueOf(newOptions: CompilerOptions, oldOptions: CompilerOptions, optionKeys: (keyof CompilerOptions)[]) {
7005+
for (const optionKey of optionKeys) {
7006+
if (newOptions[optionKey] !== oldOptions[optionKey]) {
7007+
return true;
7008+
}
7009+
}
7010+
return false;
7011+
}
7012+
69707013
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
69717014
let seenAsterisk = false;
69727015
for (let i = 0; i < str.length; i++) {

src/testRunner/unittests/tscWatchMode.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,49 @@ export class B
13121312
// File a need not be rewritten
13131313
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
13141314
});
1315+
1316+
it("updates errors when strictNullChecks changes", () => {
1317+
const currentDirectory = "/user/username/projects/myproject";
1318+
const aFile: File = {
1319+
path: `${currentDirectory}/a.ts`,
1320+
content: `declare function foo(): null | { hello: any };
1321+
foo().hello`
1322+
};
1323+
const compilerOptions: CompilerOptions = {
1324+
};
1325+
const config: File = {
1326+
path: `${currentDirectory}/tsconfig.json`,
1327+
content: JSON.stringify({ compilerOptions })
1328+
};
1329+
const files = [aFile, config, libFile];
1330+
const host = createWatchedSystem(files, { currentDirectory });
1331+
const watch = createWatchOfConfigFile("tsconfig.json", host);
1332+
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
1333+
checkOutputErrorsInitial(host, emptyArray);
1334+
const modifiedTimeOfAJs = host.getModifiedTime(`${currentDirectory}/a.js`);
1335+
compilerOptions.strictNullChecks = true;
1336+
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
1337+
host.runQueuedTimeoutCallbacks();
1338+
const expectedStrictNullErrors = [
1339+
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("foo()"), 5, Diagnostics.Object_is_possibly_null)
1340+
];
1341+
checkOutputErrorsIncremental(host, expectedStrictNullErrors);
1342+
// File a need not be rewritten
1343+
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
1344+
compilerOptions.strict = true;
1345+
delete (compilerOptions.strictNullChecks);
1346+
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
1347+
host.runQueuedTimeoutCallbacks();
1348+
checkOutputErrorsIncremental(host, expectedStrictNullErrors);
1349+
// File a need not be rewritten
1350+
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
1351+
delete (compilerOptions.strict);
1352+
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
1353+
host.runQueuedTimeoutCallbacks();
1354+
checkOutputErrorsIncremental(host, emptyArray);
1355+
// File a need not be rewritten
1356+
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
1357+
});
13151358
});
13161359

13171360
describe("tsc-watch emit with outFile or out setting", () => {

0 commit comments

Comments
 (0)