Skip to content

Commit c5b74db

Browse files
authored
Merge pull request #26200 from Microsoft/watchWithStrict
Refresh semantic diagnostics when compiler options affecting semantic diagnostics generation changes
2 parents 421730a + 7963022 commit c5b74db

File tree

6 files changed

+76
-4
lines changed

6 files changed

+76
-4
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/commandLineParser.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,41 +319,47 @@ namespace ts {
319319
{
320320
name: "noImplicitAny",
321321
type: "boolean",
322+
strictFlag: true,
322323
showInSimplifiedHelpView: true,
323324
category: Diagnostics.Strict_Type_Checking_Options,
324-
description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type,
325+
description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type
325326
},
326327
{
327328
name: "strictNullChecks",
328329
type: "boolean",
330+
strictFlag: true,
329331
showInSimplifiedHelpView: true,
330332
category: Diagnostics.Strict_Type_Checking_Options,
331333
description: Diagnostics.Enable_strict_null_checks
332334
},
333335
{
334336
name: "strictFunctionTypes",
335337
type: "boolean",
338+
strictFlag: true,
336339
showInSimplifiedHelpView: true,
337340
category: Diagnostics.Strict_Type_Checking_Options,
338341
description: Diagnostics.Enable_strict_checking_of_function_types
339342
},
340343
{
341344
name: "strictPropertyInitialization",
342345
type: "boolean",
346+
strictFlag: true,
343347
showInSimplifiedHelpView: true,
344348
category: Diagnostics.Strict_Type_Checking_Options,
345349
description: Diagnostics.Enable_strict_checking_of_property_initialization_in_classes
346350
},
347351
{
348352
name: "noImplicitThis",
349353
type: "boolean",
354+
strictFlag: true,
350355
showInSimplifiedHelpView: true,
351356
category: Diagnostics.Strict_Type_Checking_Options,
352357
description: Diagnostics.Raise_error_on_this_expressions_with_an_implied_any_type,
353358
},
354359
{
355360
name: "alwaysStrict",
356361
type: "boolean",
362+
strictFlag: true,
357363
showInSimplifiedHelpView: true,
358364
category: Diagnostics.Strict_Type_Checking_Options,
359365
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
@@ -363,27 +369,31 @@ namespace ts {
363369
{
364370
name: "noUnusedLocals",
365371
type: "boolean",
372+
affectsSemanticDiagnostics: true,
366373
showInSimplifiedHelpView: true,
367374
category: Diagnostics.Additional_Checks,
368375
description: Diagnostics.Report_errors_on_unused_locals,
369376
},
370377
{
371378
name: "noUnusedParameters",
372379
type: "boolean",
380+
affectsSemanticDiagnostics: true,
373381
showInSimplifiedHelpView: true,
374382
category: Diagnostics.Additional_Checks,
375383
description: Diagnostics.Report_errors_on_unused_parameters,
376384
},
377385
{
378386
name: "noImplicitReturns",
379387
type: "boolean",
388+
affectsSemanticDiagnostics: true,
380389
showInSimplifiedHelpView: true,
381390
category: Diagnostics.Additional_Checks,
382391
description: Diagnostics.Report_error_when_not_all_code_paths_in_function_return_a_value
383392
},
384393
{
385394
name: "noFallthroughCasesInSwitch",
386395
type: "boolean",
396+
affectsSemanticDiagnostics: true,
387397
showInSimplifiedHelpView: true,
388398
category: Diagnostics.Additional_Checks,
389399
description: Diagnostics.Report_errors_for_fallthrough_cases_in_switch_statement
@@ -455,12 +465,14 @@ namespace ts {
455465
{
456466
name: "allowSyntheticDefaultImports",
457467
type: "boolean",
468+
affectsSemanticDiagnostics: true,
458469
category: Diagnostics.Module_Resolution_Options,
459470
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking
460471
},
461472
{
462473
name: "esModuleInterop",
463474
type: "boolean",
475+
affectsSemanticDiagnostics: true,
464476
showInSimplifiedHelpView: true,
465477
category: Diagnostics.Module_Resolution_Options,
466478
description: Diagnostics.Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for_all_imports_Implies_allowSyntheticDefaultImports
@@ -640,6 +652,7 @@ namespace ts {
640652
{
641653
name: "noImplicitUseStrict",
642654
type: "boolean",
655+
affectsSemanticDiagnostics: true,
643656
category: Diagnostics.Advanced_Options,
644657
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output
645658
},
@@ -678,24 +691,28 @@ namespace ts {
678691
{
679692
name: "allowUnusedLabels",
680693
type: "boolean",
694+
affectsSemanticDiagnostics: true,
681695
category: Diagnostics.Advanced_Options,
682696
description: Diagnostics.Do_not_report_errors_on_unused_labels
683697
},
684698
{
685699
name: "allowUnreachableCode",
686700
type: "boolean",
701+
affectsSemanticDiagnostics: true,
687702
category: Diagnostics.Advanced_Options,
688703
description: Diagnostics.Do_not_report_errors_on_unreachable_code
689704
},
690705
{
691706
name: "suppressExcessPropertyErrors",
692707
type: "boolean",
708+
affectsSemanticDiagnostics: true,
693709
category: Diagnostics.Advanced_Options,
694710
description: Diagnostics.Suppress_excess_property_checks_for_object_literals,
695711
},
696712
{
697713
name: "suppressImplicitAnyIndexErrors",
698714
type: "boolean",
715+
affectsSemanticDiagnostics: true,
699716
category: Diagnostics.Advanced_Options,
700717
description: Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures,
701718
},
@@ -714,6 +731,7 @@ namespace ts {
714731
{
715732
name: "noStrictGenericChecks",
716733
type: "boolean",
734+
affectsSemanticDiagnostics: true,
717735
category: Diagnostics.Advanced_Options,
718736
description: Diagnostics.Disable_strict_checking_of_generic_signatures_in_function_types,
719737
},

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4546,6 +4546,8 @@ namespace ts {
45464546
isCommandLineOnly?: boolean;
45474547
showInSimplifiedHelpView?: boolean;
45484548
category?: DiagnosticMessage;
4549+
strictFlag?: true; // true if the option is one of the flag under strict
4550+
affectsSemanticDiagnostics?: true; // true if option affects semantic diagnostics
45494551
}
45504552

45514553
/* @internal */

src/compiler/utilities.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6978,6 +6978,15 @@ namespace ts {
69786978
return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag];
69796979
}
69806980

6981+
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) {
6982+
if (oldOptions === newOptions) {
6983+
return false;
6984+
}
6985+
6986+
return optionDeclarations.some(option => (!!option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) ||
6987+
(!!option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name]));
6988+
}
6989+
69816990
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
69826991
let seenAsterisk = false;
69836992
for (let i = 0; i < str.length; i++) {

src/testRunner/unittests/tscWatchMode.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,6 @@ namespace ts.tscWatch {
11411141
}
11421142

11431143
it("without outDir or outFile is specified", () => {
1144-
debugger;
11451144
verifyWithOptions({ module: ModuleKind.AMD }, ["file1.js", "src/file2.js"]);
11461145
});
11471146

@@ -1313,6 +1312,49 @@ export class B
13131312
// File a need not be rewritten
13141313
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
13151314
});
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+
});
13161358
});
13171359

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

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9333,7 +9333,7 @@ export function Test2() {
93339333
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
93349334
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
93359335
});
9336-
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 }); debugger;
9336+
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
93379337
verifyUserTsConfigProject(session);
93389338

93399339
// Navigate to the definition

0 commit comments

Comments
 (0)