mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fixed PY-3055 Missing super constructor call Inspection
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user