mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Extended reportCallInDefaultInitializer diagnostic check to disallow list, set or dict expressions in default argument expression.
This commit is contained in:
parent
209e9283ca
commit
14ad02575f
@ -130,7 +130,7 @@ The following settings control pyright’s diagnostic output (warnings or errors
|
||||
|
||||
**reportInvalidTypeVarUse** [boolean or string, optional]: Generate or suppress diagnostics when a TypeVar is used inappropriately (e.g. if a TypeVar appears only once) within a generic function signature. The default value for this setting is 'none'.
|
||||
|
||||
**reportCallInDefaultInitializer** [boolean or string, optional]: Generate or suppress diagnostics for function calls within a default value initialization expression. Such calls can mask expensive operations that are performed at module initialization time. The default value for this setting is 'none'.
|
||||
**reportCallInDefaultInitializer** [boolean or string, optional]: Generate or suppress diagnostics for function calls, list expressions, set expressions, or dictionary expressions within a default value initialization expression. Such calls can mask expensive operations that are performed at module initialization time. The default value for this setting is 'none'.
|
||||
|
||||
**reportUnnecessaryIsInstance** [boolean or string, optional]: Generate or suppress diagnostics for 'isinstance' or 'issubclass' calls where the result is statically determined to be always true. Such calls are often indicative of a programming error. The default value for this setting is 'none'.
|
||||
|
||||
|
@ -31,6 +31,7 @@ import {
|
||||
CaseNode,
|
||||
ClassNode,
|
||||
DelNode,
|
||||
DictionaryNode,
|
||||
ErrorNode,
|
||||
ExceptNode,
|
||||
FormatStringNode,
|
||||
@ -45,6 +46,7 @@ import {
|
||||
isExpressionNode,
|
||||
LambdaNode,
|
||||
ListComprehensionNode,
|
||||
ListNode,
|
||||
MatchNode,
|
||||
MemberAccessNode,
|
||||
ModuleNode,
|
||||
@ -55,6 +57,7 @@ import {
|
||||
ParseNodeType,
|
||||
RaiseNode,
|
||||
ReturnNode,
|
||||
SetNode,
|
||||
SliceNode,
|
||||
StatementListNode,
|
||||
StatementNode,
|
||||
@ -568,14 +571,7 @@ export class Checker extends ParseTreeWalker {
|
||||
override visitCall(node: CallNode): boolean {
|
||||
this._validateIsInstanceCall(node);
|
||||
|
||||
if (ParseTreeUtils.isWithinDefaultParamInitializer(node) && !this._fileInfo.isStubFile) {
|
||||
this._evaluator.addDiagnostic(
|
||||
this._fileInfo.diagnosticRuleSet.reportCallInDefaultInitializer,
|
||||
DiagnosticRule.reportCallInDefaultInitializer,
|
||||
Localizer.Diagnostic.defaultValueContainsCall(),
|
||||
node
|
||||
);
|
||||
}
|
||||
this._validateIllegalDefaultParamInitializer(node);
|
||||
|
||||
if (
|
||||
this._fileInfo.diagnosticRuleSet.reportUnusedCallResult !== 'none' ||
|
||||
@ -638,6 +634,21 @@ export class Checker extends ParseTreeWalker {
|
||||
return true;
|
||||
}
|
||||
|
||||
override visitList(node: ListNode): boolean {
|
||||
this._validateIllegalDefaultParamInitializer(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
override visitSet(node: SetNode): boolean {
|
||||
this._validateIllegalDefaultParamInitializer(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
override visitDictionary(node: DictionaryNode): boolean {
|
||||
this._validateIllegalDefaultParamInitializer(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
override visitListComprehension(node: ListComprehensionNode): boolean {
|
||||
this._scopedNodes.push(node);
|
||||
return true;
|
||||
@ -1120,6 +1131,19 @@ export class Checker extends ParseTreeWalker {
|
||||
return false;
|
||||
}
|
||||
|
||||
private _validateIllegalDefaultParamInitializer(node: ParseNode) {
|
||||
if (this._fileInfo.diagnosticRuleSet.reportCallInDefaultInitializer !== 'none') {
|
||||
if (ParseTreeUtils.isWithinDefaultParamInitializer(node) && !this._fileInfo.isStubFile) {
|
||||
this._evaluator.addDiagnostic(
|
||||
this._fileInfo.diagnosticRuleSet.reportCallInDefaultInitializer,
|
||||
DiagnosticRule.reportCallInDefaultInitializer,
|
||||
Localizer.Diagnostic.defaultValueContainsCall(),
|
||||
node
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determines whether the types of the two operands for an == or != operation
|
||||
// have overlapping types.
|
||||
private _validateComparisonTypes(node: BinaryOperationNode) {
|
||||
|
@ -62,7 +62,7 @@
|
||||
"dataClassFieldWithDefault": "Fields without default values cannot appear after fields with default values",
|
||||
"declaredReturnTypePartiallyUnknown": "Declared return type, \"{returnType}\", is partially unknown",
|
||||
"declaredReturnTypeUnknown": "Declared return type is unknown",
|
||||
"defaultValueContainsCall": "Function calls within default value initializer are not permitted",
|
||||
"defaultValueContainsCall": "Function calls and mutable objects not allowed within parameter default value expression",
|
||||
"defaultValueNotAllowed": "Parameter with \"*\" or \"**\" cannot have default value",
|
||||
"defaultValueNotEllipsis": "Default values in stub files should be specified as \"...\"",
|
||||
"delTargetExpr": "Expression cannot be deleted",
|
||||
|
@ -176,14 +176,14 @@ test('Mro3', () => {
|
||||
test('DefaultInitializer1', () => {
|
||||
const configOptions = new ConfigOptions('.');
|
||||
|
||||
// By default, optional diagnostics are ignored.
|
||||
// By default, the reportCallInDefaultInitializer is disabled.
|
||||
let analysisResults = TestUtils.typeAnalyzeSampleFiles(['defaultInitializer1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
|
||||
// Turn on errors.
|
||||
configOptions.diagnosticRuleSet.reportCallInDefaultInitializer = 'error';
|
||||
analysisResults = TestUtils.typeAnalyzeSampleFiles(['defaultInitializer1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults, 2);
|
||||
TestUtils.validateResults(analysisResults, 5);
|
||||
});
|
||||
|
||||
test('UnnecessaryIsInstance1', () => {
|
||||
|
@ -1,8 +1,9 @@
|
||||
# This sample tests the type analyzer's reporting of issues
|
||||
# with parameter default initializer expressions.
|
||||
# with parameter default initializer expressions. This is
|
||||
# covered by the reportCallInDefaultInitializer diagnostic rule.
|
||||
|
||||
|
||||
def foo(
|
||||
def func1(
|
||||
a=None,
|
||||
# This should generate an error
|
||||
b=dict(),
|
||||
@ -10,3 +11,16 @@ def foo(
|
||||
c=max(3, 4),
|
||||
):
|
||||
return 3
|
||||
|
||||
|
||||
def func2(
|
||||
a=None,
|
||||
# This should generate an error
|
||||
b={},
|
||||
# This should generate an error
|
||||
c=[],
|
||||
# This should generate an error
|
||||
d={1, 2, 3},
|
||||
e=(1, 2, 3),
|
||||
):
|
||||
return 3
|
||||
|
Loading…
Reference in New Issue
Block a user