mirror of
https://github.com/microsoft/pyright.git
synced 2024-08-17 03:40:44 +03:00
Added new diagnostic rule "reportFunctionMemberAccess" that reports an attempt to access, set or delete non-standard attributes of function objects.
This commit is contained in:
parent
05e118a4b3
commit
1601a177cd
@ -50,6 +50,8 @@ The following settings control pyright’s diagnostic output (warnings or errors
|
||||
|
||||
**reportPropertyTypeMismatch** [boolean or string, optional]: Generate or suppress diagnostics for properties where the type of the value passed to the setter is not assignable to the value returned by the getter. Such mismatches violate the intended use of properties, which are meant to act like variables. The default value for this setting is 'error'.
|
||||
|
||||
**reportFunctionMemberAccess** [boolean or string, optional]: Generate or suppress diagnostics for non-standard member accesses for functions. The default value for this setting is 'none'.
|
||||
|
||||
**reportMissingImports** [boolean or string, optional]: Generate or suppress diagnostics for imports that have no corresponding imported python file or type stub file. The default value for this setting is 'none', although pyright can do a much better job of static type checking if type stub files are provided for all imports.
|
||||
|
||||
**reportMissingModuleSource** [boolean or string, optional]: Generate or suppress diagnostics for imports that have no corresponding source file. This happens when a type stub is found, but the module source file was not found, indicating that the code may fail at runtime when using this execution environment. Type checking will be done using the type stub. The default value for this setting is 'warning'.
|
||||
|
@ -3019,6 +3019,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
EvaluatorFlags.None
|
||||
);
|
||||
writeTypeCache(node.memberName, memberType.type);
|
||||
writeTypeCache(node, memberType.type);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3630,9 +3631,15 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
|
||||
case TypeCategory.Function:
|
||||
case TypeCategory.OverloadedFunction: {
|
||||
// TODO - not yet sure what to do about members of functions,
|
||||
// which have associated dictionaries.
|
||||
type = AnyType.create();
|
||||
const functionObj = getBuiltInObject(node, 'function');
|
||||
|
||||
// The "__defaults__" member is not currently defined in the "function"
|
||||
// class, so we'll special-case it here.
|
||||
if (functionObj && memberName !== '__defaults__') {
|
||||
type = getTypeFromMemberAccessWithBaseType(node, { type: functionObj, node }, usage, flags).type;
|
||||
} else {
|
||||
type = AnyType.create();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3656,13 +3663,25 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
diag = usage.setExpectedTypeDiag;
|
||||
}
|
||||
|
||||
const isFunctionRule =
|
||||
isFunction(baseType) ||
|
||||
isOverloadedFunction(baseType) ||
|
||||
(isObject(baseType) && ClassType.isBuiltIn(baseType.classType, 'function'));
|
||||
const [ruleSet, rule] = isFunctionRule
|
||||
? [fileInfo.diagnosticRuleSet.reportFunctionMemberAccess, DiagnosticRule.reportFunctionMemberAccess]
|
||||
: [fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, DiagnosticRule.reportGeneralTypeIssues];
|
||||
|
||||
addDiagnostic(
|
||||
fileInfo.diagnosticRuleSet.reportGeneralTypeIssues,
|
||||
DiagnosticRule.reportGeneralTypeIssues,
|
||||
ruleSet,
|
||||
rule,
|
||||
diagMessage.format({ name: memberName, type: printType(baseType) }) + diag.getString(),
|
||||
node.memberName
|
||||
);
|
||||
type = UnknownType.create();
|
||||
|
||||
// If this is member access on a function, use "Any" so if the
|
||||
// reportFunctionMemberAccess rule is disabled, we don't trigger
|
||||
// additional reportUnknownMemberType diagnostics.
|
||||
type = isFunctionRule ? AnyType.create() : UnknownType.create();
|
||||
}
|
||||
|
||||
// Should we specialize the class?
|
||||
|
@ -96,6 +96,9 @@ export interface DiagnosticRuleSet {
|
||||
// Report mismatch in types between property getter and setter?
|
||||
reportPropertyTypeMismatch: DiagnosticLevel;
|
||||
|
||||
// Report the use of unknown member accesses on function objects?
|
||||
reportFunctionMemberAccess: DiagnosticLevel;
|
||||
|
||||
// Report missing imports?
|
||||
reportMissingImports: DiagnosticLevel;
|
||||
|
||||
@ -246,6 +249,7 @@ export function getDiagLevelDiagnosticRules() {
|
||||
return [
|
||||
DiagnosticRule.reportGeneralTypeIssues,
|
||||
DiagnosticRule.reportPropertyTypeMismatch,
|
||||
DiagnosticRule.reportFunctionMemberAccess,
|
||||
DiagnosticRule.reportMissingImports,
|
||||
DiagnosticRule.reportMissingModuleSource,
|
||||
DiagnosticRule.reportMissingTypeStubs,
|
||||
@ -307,6 +311,7 @@ export function getOffDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
enableTypeIgnoreComments: true,
|
||||
reportGeneralTypeIssues: 'none',
|
||||
reportPropertyTypeMismatch: 'none',
|
||||
reportFunctionMemberAccess: 'none',
|
||||
reportMissingImports: 'warning',
|
||||
reportMissingModuleSource: 'warning',
|
||||
reportMissingTypeStubs: 'none',
|
||||
@ -364,6 +369,7 @@ export function getBasicDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
enableTypeIgnoreComments: true,
|
||||
reportGeneralTypeIssues: 'error',
|
||||
reportPropertyTypeMismatch: 'error',
|
||||
reportFunctionMemberAccess: 'none',
|
||||
reportMissingImports: 'error',
|
||||
reportMissingModuleSource: 'warning',
|
||||
reportMissingTypeStubs: 'none',
|
||||
@ -421,6 +427,7 @@ export function getStrictDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
enableTypeIgnoreComments: true, // Not overridden by strict mode
|
||||
reportGeneralTypeIssues: 'error',
|
||||
reportPropertyTypeMismatch: 'error',
|
||||
reportFunctionMemberAccess: 'error',
|
||||
reportMissingImports: 'error',
|
||||
reportMissingModuleSource: 'warning',
|
||||
reportMissingTypeStubs: 'error',
|
||||
@ -803,6 +810,13 @@ export class ConfigOptions {
|
||||
defaultSettings.reportPropertyTypeMismatch
|
||||
),
|
||||
|
||||
// Read the "reportFunctionMemberAccess" entry.
|
||||
reportFunctionMemberAccess: this._convertDiagnosticLevel(
|
||||
configObj.reportFunctionMemberAccess,
|
||||
DiagnosticRule.reportFunctionMemberAccess,
|
||||
defaultSettings.reportFunctionMemberAccess
|
||||
),
|
||||
|
||||
// Read the "reportMissingImports" entry.
|
||||
reportMissingImports: this._convertDiagnosticLevel(
|
||||
configObj.reportMissingImports,
|
||||
|
@ -18,6 +18,7 @@ export enum DiagnosticRule {
|
||||
|
||||
reportGeneralTypeIssues = 'reportGeneralTypeIssues',
|
||||
reportPropertyTypeMismatch = 'reportPropertyTypeMismatch',
|
||||
reportFunctionMemberAccess = 'reportFunctionMemberAccess',
|
||||
reportMissingImports = 'reportMissingImports',
|
||||
reportMissingModuleSource = 'reportMissingModuleSource',
|
||||
reportMissingTypeStubs = 'reportMissingTypeStubs',
|
||||
|
18
packages/pyright-internal/src/tests/samples/function13.py
Normal file
18
packages/pyright-internal/src/tests/samples/function13.py
Normal file
@ -0,0 +1,18 @@
|
||||
# This sample tests the reportFunctionMemberAccess diagnostic rule.
|
||||
|
||||
|
||||
def func1():
|
||||
pass
|
||||
|
||||
|
||||
a = func1.__annotations__
|
||||
b = func1.__class__
|
||||
|
||||
# This should generate an error
|
||||
c = func1.bar
|
||||
|
||||
# This should generate an error
|
||||
func1.baz = 3
|
||||
|
||||
# This should generate an error
|
||||
del func1.baz
|
@ -518,6 +518,18 @@ test('Function12', () => {
|
||||
TestUtils.validateResults(analysisResults, 0, 0, 0, 2);
|
||||
});
|
||||
|
||||
test('Function13', () => {
|
||||
// Analyze with reportFunctionMemberAccess disabled.
|
||||
const analysisResult1 = TestUtils.typeAnalyzeSampleFiles(['function13.py']);
|
||||
TestUtils.validateResults(analysisResult1, 0);
|
||||
|
||||
// Analyze with reportFunctionMemberAccess enabled.
|
||||
const configOptions = new ConfigOptions('.');
|
||||
configOptions.diagnosticRuleSet.reportFunctionMemberAccess = 'error';
|
||||
const analysisResult2 = TestUtils.typeAnalyzeSampleFiles(['function13.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResult2, 3);
|
||||
});
|
||||
|
||||
test('Annotations1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['annotations1.py']);
|
||||
|
||||
|
@ -136,6 +136,17 @@
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"reportFunctionMemberAccess": {
|
||||
"type": "string",
|
||||
"description": "Diagnostics for member accesses on functions.",
|
||||
"default": "none",
|
||||
"enum": [
|
||||
"none",
|
||||
"information",
|
||||
"warning",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"reportMissingImports": {
|
||||
"type": "string",
|
||||
"description": "Diagnostics for imports that have no corresponding imported python file or type stub file.",
|
||||
|
@ -135,6 +135,12 @@
|
||||
"title": "Controls reporting of property getter/setter type mismatches",
|
||||
"default": "error"
|
||||
},
|
||||
"reportFunctionMemberAccess": {
|
||||
"$id": "#/properties/reportFunctionMemberAccess",
|
||||
"$ref": "#/definitions/diagnostic",
|
||||
"title": "Controls reporting of member accesses on function objects",
|
||||
"default": "none"
|
||||
},
|
||||
"reportMissingImports": {
|
||||
"$id": "#/properties/reportMissingImports",
|
||||
"$ref": "#/definitions/diagnostic",
|
||||
|
Loading…
Reference in New Issue
Block a user