diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 83d039eb0ff8..4e751db39380 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -22,6 +22,7 @@ import com.jetbrains.python.psi.impl.PyQualifiedName; import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyNoneType; import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.PyTypeChecker; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -135,8 +136,9 @@ public class PyPropertyDefinitionInspection extends PyInspection { Callable callable = null; if (argument instanceof PyReferenceExpression) { PsiElement resolved = ((PyReferenceExpression)argument).getReference(resolveWithoutImplicits()).resolve(); - if (resolved instanceof PyFunction) callable = (PyFunction)resolved; - else if (resolved instanceof PyLambdaExpression) callable = (PyLambdaExpression)resolved; + if (resolved instanceof Callable) { + callable = (Callable)resolved; + } else { reportNonCallableArg(resolved, argument); return; @@ -161,19 +163,19 @@ public class PyPropertyDefinitionInspection extends PyInspection { } } - private void reportNonCallableArg(PsiElement resolved, PsiElement being_checked) { - if (! PyUtil.instanceOf(resolved, PySubscriptionExpression.class, PyNoneLiteralExpression.class)) { - boolean is_not_callable = true; - if (resolved instanceof PyExpression) { - PyType expr_type = ((PyExpression)resolved).getType(myTypeEvalContext); - if (expr_type instanceof PyClassType) { - final PyClassType cls_type = (PyClassType)expr_type; - PyClass cls = cls_type.getPyClass(); - if (!cls_type.isDefinition()) is_not_callable = cls.findMethodByName("__call__", true) == null; - } + private void reportNonCallableArg(PsiElement resolved, PsiElement element) { + if (resolved instanceof PySubscriptionExpression || resolved instanceof PyNoneLiteralExpression) { + return; + } + if (PyNames.NONE.equals(element.getText())) { + return; + } + if (resolved instanceof PyTypedElement) { + final PyType type = ((PyTypedElement)resolved).getType(myTypeEvalContext); + final Boolean isCallable = PyTypeChecker.isCallable(type); + if (isCallable != null && !isCallable) { + registerProblem(element, PyBundle.message("INSP.strange.arg.want.callable")); } - if (is_not_callable && !"None".equals(being_checked.getText())) - registerProblem(being_checked, PyBundle.message("INSP.strange.arg.want.callable")); } } diff --git a/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml b/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml index 400806dc8848..38414607ac1f 100644 --- a/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml +++ b/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml @@ -45,10 +45,5 @@ 48 Getter should return something - - prop_test.py - 76 - Strange argument; a callable expected - diff --git a/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py index a7377526fbde..60d6413106d5 100644 --- a/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py +++ b/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py @@ -73,7 +73,7 @@ gb = Ghostbusters() class B(object): x = property(gb) # pass y = property(Ghostbusters()) # pass - z = property(Ghostbusters) # fail: not callable + z = property(Ghostbusters) # pass class Eternal(object): def give(self): diff --git a/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py index 62ad2f15021f..5823e797f197 100644 --- a/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py +++ b/python/testData/inspections/PyPropertyDefinitionInspection26/src/prop_test.py @@ -59,3 +59,7 @@ class A(object): def xoo(self, x): self._x = x return + + get_foo2 = lambda self: 'foo2' + + foo2 = property(get_foo2)