diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index d1667a07eed5..c9d212cb6ddd 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -7,9 +7,11 @@ import com.intellij.psi.ResolveState; import com.intellij.util.ProcessingContext; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyQualifiedExpression; import com.jetbrains.python.psi.resolve.CompletionVariantsProcessor; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; +import com.jetbrains.python.psi.types.PyCallableType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; @@ -20,11 +22,13 @@ import java.util.List; /** * @author yole */ -public class PyJavaClassType implements PyType { +public class PyJavaClassType implements PyCallableType { private final PsiClass myClass; + private final boolean myDefinition; - public PyJavaClassType(final PsiClass aClass) { + public PyJavaClassType(final PsiClass aClass, boolean definition) { myClass = aClass; + myDefinition = definition; } @Nullable @@ -68,4 +72,18 @@ public class PyJavaClassType implements PyType { @Override public void assertValid(String message) { } + + @Override + public boolean isCallable() { + return myDefinition; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + if (myDefinition) { + return new PyJavaClassType(myClass, false); + } + return null; + } } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java index 369894203038..9d186f315c9e 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java @@ -23,7 +23,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase { @Nullable public PyType getReferenceType(@NotNull final PsiElement referenceTarget, TypeEvalContext context, @Nullable PsiElement anchor) { if (referenceTarget instanceof PsiClass) { - return new PyJavaClassType((PsiClass) referenceTarget); + return new PyJavaClassType((PsiClass) referenceTarget, true); } if (referenceTarget instanceof PsiPackage) { return new PyJavaPackageType((PsiPackage) referenceTarget, anchor == null ? null : ModuleUtil.findModuleForPsiElement(anchor)); @@ -44,7 +44,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase { final PsiClassType classType = (PsiClassType)type; final PsiClass psiClass = classType.resolve(); if (psiClass != null) { - return new PyJavaClassType(psiClass); + return new PyJavaClassType(psiClass, false); } } return null; @@ -67,7 +67,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase { if (paramType instanceof PsiClassType) { final PsiClass psiClass = ((PsiClassType)paramType).resolve(); if (psiClass != null) { - superMethodParameterTypes.add(new PyJavaClassType(psiClass)); + superMethodParameterTypes.add(new PyJavaClassType(psiClass, false)); } } } diff --git a/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java b/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java new file mode 100644 index 000000000000..8ddd01f29daf --- /dev/null +++ b/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java @@ -0,0 +1,22 @@ +package com.jetbrains.jython; + +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.jetbrains.python.PythonTestUtil; +import com.jetbrains.python.inspections.PyCallingNonCallableInspection; + +/** + * @author yole + */ +public class PyJythonHighlightingTest extends LightCodeInsightFixtureTestCase { + public void testCallableJavaClass() { + myFixture.configureByFile("callableJavaClass.py"); + myFixture.enableInspections(PyCallingNonCallableInspection.class); + myFixture.checkHighlighting(true, false, false); + } + + + @Override + protected String getTestDataPath() { + return PythonTestUtil.getTestDataPath() + "/highlighting/jython/"; + } +} diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 6c594c0755a2..74d0c2e8637c 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -11,6 +11,11 @@ import org.jetbrains.annotations.Nullable; * @author yole */ public interface PyCallableType extends PyType { + /** + * Returns true if the type is callable. + */ + boolean isCallable(); + /** * Returns the type which is the result of calling an instance of this type. * diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 0fb2f10830eb..14adb35a719c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -220,6 +220,21 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { return PyBuiltinCache.getInstance(myClass).getObjectType("type"); } + @Override + public boolean isCallable() { + if (isDefinition()) { + return true; + } + if (PyTypeChecker.isMethodType(this)) { + return true; + } + final PyClass cls = getPyClass(); + if (PyABCUtil.isSubclass(cls, PyNames.CALLABLE)) { + return true; + } + return false; + } + @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 8b68d03094a8..3bbfce984a95 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -22,6 +22,11 @@ public class PyFunctionType implements PyCallableType { myCallable = callable; } + @Override + public boolean isCallable() { + return true; + } + @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 80ff2bb3b929..5037de76a225 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -427,19 +427,6 @@ public class PyTypeChecker { if (type == null || type instanceof PyTypeReference) { return null; } - else if (type instanceof PyClassType) { - final PyClassType classType = (PyClassType)type; - if (classType.isDefinition()) { - return true; - } - if (isMethodType(classType)) { - return true; - } - final PyClass cls = classType.getPyClass(); - if (PyABCUtil.isSubclass(cls, PyNames.CALLABLE)) { - return true; - } - } else if (type instanceof PyUnionType) { Boolean result = true; for (PyType member : ((PyUnionType)type).getMembers()) { @@ -454,12 +441,12 @@ public class PyTypeChecker { return result; } else if (type instanceof PyCallableType) { - return true; + return ((PyCallableType) type).isCallable(); } return false; } - private static boolean isMethodType(@NotNull PyClassType type) { + public static boolean isMethodType(@NotNull PyClassType type) { final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(type.getPyClass()); return type.equals(builtinCache.getClassMethodType()) || type.equals(builtinCache.getStaticMethodType()); } diff --git a/python/testData/highlighting/jython/callableJavaClass.py b/python/testData/highlighting/jython/callableJavaClass.py new file mode 100644 index 000000000000..eb4f6d113e94 --- /dev/null +++ b/python/testData/highlighting/jython/callableJavaClass.py @@ -0,0 +1,2 @@ +from java.util import ArrayList +l = ArrayList()