Enhanced the reportUninitializedInstanceVariable check to detect cases where a class variable is declared but not initialized in the class body and no instance variable of the same name is assigned in the __init__ method.

This commit is contained in:
Eric Traut 2022-05-02 18:51:52 -07:00
parent 1d756da35b
commit 89fd2859c6
3 changed files with 42 additions and 1 deletions

View File

@ -3743,10 +3743,25 @@ export class Checker extends ParseTreeWalker {
if (
decls.find((decl) => {
const containingClass = ParseTreeUtils.getEnclosingClassOrFunction(decl.node);
if (!containingClass || containingClass.nodeType === ParseNodeType.Class) {
if (!containingClass) {
return true;
}
if (containingClass.nodeType === ParseNodeType.Class) {
// If this is part of an assignment statement, assume it has been
// initialized as a class variable.
if (decl.node.parent?.nodeType === ParseNodeType.Assignment) {
return true;
}
if (
decl.node.parent?.nodeType === ParseNodeType.TypeAnnotation &&
decl.node.parent.parent?.nodeType === ParseNodeType.Assignment
) {
return true;
}
}
if (containingClass.name.value === '__init__') {
return true;
}

View File

@ -413,6 +413,19 @@ test('UnusedExpression1', () => {
TestUtils.validateResults(analysisResults, 10);
});
test('UninitializedVariable1', () => {
const configOptions = new ConfigOptions('.');
// By default, this is off.
let analysisResults = TestUtils.typeAnalyzeSampleFiles(['uninitializedVariable1.py'], configOptions);
TestUtils.validateResults(analysisResults, 0);
// Enable it as an error.
configOptions.diagnosticRuleSet.reportUninitializedInstanceVariable = 'error';
analysisResults = TestUtils.typeAnalyzeSampleFiles(['uninitializedVariable1.py'], configOptions);
TestUtils.validateResults(analysisResults, 1);
});
// For now, this functionality is disabled.
// test('Deprecated1', () => {

View File

@ -0,0 +1,13 @@
# This sample tests the reportUninitializedInstanceVariable functionality.
class A:
# This should generate an error if reportUninitializedInstanceVariable
# is enabled.
v1: int
v2: int
v3 = 2
v4: int = 3
def __init__(self) -> None:
self.v2 = 3
super().__init__()