From 68fca4eab6d57fe7967133776e6f12864f598e21 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 20 Feb 2021 09:28:57 -0700 Subject: [PATCH] Added "reportOverlappingOverload" diagnostic rule, splitting out a few checks that were previously in the "reportGeneralTypeIssue" rule. This allows for finer-grained control over these overload checks. --- docs/configuration.md | 3 +++ packages/pyright-internal/src/analyzer/checker.ts | 8 ++++---- .../pyright-internal/src/common/configOptions.ts | 15 +++++++++++++++ .../src/common/diagnosticRules.ts | 1 + .../src/tests/typeEvaluator2.test.ts | 9 ++++++++- packages/vscode-pyright/package.json | 11 +++++++++++ .../schemas/pyrightconfig.schema.json | 6 ++++++ 7 files changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 56784d1f6..3f88fc23f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -100,6 +100,8 @@ The following settings control pyright’s diagnostic output (warnings or errors **reportIncompatibleVariableOverride** [boolean or string, optional]: Generate or suppress diagnostics for class variable declarations that override a symbol of the same name in a base class with a type that is incompatible with the base class symbol type. The default value for this setting is 'none'. +**reportOverlappingOverload** [boolean or string, optional]: Generate or suppress diagnostics for function overloads that overlap in signature and obscure each other or have incompatible return types. + **reportInvalidStringEscapeSequence** [boolean or string, optional]: Generate or suppress diagnostics for invalid escape sequences used within string literals. The Python specification indicates that such sequences will generate a syntax error in future versions. The default value for this setting is 'warning'. **reportUnknownParameterType** [boolean or string, optional]: Generate or suppress diagnostics for input or return parameters for functions or methods that have an unknown type. The default value for this setting is 'none'. @@ -256,6 +258,7 @@ The following table lists the default severity levels for each diagnostic rule w | reportConstantRedefinition | "none" | "none" | "error" | | reportIncompatibleMethodOverride | "none" | "none" | "error" | | reportIncompatibleVariableOverride | "none" | "none" | "error" | +| reportOverlappingOverload | "none" | "none" | "none" | | reportInvalidStringEscapeSequence | "none" | "warning" | "error" | | reportUnknownParameterType | "none" | "none" | "error" | | reportUnknownArgumentType | "none" | "none" | "error" | diff --git a/packages/pyright-internal/src/analyzer/checker.ts b/packages/pyright-internal/src/analyzer/checker.ts index fcd43cab6..4ed9e4b0f 100644 --- a/packages/pyright-internal/src/analyzer/checker.ts +++ b/packages/pyright-internal/src/analyzer/checker.ts @@ -1039,8 +1039,8 @@ export class Checker extends ParseTreeWalker { const prevOverload = prevOverloads[i]; if (this._isOverlappingOverload(functionType, prevOverload)) { this._evaluator.addDiagnostic( - this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, - DiagnosticRule.reportGeneralTypeIssues, + this._fileInfo.diagnosticRuleSet.reportOverlappingOverload, + DiagnosticRule.reportOverlappingOverload, Localizer.Diagnostic.overlappingOverload().format({ name: node.name.value, obscured: prevOverloads.length + 1, @@ -1071,8 +1071,8 @@ export class Checker extends ParseTreeWalker { ) { const altNode = this._findNodeForOverload(node, prevOverload); this._evaluator.addDiagnostic( - this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, - DiagnosticRule.reportGeneralTypeIssues, + this._fileInfo.diagnosticRuleSet.reportOverlappingOverload, + DiagnosticRule.reportOverlappingOverload, Localizer.Diagnostic.overloadReturnTypeMismatch().format({ name: node.name.value, newIndex: prevOverloads.length + 1, diff --git a/packages/pyright-internal/src/common/configOptions.ts b/packages/pyright-internal/src/common/configOptions.ts index 2b8196ea0..e2d6c3650 100644 --- a/packages/pyright-internal/src/common/configOptions.ts +++ b/packages/pyright-internal/src/common/configOptions.ts @@ -174,6 +174,10 @@ export interface DiagnosticRuleSet { // the base class symbol of the same name? reportIncompatibleVariableOverride: DiagnosticLevel; + // Report function overloads that overlap in signature but have + // incompatible return types. + reportOverlappingOverload: DiagnosticLevel; + // Report usage of invalid escape sequences in string literals? reportInvalidStringEscapeSequence: DiagnosticLevel; @@ -289,6 +293,7 @@ export function getDiagLevelDiagnosticRules() { DiagnosticRule.reportConstantRedefinition, DiagnosticRule.reportIncompatibleMethodOverride, DiagnosticRule.reportIncompatibleVariableOverride, + DiagnosticRule.reportOverlappingOverload, DiagnosticRule.reportInvalidStringEscapeSequence, DiagnosticRule.reportUnknownParameterType, DiagnosticRule.reportUnknownArgumentType, @@ -355,6 +360,7 @@ export function getOffDiagnosticRuleSet(): DiagnosticRuleSet { reportConstantRedefinition: 'none', reportIncompatibleMethodOverride: 'none', reportIncompatibleVariableOverride: 'none', + reportOverlappingOverload: 'none', reportInvalidStringEscapeSequence: 'none', reportUnknownParameterType: 'none', reportUnknownArgumentType: 'none', @@ -417,6 +423,7 @@ export function getBasicDiagnosticRuleSet(): DiagnosticRuleSet { reportConstantRedefinition: 'none', reportIncompatibleMethodOverride: 'none', reportIncompatibleVariableOverride: 'none', + reportOverlappingOverload: 'none', reportInvalidStringEscapeSequence: 'warning', reportUnknownParameterType: 'none', reportUnknownArgumentType: 'none', @@ -479,6 +486,7 @@ export function getStrictDiagnosticRuleSet(): DiagnosticRuleSet { reportConstantRedefinition: 'error', reportIncompatibleMethodOverride: 'error', reportIncompatibleVariableOverride: 'error', + reportOverlappingOverload: 'none', reportInvalidStringEscapeSequence: 'error', reportUnknownParameterType: 'error', reportUnknownArgumentType: 'error', @@ -1022,6 +1030,13 @@ export class ConfigOptions { defaultSettings.reportIncompatibleVariableOverride ), + // Read the "reportOverlappingOverload" entry. + reportOverlappingOverload: this._convertDiagnosticLevel( + configObj.reportOverlappingOverload, + DiagnosticRule.reportOverlappingOverload, + defaultSettings.reportOverlappingOverload + ), + // Read the "reportInvalidStringEscapeSequence" entry. reportInvalidStringEscapeSequence: this._convertDiagnosticLevel( configObj.reportInvalidStringEscapeSequence, diff --git a/packages/pyright-internal/src/common/diagnosticRules.ts b/packages/pyright-internal/src/common/diagnosticRules.ts index daee552df..4ece1f9ac 100644 --- a/packages/pyright-internal/src/common/diagnosticRules.ts +++ b/packages/pyright-internal/src/common/diagnosticRules.ts @@ -43,6 +43,7 @@ export enum DiagnosticRule { reportConstantRedefinition = 'reportConstantRedefinition', reportIncompatibleMethodOverride = 'reportIncompatibleMethodOverride', reportIncompatibleVariableOverride = 'reportIncompatibleVariableOverride', + reportOverlappingOverload = 'reportOverlappingOverload', reportInvalidStringEscapeSequence = 'reportInvalidStringEscapeSequence', reportUnknownParameterType = 'reportUnknownParameterType', reportUnknownArgumentType = 'reportUnknownArgumentType', diff --git a/packages/pyright-internal/src/tests/typeEvaluator2.test.ts b/packages/pyright-internal/src/tests/typeEvaluator2.test.ts index 238c2cec4..9e522760b 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator2.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator2.test.ts @@ -868,7 +868,14 @@ test('Overload4', () => { }); test('Overload5', () => { - const analysisResults = TestUtils.typeAnalyzeSampleFiles(['overload5.py']); + const configOptions = new ConfigOptions('.'); + + // By default, reportOverlappingOverload is off. + let analysisResults = TestUtils.typeAnalyzeSampleFiles(['overload5.py'], configOptions); + TestUtils.validateResults(analysisResults, 0); + + configOptions.diagnosticRuleSet.reportOverlappingOverload = 'error'; + analysisResults = TestUtils.typeAnalyzeSampleFiles(['overload5.py'], configOptions); TestUtils.validateResults(analysisResults, 5); }); diff --git a/packages/vscode-pyright/package.json b/packages/vscode-pyright/package.json index 09f53028a..bdc6114de 100644 --- a/packages/vscode-pyright/package.json +++ b/packages/vscode-pyright/package.json @@ -411,6 +411,17 @@ "error" ] }, + "reportOverlappingOverload": { + "type": "string", + "description": "Diagnostics for function overloads that overlap in signature and obscure each other or have incompatible return types.", + "default": "none", + "enum": [ + "none", + "information", + "warning", + "error" + ] + }, "reportInvalidStringEscapeSequence": { "type": "string", "description": "Diagnostics for invalid escape sequences used within string literals. The Python specification indicates that such sequences will generate a syntax error in future versions.", diff --git a/packages/vscode-pyright/schemas/pyrightconfig.schema.json b/packages/vscode-pyright/schemas/pyrightconfig.schema.json index 49e4b8a64..718e394d7 100644 --- a/packages/vscode-pyright/schemas/pyrightconfig.schema.json +++ b/packages/vscode-pyright/schemas/pyrightconfig.schema.json @@ -285,6 +285,12 @@ "title": "Controls reporting of overrides in subclasses that redefine a variable in an incompatible way", "default": "none" }, + "reportOverlappingOverload": { + "$id": "#/properties/reportOverlappingOverload", + "$ref": "#/definitions/diagnostic", + "title": "Controls reporting of function overloads that overlap in signature and obscure each other or do not agree on return type", + "default": "none" + }, "reportInvalidStringEscapeSequence": { "$id": "#/properties/reportInvalidStringEscapeSequence", "$ref": "#/definitions/diagnostic",