From 63f2789931a4e848705f8ae28f3f2c830abacc8b Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 4 Jul 2014 13:56:42 +0400 Subject: [PATCH] Introduced PyCallSiteExpression for distinguishing a[b] and a[b](c) in the type checker (PY-13051) PyTypeChecker.analyzeCallSite() was used for analyzing the return type of the call in the same way for different expressions: a[b] and a[b](c) as analyzeCallSite(a[b]) making it impossible to distinguish between the two. Now we pass a PyCallExpression for analyzing the function call instead of a PyQualifiedExpression. --- .../python/psi/impl/PyJavaClassType.java | 4 ++-- .../python/psi/impl/PyJavaMethodType.java | 4 ++-- .../com/jetbrains/python/psi/Callable.java | 2 +- .../python/psi/PyBinaryExpression.java | 2 +- .../python/psi/PyCallExpression.java | 2 +- .../python/psi/PyCallSiteExpression.java | 24 +++++++++++++++++++ .../python/psi/PySubscriptionExpression.java | 2 +- .../python/psi/impl/PyTypeProvider.java | 2 +- .../python/psi/types/PyCallableType.java | 4 ++-- .../python/psi/types/PyTypeProviderBase.java | 11 +++++---- .../NumpyDocStringTypeProvider.java | 10 ++++---- .../codeInsight/stdlib/PyNamedTupleType.java | 2 +- .../stdlib/PyStdlibTypeProvider.java | 2 +- .../inspections/PyTypeCheckerInspection.java | 7 ++---- .../psi/impl/PyCallExpressionHelper.java | 14 ++++------- .../python/psi/impl/PyFunctionImpl.java | 2 +- .../psi/impl/PyLambdaExpressionImpl.java | 2 +- .../psi/impl/PyPrefixExpressionImpl.java | 3 ++- .../python/psi/types/PyCallableTypeImpl.java | 4 ++-- .../python/psi/types/PyClassTypeImpl.java | 2 +- .../python/psi/types/PyFunctionType.java | 2 +- .../python/psi/types/PyTypeChecker.java | 13 +++------- .../callDictSubscriptionExpression.py | 4 ++++ .../PyCallingNonCallableInspectionTest.java | 5 ++++ 24 files changed, 73 insertions(+), 56 deletions(-) create mode 100644 python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java create mode 100644 python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index a667bb69f849..e9014b3759c2 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -18,8 +18,8 @@ package com.jetbrains.python.psi.impl; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; import com.jetbrains.python.psi.AccessDirection; +import com.jetbrains.python.psi.PyCallSiteExpression; 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; @@ -113,7 +113,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { return getReturnType(context); } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index 6f0fd48e8742..cb5d94e516bb 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -21,8 +21,8 @@ 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.PyCallSiteExpression; 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.PyCallableParameter; @@ -58,7 +58,7 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { return getReturnType(context); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/Callable.java b/python/psi-api/src/com/jetbrains/python/psi/Callable.java index a31197ec60c1..59e190ee4f4e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -45,7 +45,7 @@ public interface Callable extends PyTypedElement, PyQualifiedNameOwner { * Returns the type of the call to the callable. */ @Nullable - PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite); + PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite); /** * Returns the type of the call to the callable where the call site is specified by the optional receiver and the arguments to parameters diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java index 0461318736fc..9ca5a30b3d2f 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyBinaryExpression.java @@ -21,7 +21,7 @@ import org.jetbrains.annotations.Nullable; /** * @author yole */ -public interface PyBinaryExpression extends PyQualifiedExpression, PyReferenceOwner { +public interface PyBinaryExpression extends PyQualifiedExpression, PyCallSiteExpression, PyReferenceOwner { PyExpression getLeftExpression(); @Nullable PyExpression getRightExpression(); diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java index 581c4257c430..ae429f0d51af 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents an entire call expression, like foo() or foo.bar[1]('x'). */ -public interface PyCallExpression extends PyExpression { +public interface PyCallExpression extends PyCallSiteExpression { /** * @return the expression representing the object being called (reference to a function). diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java new file mode 100644 index 000000000000..a2c49cb52500 --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallSiteExpression.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.psi; + +/** + * Marker interface for Python expressions that are call sites for explicit or implicit function calls. + * + * @author vlan + */ +public interface PyCallSiteExpression extends PyExpression { +} diff --git a/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java index dc3f28d8ea38..cc1bba0616d2 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java @@ -21,7 +21,7 @@ import org.jetbrains.annotations.Nullable; /** * @author yole */ -public interface PySubscriptionExpression extends PyQualifiedExpression, PyReferenceOwner { +public interface PySubscriptionExpression extends PyQualifiedExpression, PyCallSiteExpression, PyReferenceOwner { /** * @return For spam[x][y][n] will return spam regardless number of its dimensions diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java index 5707005026cb..be76db2af007 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java @@ -42,7 +42,7 @@ public interface PyTypeProvider { PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context); @Nullable - PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context); + PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context); @Nullable PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context); 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 66fb827babe4..d2c36ba37343 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 @@ -15,7 +15,7 @@ */ package com.jetbrains.python.psi.types; -import com.jetbrains.python.psi.PyQualifiedExpression; +import com.jetbrains.python.psi.PyCallSiteExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,7 +46,7 @@ public interface PyCallableType extends PyType { * Returns the type which is the result of calling an instance of this type. */ @Nullable - PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite); + PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite); /** * Returns the list of parameter types. diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index c27dc4bc04ed..0c60e6555b59 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -35,7 +35,7 @@ public class PyTypeProviderBase implements PyTypeProvider { protected interface ReturnTypeCallback { @Nullable - PyType getType(@Nullable PyQualifiedExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context); + PyType getType(@Nullable PyCallSiteExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context); } private static class ReturnTypeDescriptor { @@ -46,12 +46,13 @@ public class PyTypeProviderBase implements PyTypeProvider { } @Nullable - public PyType get(PyFunction function, @Nullable PyQualifiedExpression callSite, TypeEvalContext context) { + public PyType get(PyFunction function, @Nullable PyCallSiteExpression callSite, TypeEvalContext context) { PyClass containingClass = function.getContainingClass(); if (containingClass != null) { final ReturnTypeCallback typeCallback = myStringToReturnTypeMap.get(containingClass.getQualifiedName()); if (typeCallback != null) { - final PyExpression qualifier = callSite != null ? callSite.getQualifier() : null; + final PyExpression callee = callSite instanceof PyCallExpression ? ((PyCallExpression)callSite).getCallee() : null; + final PyExpression qualifier = callee instanceof PyQualifiedExpression ? ((PyQualifiedExpression)callee).getQualifier() : null; PyType qualifierType = qualifier != null ? context.getType(qualifier) : null; return typeCallback.getType(callSite, qualifierType, context); } @@ -62,7 +63,7 @@ public class PyTypeProviderBase implements PyTypeProvider { private final ReturnTypeCallback mySelfTypeCallback = new ReturnTypeCallback() { @Override - public PyType getType(@Nullable PyQualifiedExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context) { + public PyType getType(@Nullable PyCallSiteExpression callSite, @Nullable PyType qualifierType, TypeEvalContext context) { if (qualifierType instanceof PyClassType) { PyClass aClass = ((PyClassType)qualifierType).getPyClass(); return PyPsiFacade.getInstance(aClass.getProject()).createClassType(aClass, false); @@ -101,7 +102,7 @@ public class PyTypeProviderBase implements PyTypeProvider { } @Override - public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { ReturnTypeDescriptor descriptor; synchronized (myMethodToReturnTypeMap) { descriptor = myMethodToReturnTypeMap.get(function.getName()); diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java index 27207ab31136..18786ed32ee5 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java @@ -20,10 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.jetbrains.numpy.documentation.NumPyDocString; import com.jetbrains.numpy.documentation.NumPyDocStringParameter; -import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyNamedParameter; -import com.jetbrains.python.psi.PyPsiFacade; -import com.jetbrains.python.psi.PyQualifiedExpression; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.PyTypeProviderBase; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -67,9 +64,10 @@ public class NumpyDocStringTypeProvider extends PyTypeProviderBase { @Nullable @Override - public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { if (isInsideNumPy(function)) { - final NumPyDocString docString = NumPyDocString.forFunction(function, callSite); + final PyExpression callee = callSite instanceof PyCallExpression ? ((PyCallExpression)callSite).getCallee() : null; + final NumPyDocString docString = NumPyDocString.forFunction(function, callee); if (docString != null) { final List returns = docString.getReturns(); final PyPsiFacade facade = getPsiFacade(function); diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index ad1d6a24bdc1..bcad2c1a105c 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -95,7 +95,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { if (myDefinitionLevel > 0) { return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1); } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index d7678c2cd871..346d40f3273e 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -120,7 +120,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { @Nullable @Override - public PyType getCallType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { + public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { final String qname = getQualifiedName(function, callSite); if (qname != null) { if (OPEN_FUNCTIONS.contains(qname) && callSite != null) { diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index d31d19ef4da9..bb0c83ed1979 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -56,10 +56,7 @@ public class PyTypeCheckerInspection extends PyInspection { // TODO: Visit decorators with arguments @Override public void visitPyCallExpression(PyCallExpression node) { - final PyExpression callee = node.getCallee(); - if (callee instanceof PyQualifiedExpression) { - checkCallSite((PyQualifiedExpression)callee); - } + checkCallSite(node); } @Override @@ -85,7 +82,7 @@ public class PyTypeCheckerInspection extends PyInspection { } } - private void checkCallSite(@Nullable PyQualifiedExpression callSite) { + private void checkCallSite(@Nullable PyCallSiteExpression callSite) { final Map substitutions = new LinkedHashMap(); final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext); if (results != null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 74d4b4abaeae..d44c848049ba 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -449,7 +449,7 @@ public class PyCallExpressionHelper { } } if (init != null) { - final PyType t = init.getCallType(context, (PyReferenceExpression)callee); + final PyType t = init.getCallType(context, call); if (cls != null) { if (init.getContainingClass() != cls) { if (t instanceof PyCollectionType) { @@ -474,11 +474,11 @@ public class PyCallExpressionHelper { } final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, call); if (providedType instanceof PyCallableType) { - return ((PyCallableType)providedType).getCallType(context, (PyReferenceExpression)callee); + return ((PyCallableType)providedType).getCallType(context, call); } if (target instanceof Callable) { final Callable callable = (Callable)target; - return callable.getCallType(context, (PyReferenceExpression)callee); + return callable.getCallType(context, call); } } } @@ -489,13 +489,7 @@ public class PyCallExpressionHelper { final PyType type = context.getType(callee); if (type instanceof PyCallableType) { final PyCallableType callableType = (PyCallableType)type; - final PyQualifiedExpression callSite = callee instanceof PyQualifiedExpression ? (PyQualifiedExpression)callee : null; - if (callSite != null) { - return callableType.getCallType(context, callSite); - } - else { - return callableType.getReturnType(context); - } + return callableType.getCallType(context, call); } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index acc225b67f22..2531b37bf8b2 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -209,7 +209,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { PyType type = null; for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { type = typeProvider.getCallType(this, callSite, context); diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 0dd75915de12..3dd9f78083d6 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -70,7 +70,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { return context.getReturnType(this); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java index 79535f21f3f4..7b686633cfc8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java @@ -88,7 +88,8 @@ public class PyPrefixExpressionImpl extends PyElementImpl implements PyPrefixExp if (ref != null) { final PsiElement resolved = ref.resolve(); if (resolved instanceof Callable) { - return ((Callable)resolved).getCallType(context, this); + // TODO: Make PyPrefixExpression a PyCallSiteExpression, use getCallType() here and analyze it in PyTypeChecker.analyzeCallSite() + return ((Callable)resolved).getReturnType(context, key); } } return null; diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index dc63784e19aa..520c9b558881 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -21,8 +21,8 @@ import com.intellij.util.Function; import com.intellij.util.ProcessingContext; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.AccessDirection; +import com.jetbrains.python.psi.PyCallSiteExpression; 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 org.jetbrains.annotations.NotNull; @@ -55,7 +55,7 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { return myReturnType; } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 778b8387f85e..34a92e16bf01 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -316,7 +316,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { return getReturnType(context); } diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 229fe2677d12..bb58b68300e8 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -52,7 +52,7 @@ public class PyFunctionType implements PyCallableType { @Nullable @Override - public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) { + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { return myCallable.getCallType(context, callSite); } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index f4a52368a047..9881d6cc106c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -496,16 +496,9 @@ public class PyTypeChecker { } @Nullable - public static AnalyzeCallResults analyzeCallSite(@Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) { - if (callSite == null) { - return null; - } - PsiElement parent = callSite.getParent(); - while (parent instanceof PyParenthesizedExpression) { - parent = ((PyParenthesizedExpression)parent).getContainedExpression(); - } - if (parent instanceof PyCallExpression) { - return analyzeCall((PyCallExpression)parent, context); + public static AnalyzeCallResults analyzeCallSite(@Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { + if (callSite instanceof PyCallExpression) { + return analyzeCall((PyCallExpression)callSite, context); } else if (callSite instanceof PyBinaryExpression) { return analyzeCall((PyBinaryExpression)callSite, context); diff --git a/python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py b/python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py new file mode 100644 index 000000000000..4c6d7657d59d --- /dev/null +++ b/python/testData/inspections/PyCallingNonCallableInspection/callDictSubscriptionExpression.py @@ -0,0 +1,4 @@ +ops = {'and': all, 'or': any} +op = ops['or'] +ops['and']() +op() diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java index 22743ac76b09..2f009d52b6c1 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java @@ -89,6 +89,11 @@ public class PyCallingNonCallableInspectionTest extends PyTestCase { doTest(); } + // PY-13051 + public void testCallDictSubscriptionExpression() { + doTest(); + } + private void doTest() { setLanguageLevel(LanguageLevel.PYTHON27); try {