From c6ca96bdcf545b2d5e8f1f596cbba9b92deac023 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 3 Aug 2018 15:41:44 -0700 Subject: [PATCH 1/4] Removing debugger statements from tests --- src/testRunner/unittests/tscWatchMode.ts | 1 - src/testRunner/unittests/tsserverProjectSystem.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/testRunner/unittests/tscWatchMode.ts b/src/testRunner/unittests/tscWatchMode.ts index 8a3b732ad97..1456a621019 100644 --- a/src/testRunner/unittests/tscWatchMode.ts +++ b/src/testRunner/unittests/tscWatchMode.ts @@ -1141,7 +1141,6 @@ namespace ts.tscWatch { } it("without outDir or outFile is specified", () => { - debugger; verifyWithOptions({ module: ModuleKind.AMD }, ["file1.js", "src/file2.js"]); }); diff --git a/src/testRunner/unittests/tsserverProjectSystem.ts b/src/testRunner/unittests/tsserverProjectSystem.ts index c89d29ffc5b..04e34d5a898 100644 --- a/src/testRunner/unittests/tsserverProjectSystem.ts +++ b/src/testRunner/unittests/tsserverProjectSystem.ts @@ -9333,7 +9333,7 @@ export function Test2() { textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }), definitions: [protocolFileSpanFromSubstring(aTs, "fnA")], }); - checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 }); debugger; + checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 }); verifyUserTsConfigProject(session); // Navigate to the definition From d419968c0dcfa102e86709df5d1eee0dafceb01c Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 3 Aug 2018 16:27:25 -0700 Subject: [PATCH 2/4] Refresh semantic diagnostics when compiler options affecting semantic diagnostics generation changes Fixes #26195 --- src/compiler/builder.ts | 3 +- src/compiler/utilities.ts | 43 ++++++++++++++++++++++++ src/testRunner/unittests/tscWatchMode.ts | 43 ++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index e2d59975d04..f4a61267144 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -65,7 +65,8 @@ namespace ts { } state.changedFilesSet = createMap(); const useOldState = BuilderState.canReuseOldState(state.referencedMap, oldState); - const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile; + const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile && + !compilerOptionsAffectSemanticDiagnostics(compilerOptions, oldState!.program.getCompilerOptions()); if (useOldState) { // Verify the sanity of old state if (!oldState!.currentChangedFilePath) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 56ea3cace0c..dcc4f968f26 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6967,6 +6967,49 @@ namespace ts { return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag]; } + export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) { + if (oldOptions === newOptions) { + return false; + } + + return changedCompileOptionValueOf(newOptions, oldOptions, [ + "noImplicitReturns", + "strict", + "suppressExcessPropertyErrors", + "suppressImplicitAnyIndexErrors", + "noFallthroughCasesInSwitch", + "noStrictGenericChecks", + "noUnusedLocals", + "noUnusedParameters", + "noImplicitUseStrict" + ]) || changedStrictOptionValueOf(newOptions, oldOptions, [ + "noImplicitAny", + "noImplicitThis", + "strictNullChecks", + "strictFunctionTypes", + "strictPropertyInitialization", + "alwaysStrict" + ]); + } + + function changedStrictOptionValueOf(newOptions: CompilerOptions, oldOptions: CompilerOptions, flags: StrictOptionName[]) { + for (const flag of flags) { + if (getStrictOptionValue(newOptions, flag) !== getStrictOptionValue(oldOptions, flag)) { + return true; + } + } + return false; + } + + function changedCompileOptionValueOf(newOptions: CompilerOptions, oldOptions: CompilerOptions, optionKeys: (keyof CompilerOptions)[]) { + for (const optionKey of optionKeys) { + if (newOptions[optionKey] !== oldOptions[optionKey]) { + return true; + } + } + return false; + } + export function hasZeroOrOneAsteriskCharacter(str: string): boolean { let seenAsterisk = false; for (let i = 0; i < str.length; i++) { diff --git a/src/testRunner/unittests/tscWatchMode.ts b/src/testRunner/unittests/tscWatchMode.ts index 1456a621019..d91559c72fc 100644 --- a/src/testRunner/unittests/tscWatchMode.ts +++ b/src/testRunner/unittests/tscWatchMode.ts @@ -1312,6 +1312,49 @@ export class B // File a need not be rewritten assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs); }); + + it("updates errors when strictNullChecks changes", () => { + const currentDirectory = "/user/username/projects/myproject"; + const aFile: File = { + path: `${currentDirectory}/a.ts`, + content: `declare function foo(): null | { hello: any }; +foo().hello` + }; + const compilerOptions: CompilerOptions = { + }; + const config: File = { + path: `${currentDirectory}/tsconfig.json`, + content: JSON.stringify({ compilerOptions }) + }; + const files = [aFile, config, libFile]; + const host = createWatchedSystem(files, { currentDirectory }); + const watch = createWatchOfConfigFile("tsconfig.json", host); + checkProgramActualFiles(watch(), [aFile.path, libFile.path]); + checkOutputErrorsInitial(host, emptyArray); + const modifiedTimeOfAJs = host.getModifiedTime(`${currentDirectory}/a.js`); + compilerOptions.strictNullChecks = true; + host.writeFile(config.path, JSON.stringify({ compilerOptions })); + host.runQueuedTimeoutCallbacks(); + const expectedStrictNullErrors = [ + getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("foo()"), 5, Diagnostics.Object_is_possibly_null) + ]; + checkOutputErrorsIncremental(host, expectedStrictNullErrors); + // File a need not be rewritten + assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs); + compilerOptions.strict = true; + delete (compilerOptions.strictNullChecks); + host.writeFile(config.path, JSON.stringify({ compilerOptions })); + host.runQueuedTimeoutCallbacks(); + checkOutputErrorsIncremental(host, expectedStrictNullErrors); + // File a need not be rewritten + assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs); + delete (compilerOptions.strict); + host.writeFile(config.path, JSON.stringify({ compilerOptions })); + host.runQueuedTimeoutCallbacks(); + checkOutputErrorsIncremental(host, emptyArray); + // File a need not be rewritten + assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs); + }); }); describe("tsc-watch emit with outFile or out setting", () => { From 4475d81b9c7f5dfcbe7efaee8abb6eefe9254bb9 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 6 Aug 2018 14:54:57 -0700 Subject: [PATCH 3/4] Add flags on commandLineOption to indicate strictFlag or option affecting semanticDiagnostics --- src/compiler/commandLineParser.ts | 18 +++++++++++++++- src/compiler/types.ts | 2 ++ src/compiler/utilities.ts | 35 +++---------------------------- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 55f224caec4..9845ec76fd3 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -319,13 +319,15 @@ namespace ts { { name: "noImplicitAny", type: "boolean", + strictFlag: true, showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, - description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type, + description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type }, { name: "strictNullChecks", type: "boolean", + strictFlag: true, showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Enable_strict_null_checks @@ -333,6 +335,7 @@ namespace ts { { name: "strictFunctionTypes", type: "boolean", + strictFlag: true, showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Enable_strict_checking_of_function_types @@ -340,6 +343,7 @@ namespace ts { { name: "strictPropertyInitialization", type: "boolean", + strictFlag: true, showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Enable_strict_checking_of_property_initialization_in_classes @@ -347,6 +351,7 @@ namespace ts { { name: "noImplicitThis", type: "boolean", + strictFlag: true, showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Raise_error_on_this_expressions_with_an_implied_any_type, @@ -354,6 +359,7 @@ namespace ts { { name: "alwaysStrict", type: "boolean", + strictFlag: true, showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file @@ -363,6 +369,7 @@ namespace ts { { name: "noUnusedLocals", type: "boolean", + affectsSemanticDiagnostics: true, showInSimplifiedHelpView: true, category: Diagnostics.Additional_Checks, description: Diagnostics.Report_errors_on_unused_locals, @@ -370,6 +377,7 @@ namespace ts { { name: "noUnusedParameters", type: "boolean", + affectsSemanticDiagnostics: true, showInSimplifiedHelpView: true, category: Diagnostics.Additional_Checks, description: Diagnostics.Report_errors_on_unused_parameters, @@ -377,6 +385,7 @@ namespace ts { { name: "noImplicitReturns", type: "boolean", + affectsSemanticDiagnostics: true, showInSimplifiedHelpView: true, category: Diagnostics.Additional_Checks, description: Diagnostics.Report_error_when_not_all_code_paths_in_function_return_a_value @@ -384,6 +393,7 @@ namespace ts { { name: "noFallthroughCasesInSwitch", type: "boolean", + affectsSemanticDiagnostics: true, showInSimplifiedHelpView: true, category: Diagnostics.Additional_Checks, description: Diagnostics.Report_errors_for_fallthrough_cases_in_switch_statement @@ -640,6 +650,7 @@ namespace ts { { name: "noImplicitUseStrict", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Advanced_Options, description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output }, @@ -678,24 +689,28 @@ namespace ts { { name: "allowUnusedLabels", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Advanced_Options, description: Diagnostics.Do_not_report_errors_on_unused_labels }, { name: "allowUnreachableCode", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Advanced_Options, description: Diagnostics.Do_not_report_errors_on_unreachable_code }, { name: "suppressExcessPropertyErrors", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Advanced_Options, description: Diagnostics.Suppress_excess_property_checks_for_object_literals, }, { name: "suppressImplicitAnyIndexErrors", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Advanced_Options, description: Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures, }, @@ -714,6 +729,7 @@ namespace ts { { name: "noStrictGenericChecks", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Advanced_Options, description: Diagnostics.Disable_strict_checking_of_generic_signatures_in_function_types, }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f66c0c02e39..2fb504fef27 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4540,6 +4540,8 @@ namespace ts { isCommandLineOnly?: boolean; showInSimplifiedHelpView?: boolean; category?: DiagnosticMessage; + strictFlag?: true; // true if the option is one of the flag under strict + affectsSemanticDiagnostics?: true; // true if option affects semantic diagnostics } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index dcc4f968f26..77db371f701 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6972,38 +6972,9 @@ namespace ts { return false; } - return changedCompileOptionValueOf(newOptions, oldOptions, [ - "noImplicitReturns", - "strict", - "suppressExcessPropertyErrors", - "suppressImplicitAnyIndexErrors", - "noFallthroughCasesInSwitch", - "noStrictGenericChecks", - "noUnusedLocals", - "noUnusedParameters", - "noImplicitUseStrict" - ]) || changedStrictOptionValueOf(newOptions, oldOptions, [ - "noImplicitAny", - "noImplicitThis", - "strictNullChecks", - "strictFunctionTypes", - "strictPropertyInitialization", - "alwaysStrict" - ]); - } - - function changedStrictOptionValueOf(newOptions: CompilerOptions, oldOptions: CompilerOptions, flags: StrictOptionName[]) { - for (const flag of flags) { - if (getStrictOptionValue(newOptions, flag) !== getStrictOptionValue(oldOptions, flag)) { - return true; - } - } - return false; - } - - function changedCompileOptionValueOf(newOptions: CompilerOptions, oldOptions: CompilerOptions, optionKeys: (keyof CompilerOptions)[]) { - for (const optionKey of optionKeys) { - if (newOptions[optionKey] !== oldOptions[optionKey]) { + for (const option of optionDeclarations) { + if ((option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) || + (option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name])) { return true; } } From 796302294fffe130b94c75d41443a7f96894940f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 10 Aug 2018 14:44:44 -0700 Subject: [PATCH 4/4] Review feedback --- src/compiler/commandLineParser.ts | 2 ++ src/compiler/utilities.ts | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 9845ec76fd3..00920325721 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -465,12 +465,14 @@ namespace ts { { name: "allowSyntheticDefaultImports", type: "boolean", + affectsSemanticDiagnostics: true, category: Diagnostics.Module_Resolution_Options, description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking }, { name: "esModuleInterop", type: "boolean", + affectsSemanticDiagnostics: true, showInSimplifiedHelpView: true, category: Diagnostics.Module_Resolution_Options, description: Diagnostics.Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for_all_imports_Implies_allowSyntheticDefaultImports diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 77db371f701..97a71897f1f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6972,13 +6972,8 @@ namespace ts { return false; } - for (const option of optionDeclarations) { - if ((option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) || - (option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name])) { - return true; - } - } - return false; + return optionDeclarations.some(option => (!!option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) || + (!!option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name])); } export function hasZeroOrOneAsteriskCharacter(str: string): boolean {