PY-33265: Removed false positive warning when the superclass has a decorated abstract constructor

GitOrigin-RevId: 07e3a621997f3b3e1fdb01e7a83df69bcd3985d8
This commit is contained in:
Irina Fediaeva
2021-04-02 13:47:07 +00:00
committed by intellij-monorepo-bot
parent f2bcba9f7b
commit 737e13b9b0
3 changed files with 59 additions and 13 deletions
@@ -28,14 +28,7 @@ import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.PyPsiBundle;
import com.jetbrains.python.inspections.quickfix.AddCallSuperQuickFix;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyCallExpression;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyQualifiedExpression;
import com.jetbrains.python.psi.PyRecursiveElementVisitor;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.types.TypeEvalContext;
import java.util.Objects;
import java.util.Optional;
@@ -67,7 +60,7 @@ public class PyMissingConstructorInspection extends PyInspection {
if (superClasses.length == 0 ||
superClasses.length == 1 && OBJECT.equals(superClasses[0].getText()) ||
!superHasConstructor(node, myTypeEvalContext)) {
!superHasNonAbstractConstructor(node, myTypeEvalContext)) {
return;
}
@@ -86,14 +79,16 @@ public class PyMissingConstructorInspection extends PyInspection {
}
}
private static boolean superHasConstructor(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
private static boolean superHasNonAbstractConstructor(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
final String className = cls.getName();
for (PyClass baseClass : cls.getAncestorClasses(context)) {
if (!PyUtil.isObjectClass(baseClass) &&
!Objects.equals(className, baseClass.getName()) &&
baseClass.findMethodByName(INIT, false, context) != null) {
return true;
!Objects.equals(className, baseClass.getName())) {
var initMethod = baseClass.findMethodByName(INIT, false, context);
if (initMethod != null && !PyKnownDecoratorUtil.hasAbstractDecorator(initMethod, context)) {
return true;
}
}
}
@@ -0,0 +1,46 @@
from abc import abstractmethod
class A1:
@abstractmethod
def __init__(self):
pass
class A2:
@abstractmethod
def __init__(self):
pass
class B1:
def __init__(self):
pass
class B2:
pass
class C1(A1):
def __init__(self):
pass
class C2(A1, A2):
def __init__(self):
pass
class C3(A1, B1):
def <warning descr="Call to __init__ of super class is missed">__init__</warning>(self):
pass
class C4(B1, A1):
def <warning descr="Call to __init__ of super class is missed">__init__</warning>(self):
pass
class D(B2, A1):
def __init__(self):
pass
@@ -71,6 +71,11 @@ public class PyMissingConstructorTest extends PyTestCase {
doTest();
}
// PY-33265
public void testAbstractConstructor() {
doTest();
}
private void doTest() {
myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py");
myFixture.enableInspections(PyMissingConstructorInspection.class);