fixed PY-3055 Missing super constructor call Inspection

This commit is contained in:
Ekaterina Tuzova
2011-03-10 21:09:09 +03:00
parent d1a130f871
commit 7e17a7dd2a
5 changed files with 163 additions and 0 deletions
@@ -363,6 +363,8 @@ INSP.NAME.unnecessary.backslash=Unnecessary backslash
# PySingleQuotedDocstringInspection
INSP.NAME.single.quoted.docstring=Single quoted docstring
# PyMissingConstructorInspection
INSP.NAME.missing.super.constructor=Missed call to constructor of super class
# Refactoring
# introduce
@@ -0,0 +1,112 @@
package com.jetbrains.python.inspections;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.util.containers.Stack;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
* User: catherine
*
* Inspection to warn if call to super constructor in class is missed
*/
public class PyMissingConstructorInspection extends PyInspection {
@Nls
@NotNull
@Override
public String getDisplayName() {
return PyBundle.message("INSP.NAME.missing.super.constructor");
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends PyInspectionVisitor {
public Visitor(final ProblemsHolder holder) {
super(holder);
}
@Override
public void visitPyClass(final PyClass node) {
PyClass[] superClasses = node.getSuperClasses();
if (superClasses.length == 0)
return;
Set<String> superNames = new HashSet<String>();
if (node.isNewStyleClass())
superNames.add(PyNames.SUPER);
for (PyClass cl : superClasses) {
if (!PyNames.OBJECT.equals(cl.getName()))
superNames.add(cl.getName());
}
if (superClasses.length == 1 && PyNames.OBJECT.equals(superClasses[0].getName()))
return;
PyFunction initMethod = node.findMethodByName(PyNames.INIT, false);
if (initMethod != null) {
if (hasConstructorCall(initMethod, superNames))
return;
registerProblem(initMethod.getNameIdentifier(), "Call to constructor of super class is missed");
}
}
private static boolean hasConstructorCall(PyFunction initMethod, Set<String> superNames) {
Stack<PsiElement> stack = new Stack<PsiElement>();
PyStatementList statementList = initMethod.getStatementList();
boolean hasConstructor = false;
if (statementList != null) {
for (PyStatement st : statementList.getStatements()) {
stack.push(st);
while (!stack.isEmpty()) {
PsiElement e = stack.pop();
if (e instanceof PyExpressionStatement) {
PyExpression expression = ((PyExpressionStatement)e).getExpression();
if (expression instanceof PyCallExpression) {
if (isConstructorCall((PyCallExpression)expression, superNames))
hasConstructor = true;
}
}
for (PsiElement psiElement : e.getChildren()) {
stack.push(psiElement);
}
}
}
}
return hasConstructor;
}
private static boolean isConstructorCall(PyCallExpression expression, Set<String> superNames) {
PyExpression callee = expression.getCallee();
if (callee instanceof PyQualifiedExpression) {
PyExpression qualifier = ((PyQualifiedExpression)callee).getQualifier();
if (qualifier != null) {
String tmp = "";
if (qualifier instanceof PyCallExpression) {
PyExpression innerCallee = ((PyCallExpression)qualifier).getCallee();
if (innerCallee != null)
tmp = innerCallee.getName();
}
else
tmp = qualifier.getText();
if (superNames.contains(tmp)) {
if(PyNames.INIT.equals(callee.getName())){
return true;
}
}
}
}
return false;
}
}
}
@@ -56,6 +56,7 @@ public class PythonInspectionToolProvider implements InspectionToolProvider {
PyListCreationInspection.class,
PyUnnecessaryBackslashInspection.class,
PySingleQuotedDocstringInspection.class,
PyMissingConstructorInspection.class,
};
}
}
@@ -0,0 +1,38 @@
class A(object):
def __init__(self):
pass
class AA(A):
def __init__(self):
A.__init__(self)
print("Constructor AA was called")
class B(A):
def <warning descr="Call to constructor of super class is missed">__init__</warning>(self):
print("Constructor B was called")
class C(B):
def __init__(self):
super(C, self).__init__()
print("Constructor C was called")
class A:
def __init__(self):
print("A __init__")
class B(A):
def __init__(self):
A.__init__(self)
print("Constructor B was called")
class C(B):
def <warning descr="Call to constructor of super class is missed">__init__</warning>(self):
print("Constructor C was called")
class D(A):
def __init__(self):
if True:
A.__init__(self)
print("Constructor D was called")
@@ -312,4 +312,14 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase {
public void testPySingleQuotedDocstringInspection() { //PY-1445
doHighlightingTest(PySingleQuotedDocstringInspection.class);
}
public void testPyMissingConstructorInspection() { //PY-3055
setLanguageLevel(LanguageLevel.PYTHON27);
doHighlightingTest(PyMissingConstructorInspection.class);
}
public void testPyMissingConstructorInspection30() { //PY-3055
setLanguageLevel(LanguageLevel.PYTHON30);
doHighlightingTest(PyMissingConstructorInspection.class);
}
}