mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixed function doesn't return anything inspection for decorated and overridden methods (PY-10883)
This commit is contained in:
+27
-5
@@ -3,11 +3,10 @@ package com.jetbrains.python.inspections;
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.psi.Callable;
|
||||
import com.jetbrains.python.psi.PyAssignmentStatement;
|
||||
import com.jetbrains.python.psi.PyCallExpression;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.search.PyOverridingMethodsSearch;
|
||||
import com.jetbrains.python.psi.types.PyNoneType;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.PyTypeChecker;
|
||||
@@ -16,6 +15,8 @@ import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User: ktisha
|
||||
*
|
||||
@@ -41,6 +42,8 @@ public class PyNoneFunctionAssignmentInspection extends PyInspection {
|
||||
|
||||
|
||||
private static class Visitor extends PyInspectionVisitor {
|
||||
private final Map<PyFunction, Boolean> myHasInheritors = new HashMap<PyFunction, Boolean>();
|
||||
|
||||
public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
|
||||
super(holder, session);
|
||||
}
|
||||
@@ -56,11 +59,30 @@ public class PyNoneFunctionAssignmentInspection extends PyInspection {
|
||||
final PyTypeChecker.AnalyzeCallResults analyzeCallResults = PyTypeChecker.analyzeCall(((PyCallExpression)value), myTypeEvalContext);
|
||||
if (analyzeCallResults != null) {
|
||||
final Callable callable = analyzeCallResults.getCallable();
|
||||
if (PySdkUtil.isElementInSkeletons(callable)) return;
|
||||
if (PySdkUtil.isElementInSkeletons(callable)) {
|
||||
return;
|
||||
}
|
||||
if (callable instanceof PyFunction) {
|
||||
final PyFunction function = (PyFunction)callable;
|
||||
// Currently we don't infer types returned by decorators
|
||||
if (hasInheritors(function) || PyUtil.hasCustomDecorators(function)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerProblem(node, PyBundle.message("INSP.none.function.assignment", callee.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasInheritors(@NotNull PyFunction function) {
|
||||
final Boolean cached = myHasInheritors.get(function);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
final boolean result = PyOverridingMethodsSearch.search(function, true).findFirst() != null;
|
||||
myHasInheritors.put(function, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import abc
|
||||
from abc import abstractmethod
|
||||
|
||||
|
||||
def decorator(f):
|
||||
return f
|
||||
|
||||
|
||||
class C(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def bar(self):
|
||||
pass
|
||||
|
||||
@decorator
|
||||
def baz(self):
|
||||
pass
|
||||
|
||||
def quux(self):
|
||||
pass
|
||||
|
||||
def test(self):
|
||||
a = self.foo()
|
||||
b = self.bar()
|
||||
c = self.baz()
|
||||
<weak_warning descr="Function 'quux' doesn't return anything">d = self.quux()</weak_warning>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
class C(object):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
def bar(self):
|
||||
pass
|
||||
|
||||
def test(self):
|
||||
x = self.foo()
|
||||
<weak_warning descr="Function 'bar' doesn't return anything">y = self.bar()</weak_warning>
|
||||
|
||||
|
||||
class D(C):
|
||||
def foo(self):
|
||||
return 2
|
||||
+10
@@ -27,6 +27,16 @@ public class PyNoneFunctionAssignmentInspectionTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-10883
|
||||
public void testMethodWithInheritors() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-10883
|
||||
public void testDecoratedMethod() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile("inspections/PyNoneFunctionAssignmentInspection/" + getTestName(true) + ".py");
|
||||
myFixture.enableInspections(PyNoneFunctionAssignmentInspection.class);
|
||||
|
||||
Reference in New Issue
Block a user