From b6c860fbaf08466c9e5447627b41eacffe700995 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 25 Mar 2013 16:30:45 +0400 Subject: [PATCH] fixed PY-9262 Instance attribute defined outside init: false positive with superclass constructor call in class --- .../PyAttributeOutsideInitInspection.java | 32 ++++++++++++++++--- .../definedInSuperClass.py | 12 +++++++ .../PyAttributeOutsideInitInspectionTest.java | 4 +++ 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 python/testData/inspections/PyAttributeOutsideInitInspection/definedInSuperClass.py diff --git a/python/src/com/jetbrains/python/inspections/PyAttributeOutsideInitInspection.java b/python/src/com/jetbrains/python/inspections/PyAttributeOutsideInitInspection.java index b6add93f047c..b4ef1ff0e27c 100644 --- a/python/src/com/jetbrains/python/inspections/PyAttributeOutsideInitInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAttributeOutsideInitInspection.java @@ -6,10 +6,11 @@ import com.intellij.psi.PsiElementVisitor; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.inspections.quickfix.PyMoveAttributeToInitQuickFix; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyTargetExpression; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyCallExpressionHelper; import com.jetbrains.python.psi.impl.PyClassImpl; +import com.jetbrains.python.psi.types.PyClassType; +import com.jetbrains.python.psi.types.PyType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,9 +53,12 @@ public class PyAttributeOutsideInitInspection extends PyInspection { Map attributesInInit = new HashMap(); final PyFunction initMethod = containingClass.findMethodByName(PyNames.INIT, false); - if (initMethod != null) + if (initMethod != null) { PyClassImpl.collectInstanceAttributes(initMethod, attributesInInit); + collectAttributesFromSuper(attributesInInit, initMethod); + } + Map attributes = new HashMap(); PyClassImpl.collectInstanceAttributes(node, attributes); @@ -66,5 +70,25 @@ public class PyAttributeOutsideInitInspection extends PyInspection { } } + private void collectAttributesFromSuper(Map attributesInInit, PyFunction initMethod) { + final PyStatementList statementList = initMethod.getStatementList(); + if (statementList != null) { + for (PyStatement statement : statementList.getStatements()) { + if (statement instanceof PyExpressionStatement) { + final PyExpression expression = ((PyExpressionStatement)statement).getExpression(); + if (expression instanceof PyCallExpression) { + final PyType callType = PyCallExpressionHelper.getCallType((PyCallExpression)expression, myTypeEvalContext); + if (callType instanceof PyClassType) { + final PyClass superClass = ((PyClassType)callType).getPyClass(); + final PyFunction superInit = superClass.findMethodByName(PyNames.INIT, false); + if (superInit != null) { + PyClassImpl.collectInstanceAttributes(superInit, attributesInInit); + } + } + } + } + } + } + } } } diff --git a/python/testData/inspections/PyAttributeOutsideInitInspection/definedInSuperClass.py b/python/testData/inspections/PyAttributeOutsideInitInspection/definedInSuperClass.py new file mode 100644 index 000000000000..071e8096a381 --- /dev/null +++ b/python/testData/inspections/PyAttributeOutsideInitInspection/definedInSuperClass.py @@ -0,0 +1,12 @@ +__author__ = 'ktisha' + +class Base(object): + def __init__(self): + self.my = 1 + +class Child(Base): + def __init__(self): + super(Child, self).__init__() + + def f(self): + self.my = 1 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyAttributeOutsideInitInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyAttributeOutsideInitInspectionTest.java index 45bddc738a5c..dee5a034ec94 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyAttributeOutsideInitInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyAttributeOutsideInitInspectionTest.java @@ -15,6 +15,10 @@ public class PyAttributeOutsideInitInspectionTest extends PyTestCase { doTest(); } + public void testDefinedInSuperClass() { + doTest(); + } + private void doTest() { myFixture.configureByFile("inspections/PyAttributeOutsideInitInspection/" + getTestName(true) + ".py"); myFixture.enableInspections(PyAttributeOutsideInitInspection.class);