don't highlight Java methods as not callable (PY-9037)

This commit is contained in:
Dmitry Jemerov
2013-03-04 15:14:07 +01:00
parent 7439ebe36b
commit 5e80806668
7 changed files with 103 additions and 17 deletions

View File

@@ -0,0 +1,69 @@
package com.jetbrains.python.psi.impl;
import com.intellij.psi.PsiMethod;
import com.intellij.util.ArrayUtil;
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.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;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
/**
* @author yole
*/
public class PyJavaMethodType implements PyCallableType {
private final PsiMethod myMethod;
public PyJavaMethodType(PsiMethod method) {
myMethod = method;
}
@Override
public boolean isCallable() {
return true;
}
@Nullable
@Override
public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) {
return PyJavaTypeProvider.asPyType(myMethod.getReturnType());
}
@Nullable
@Override
public List<? extends RatedResolveResult> resolveMember(@NotNull String name,
@Nullable PyExpression location,
AccessDirection direction,
PyResolveContext resolveContext) {
return Collections.emptyList();
}
@Override
public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Nullable
@Override
public String getName() {
return "Java method(" + myMethod.getContainingClass().getQualifiedName() + "." + myMethod.getName() + ")";
}
@Override
public boolean isBuiltin(TypeEvalContext context) {
return false;
}
@Override
public void assertValid(String message) {
}
}

View File

@@ -30,7 +30,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase {
}
if (referenceTarget instanceof PsiMethod) {
PsiMethod method = (PsiMethod) referenceTarget;
return asPyType(method.getReturnType());
return new PyJavaMethodType(method);
}
if (referenceTarget instanceof PsiField) {
return asPyType(((PsiField)referenceTarget).getType());
@@ -39,7 +39,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase {
}
@Nullable
private static PyType asPyType(PsiType type) {
public static PyType asPyType(PsiType type) {
if (type instanceof PsiClassType) {
final PsiClassType classType = (PsiClassType)type;
final PsiClass psiClass = classType.resolve();

View File

@@ -3,14 +3,23 @@ package com.jetbrains.jython;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.jetbrains.python.PythonTestUtil;
import com.jetbrains.python.inspections.PyCallingNonCallableInspection;
import com.jetbrains.python.inspections.PyUnresolvedReferencesInspection;
/**
* @author yole
*/
public class PyJythonHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testCallableJavaClass() {
myFixture.configureByFile("callableJavaClass.py");
myFixture.enableInspections(PyCallingNonCallableInspection.class);
doCallableTest();
}
public void testCallableStaticMethod() {
doCallableTest();
}
private void doCallableTest() {
myFixture.configureByFile(getTestName(false) + ".py");
myFixture.enableInspections(PyCallingNonCallableInspection.class, PyUnresolvedReferencesInspection.class);
myFixture.checkHighlighting(true, false, false);
}

View File

@@ -25,16 +25,20 @@ import java.util.List;
*/
public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType {
private final String myName;
private final boolean myDefinition;
// 2 - namedtuple call itself
// 1 - return type of namedtuple call, aka namedtuple class
// 0 - namedtuple instance
private final int myDefinitionLevel;
private final PsiElement myDeclaration;
private final List<String> myFields;
public PyNamedTupleType(PyClass tupleClass, PsiElement declaration, String name, List<String> fields, boolean isDefinition) {
super(tupleClass, isDefinition);
public PyNamedTupleType(PyClass tupleClass, PsiElement declaration, String name, List<String> fields, int definitionLevel) {
super(tupleClass, definitionLevel > 0);
myDeclaration = declaration;
myFields = fields;
myName = name;
myDefinition = isDefinition;
myDefinitionLevel = definitionLevel;
}
@Override
@@ -75,15 +79,15 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType
@Nullable
@Override
public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) {
if (myDefinition) {
return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, false);
if (myDefinitionLevel > 0) {
return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1);
}
return null;
}
@Override
public PyClassType toInstance() {
return myIsDefinition ? new PyNamedTupleType(myClass, myDeclaration, myName, myFields, false) : this;
return myDefinitionLevel == 1 ? new PyNamedTupleType(myClass, myDeclaration, myName, myFields, 0) : this;
}
@Override
@@ -92,7 +96,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType
}
@Nullable
public static PyType fromCall(PyCallExpression call) {
public static PyType fromCall(PyCallExpression call, int level) {
final String name = PyPsiUtils.strValue(call.getArgument(0, PyExpression.class));
final PyExpression fieldNamesExpression = PyPsiUtils.flattenParens(call.getArgument(1, PyExpression.class));
if (name == null || fieldNamesExpression == null) {
@@ -111,7 +115,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType
if (fieldNames != null) {
PyClass tuple = PyBuiltinCache.getInstance(call).getClass(PyNames.FAKE_NAMEDTUPLE);
if (tuple != null) {
return new PyNamedTupleType(tuple, call, name, fieldNames, true);
return new PyNamedTupleType(tuple, call, name, fieldNames, level);
}
}
return null;

View File

@@ -58,7 +58,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
if (callee != null) {
final Callable callable = callee.getCallable();
if (PyNames.COLLECTIONS_PY.equals(callable.getContainingFile().getName())) {
return PyNamedTupleType.fromCall(call);
return PyNamedTupleType.fromCall(call, 1);
}
}
}
@@ -67,7 +67,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
else if (referenceTarget instanceof PyFunction && anchor instanceof PyCallExpression) {
if (PyNames.NAMEDTUPLE.equals(((PyFunction)referenceTarget).getName()) &&
PyNames.COLLECTIONS_PY.equals(referenceTarget.getContainingFile().getName())) {
return PyNamedTupleType.fromCall((PyCallExpression)anchor);
return PyNamedTupleType.fromCall((PyCallExpression)anchor, 2);
}
}
return null;

View File

@@ -419,8 +419,8 @@ public class PyCallExpressionHelper {
return new PyClassTypeImpl(cls, false);
}
final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, call);
if (providedType != null) {
return providedType;
if (providedType instanceof PyCallableType) {
return ((PyCallableType) providedType).getCallType(context, (PyReferenceExpression)callee);
}
if (target instanceof Callable) {
final Callable callable = (Callable)target;

View File

@@ -0,0 +1,4 @@
from java.util import Collections
x = Collections.emptyList()
s = x.size()