diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java index dd7d70f929b2..3fe4555051ed 100644 --- a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java +++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java @@ -1,6 +1,6 @@ package com.jetbrains.python.intelliLang; -import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLanguageInjectionHost; import com.jetbrains.python.patterns.PythonPatterns; import com.jetbrains.python.psi.PyElement; import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport; @@ -26,7 +26,12 @@ public class PyLanguageInjectionSupport extends AbstractLanguageInjectionSupport } @Override - public boolean useDefaultInjector(PsiElement host) { + public boolean isApplicableTo(PsiLanguageInjectionHost host) { return host instanceof PyElement; } + + @Override + public boolean useDefaultInjector(PsiLanguageInjectionHost host) { + return true; + } } diff --git a/python/main_pycharm.iml b/python/main_pycharm.iml index b05917390a2a..981f6a1ce273 100644 --- a/python/main_pycharm.iml +++ b/python/main_pycharm.iml @@ -47,6 +47,8 @@ + + diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index adbe3806074f..5a74a6e0f1a3 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -1,6 +1,5 @@ package com.jetbrains.python.psi.impl; -import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; @@ -12,6 +11,7 @@ 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.PyCallableParameter; import com.jetbrains.python.psi.types.PyClassLikeType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -101,7 +101,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable @Override - public List> getParameters(@NotNull TypeEvalContext context) { + public List getParameters(@NotNull TypeEvalContext context) { return null; } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index 3ef7355229b9..180ad2377503 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -1,6 +1,5 @@ package com.jetbrains.python.psi.impl; -import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.util.ArrayUtil; @@ -10,6 +9,7 @@ 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; import com.jetbrains.python.psi.types.PyCallableType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -42,7 +42,7 @@ public class PyJavaMethodType implements PyCallableType { @Nullable @Override - public List> getParameters(@NotNull TypeEvalContext context) { + public List getParameters(@NotNull TypeEvalContext context) { return null; } diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java index 3e5e117a30eb..7505d3a0ca07 100644 --- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java @@ -102,6 +102,11 @@ public class PyDynamicMember { return this; } + public PyDynamicMember toAssignment(String assignee) { + myPsiPath = new PyPsiPath.ToAssignment(myPsiPath, assignee); + return this; + } + public PyDynamicMember toPsiElement(final PsiElement psiElement) { myPsiPath = new PyPsiPath() { diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyPsiPath.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyPsiPath.java index c773926433a6..a9e96f7f8b3f 100644 --- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyPsiPath.java +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyPsiPath.java @@ -240,4 +240,43 @@ public abstract class PyPsiPath { } } } + + public static class ToAssignment extends PyPsiPath { + private final PyPsiPath myParent; + private final String myAssignee; + + public ToAssignment(PyPsiPath parent, String assignee) { + myParent = parent; + myAssignee = assignee; + } + + @Nullable + @Override + public PsiElement resolve(PsiElement context) { + PsiElement parent = myParent.resolve(context); + if (parent == null) { + return null; + } + AssignmentFinder finder = new AssignmentFinder(myAssignee); + parent.accept(finder); + return finder.myResult != null ? finder.myResult : parent; + } + } + + private static class AssignmentFinder extends PyRecursiveElementVisitor { + private final String myAssignee; + private PsiElement myResult; + + public AssignmentFinder(String assignee) { + myAssignee = assignee; + } + + @Override + public void visitPyAssignmentStatement(PyAssignmentStatement node) { + PyExpression lhs = node.getLeftHandSideExpression(); + if (lhs != null && myAssignee.equals(lhs.getText())) { + myResult = node; + } + } + } } 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 40505a9e1c04..c156564506a3 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Callable.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Callable.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; * @author dcheryasov */ -public interface Callable extends PyElement { +public interface Callable extends PyTypedElement { /** * @return a list of parameters passed to this callable, possibly empty. 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 38dfcac02dae..cc3452d52dc6 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 @@ -31,4 +31,7 @@ public interface PyTypeProvider { @Nullable PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context); + + @Nullable + PyType getCallableType(@NotNull Callable callable, @NotNull TypeEvalContext context); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableParameter.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableParameter.java new file mode 100644 index 000000000000..8df290cc9a41 --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyCallableParameter.java @@ -0,0 +1,19 @@ +package com.jetbrains.python.psi.types; + +import com.jetbrains.python.psi.PyParameter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author vlan + */ +public interface PyCallableParameter { + @Nullable + String getName(); + + @Nullable + PyType getType(@NotNull TypeEvalContext context); + + @Nullable + PyParameter getParameter(); +} 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 482df90af817..261a7eb443d2 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 @@ -1,6 +1,5 @@ package com.jetbrains.python.psi.types; -import com.intellij.openapi.util.Pair; import com.jetbrains.python.psi.PyQualifiedExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,8 +31,8 @@ public interface PyCallableType extends PyType { /** * Returns the list of parameter types. * - * @return list of (name, type) pairs or null if not applicable. Name and type in pair may be null. + * @return list of parameter info null if not applicable. */ @Nullable - List> getParameters(@NotNull TypeEvalContext context); + List getParameters(@NotNull TypeEvalContext context); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java index dd6b8c0eda59..672b37fffd0b 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java @@ -13,8 +13,8 @@ import java.util.Collection; public interface PyClassMembersProvider { ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyClassMembersProvider"); - Collection getMembers(PyClassType clazz); + Collection getMembers(PyClassType clazz, @Nullable PsiElement location); @Nullable - PsiElement resolveMember(PyClassType clazz, String name); + PsiElement resolveMember(PyClassType clazz, String name, @Nullable PsiElement location); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java index 4420221c9d6e..ef91d4ef8ddb 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java @@ -13,13 +13,13 @@ import java.util.Collections; */ public class PyClassMembersProviderBase implements PyClassMembersProvider { @Override - public Collection getMembers(PyClassType clazz) { + public Collection getMembers(PyClassType clazz, PsiElement location) { return Collections.emptyList(); } @Override - public PsiElement resolveMember(PyClassType clazz, String name) { - final Collection members = getMembers(clazz); + public PsiElement resolveMember(PyClassType clazz, String name, PsiElement location) { + final Collection members = getMembers(clazz, location); return resolveMemberByName(members, clazz, name); } 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 81988147bd01..aa23c396bab6 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 @@ -102,6 +102,12 @@ public class PyTypeProviderBase implements PyTypeProvider { return null; } + @Nullable + @Override + public PyType getCallableType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + return null; + } + protected void registerSelfReturnType(String classQualifiedName, Collection methods) { registerReturnType(classQualifiedName, methods, mySelfTypeCallback); } diff --git a/python/src/com/jetbrains/python/PyParameterInfoHandler.java b/python/src/com/jetbrains/python/PyParameterInfoHandler.java index 9cff15d75fc2..ff567ffaa17f 100644 --- a/python/src/com/jetbrains/python/PyParameterInfoHandler.java +++ b/python/src/com/jetbrains/python/PyParameterInfoHandler.java @@ -10,6 +10,7 @@ import com.intellij.util.text.CharArrayUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.ParamHelper; import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -110,12 +111,14 @@ public class PyParameterInfoHandler implements ParameterInfoHandler parameterList = Arrays.asList(callable.getParameterList().getParameters()); + final List parameterList = PyUtil.getParameters(callable, typeEvalContext); final List namedParameters = new ArrayList(parameterList.size()); // param -> hint index. indexes are not contiguous, because some hints are parentheses. @@ -123,7 +126,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler flags. this includes flags for parens. final Map> hintFlags = new HashMap>(); - final List hintsList = buildParameterListHint(callable, namedParameters, parameterToIndex, hintFlags); + final List hintsList = buildParameterListHint(parameterList, namedParameters, parameterToIndex, hintFlags); final int currentParamOffset = context.getCurrentParameterIndex(); // in Python mode, we get an offset here, not an index! @@ -268,19 +271,18 @@ public class PyParameterInfoHandler implements ParameterInfoHandler buildParameterListHint(@NotNull final Callable callable, + private static List buildParameterListHint(@NotNull List parameters, @NotNull final List namedParameters, @NotNull final Map parameterToIndex, @NotNull final Map> hintFlags) { - final List hintsList = new ArrayList(); ParamHelper.walkDownParamArray( - callable.getParameterList().getParameters(), + parameters.toArray(new PyParameter[parameters.size()]), new ParamHelper.ParamWalker() { public void enterTupleParameter(PyTupleParameter param, boolean first, boolean last) { hintFlags.put(hintsList.size(), EnumSet.noneOf(ParameterInfoUIContextEx.Flag.class)); diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java index e2576e7c8a4f..231ea319bb1d 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java @@ -1,6 +1,7 @@ package com.jetbrains.python.codeInsight.stdlib; import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiElement; import com.jetbrains.python.codeInsight.PyDynamicMember; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFile; @@ -21,7 +22,7 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase { private Key> mySocketMembersKey = Key.create("socket.members"); @Override - public Collection getMembers(PyClassType classType) { + public Collection getMembers(PyClassType classType, PsiElement location) { PyClass clazz = classType.getPyClass(); final String qualifiedName = clazz.getQualifiedName(); if ("socket._socketobject".equals(qualifiedName)) { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsLineMarkerProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsLineMarkerProvider.java index 624c67e7ce7a..1d538b219042 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsLineMarkerProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsLineMarkerProvider.java @@ -39,7 +39,7 @@ public class PyUserSkeletonsLineMarkerProvider implements LineMarkerProvider { final PyElement skeleton = getUserSkeleton(element); if (skeleton != null) { result.add(new LineMarkerInfo( - element, element.getTextRange(), ICON, Pass.VISIBLE_LINE_MARKERS, + element, element.getTextRange(), ICON, Pass.UPDATE_OVERRIDEN_MARKERS, new Function() { @Override public String fun(PsiElement e) { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java index f93b3b22978c..0a7d129b0018 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsTypeProvider.java @@ -46,4 +46,14 @@ public class PyUserSkeletonsTypeProvider extends PyTypeProviderBase { } return null; } + + @Nullable + @Override + public PyType getCallableType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + final Callable callableSkeleton = PyUserSkeletonsUtil.getUserSkeleton(callable); + if (callableSkeleton != null) { + return context.getType(callableSkeleton); + } + return null; + } } diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index 8e6db24d6d8b..8e42abebebe8 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -2,14 +2,9 @@ package com.jetbrains.python.documentation; import com.google.common.base.Function; import com.google.common.collect.Collections2; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.jetbrains.python.PyNames; -import com.jetbrains.python.psi.Callable; -import com.jetbrains.python.psi.PyNamedParameter; -import com.jetbrains.python.psi.PyParameter; import com.jetbrains.python.psi.types.*; import com.jetbrains.python.toolbox.ChainIterable; import org.jetbrains.annotations.NotNull; @@ -170,7 +165,10 @@ public class PyTypeModelBuilder { final PyTupleType tupleType = (PyTupleType)elementType; final int n = tupleType.getElementCount(); for (int i = 0; i < n; i++) { - elementTypes.add(build(tupleType.getElementType(i), true)); + final PyType t = tupleType.getElementType(i); + if (t != null) { + elementTypes.add(build(t, true)); + } } } else if (elementType != null) { @@ -206,11 +204,11 @@ public class PyTypeModelBuilder { private TypeModel build(@NotNull PyCallableType type) { List parameterModels = null; - final List> parameters = type.getParameters(myContext); + final List parameters = type.getParameters(myContext); if (parameters != null) { parameterModels = new ArrayList(); - for (Pair parameter : parameters) { - parameterModels.add(new ParamType(parameter.getFirst(), build(parameter.getSecond(), true))); + for (PyCallableParameter parameter : parameters) { + parameterModels.add(new ParamType(parameter.getName(), build(parameter.getType(myContext), true))); } } final PyType ret = type.getCallType(myContext, null); @@ -218,27 +216,6 @@ public class PyTypeModelBuilder { return new FunctionType(returnType, parameterModels); } - public TypeModel build(Callable callable) { - final PyType returnType = callable.getReturnType(myContext, null); - return new FunctionType(build(returnType, true), Collections2.transform(Lists.newArrayList(callable.getParameterList().getParameters()), - new Function() { - @Override - public TypeModel apply(PyParameter p) { - final PyNamedParameter np = p.getAsNamed(); - if (np != null) { - TypeModel paramType = _(PyNames.UNKNOWN_TYPE); - final PyType t = myContext.getType(np); - if (t != null) { - paramType = build(t, true); - } - final String name = PyFunctionType.getParameterName(np); - return new ParamType(name, paramType); - } - return new ParamType(p.toString(), null); - } - })); - } - private interface TypeVisitor { void oneOf(OneOf oneOf); diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 2133374f2bec..f9dfdfd352bf 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -15,9 +15,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Function; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; import com.jetbrains.python.console.PydevConsoleRunner; @@ -122,7 +124,19 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i ChainIterable cat = new ChainIterable(); final String name = fun.getName(); cat.addItem("def ").addWith(func_name_wrapper, $(name)); - cat.addItem(escaper.apply(PyUtil.getReadableRepr(fun.getParameterList(), false))); + final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getContainingFile()); + final List parameters = PyUtil.getParameters(fun, context); + final String paramStr = "(" + + StringUtil.join(parameters, + new Function() { + @Override + public String fun(PyParameter parameter) { + return PyUtil.getReadableRepr(parameter, false); + } + }, + ", ") + + ")"; + cat.addItem(escaper.apply(paramStr)); if (!PyNames.INIT.equals(name)) { cat.addItem(escaper.apply("\nInferred type: ")); getTypeDescription(fun, cat); @@ -157,16 +171,10 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i return String.format("Inferred type: %s", getTypeName(context.getType(element), context)); } - public static String getTypeDescription(@NotNull PyFunction fun) { - final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getContainingFile()); - PyTypeModelBuilder builder = new PyTypeModelBuilder(context); - return builder.build(fun).asString(); - } - public static void getTypeDescription(@NotNull PyFunction fun, ChainIterable body) { final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getContainingFile()); PyTypeModelBuilder builder = new PyTypeModelBuilder(context); - builder.build(fun).toBodyWithLinks(body, fun); + builder.build(context.getType(fun), true).toBodyWithLinks(body, fun); } public static String getTypeName(@Nullable PyType type, @NotNull final TypeEvalContext context) { @@ -552,27 +560,28 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i private static String generateContent(PyFunction function, String offset, String prefix, boolean checkReturn) { //TODO: this code duplicates PyDocstringGenerator in some parts - PyParameter[] list = function.getParameterList().getParameters(); - StringBuilder builder = new StringBuilder(offset); + final StringBuilder builder = new StringBuilder(offset); + final TypeEvalContext context = TypeEvalContext.userInitiated(function.getContainingFile()); PySignature signature = PySignatureCacheManager.getInstance(function.getProject()).findSignature(function); - for (PyParameter p : list) { - if (p.getText().equals(PyNames.CANONICAL_SELF) || p.getName() == null) { + for (PyParameter p : PyUtil.getParameters(function, context)) { + final String parameterName = p.getName(); + if (p.getText().equals(PyNames.CANONICAL_SELF) || parameterName == null) { continue; } - String argType = signature == null ? null : signature.getArgTypeQualifiedName(p.getName()); + String argType = signature == null ? null : signature.getArgTypeQualifiedName(parameterName); if (argType == null) { builder.append(prefix); builder.append("param "); - builder.append(p.getName()); + builder.append(parameterName); builder.append(": "); builder.append(offset); } if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB || argType != null) { builder.append(prefix); builder.append("type "); - builder.append(p.getName()); + builder.append(parameterName); builder.append(": "); if (signature != null) { builder.append(PySignatureUtil.getShortestImportableName(function, argType)); diff --git a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java index 23a538cb632e..9114b10c3d84 100644 --- a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java +++ b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java @@ -74,7 +74,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx { } @Nullable - private static UsageType checkMatchingSignatureGroup(PyCallExpression call, UsageTarget[] targets, TypeEvalContext context) { + private static UsageType checkMatchingSignatureGroup(PyCallExpression call, UsageTarget[] targets, @NotNull TypeEvalContext context) { if (targets.length == 1 && targets[0] instanceof PsiElementUsageTarget) { final PsiElement element = ((PsiElementUsageTarget)targets[0]).getElement(); if (element instanceof PyFunction) { diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java index 3c40839d3853..b6c5b7be30a2 100644 --- a/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java @@ -57,16 +57,17 @@ public class PyArgumentListInspection extends PyInspection { if (mkfunc != null && !mkfunc.isImplicitlyResolved()) { Callable callable = mkfunc.getCallable(); int first_param_offset = mkfunc.getImplicitOffset(); - PyParameter[] params = callable.getParameterList().getParameters(); - PyNamedParameter alleged_first_param = params.length < first_param_offset ? null : params[first_param_offset-1].getAsNamed(); + final List params = PyUtil.getParameters(callable, myTypeEvalContext); + final PyNamedParameter alleged_first_param = params.size() < first_param_offset ? + null : params.get(first_param_offset-1).getAsNamed(); if (alleged_first_param == null || alleged_first_param.isKeywordContainer()) { // no parameters left to pass function implicitly, or wrong param type registerProblem(deco, PyBundle.message("INSP.func.$0.lacks.first.arg", callable.getName())); // TODO: better names for anon lambdas } else { // possible unfilled params - for (int i=first_param_offset; i < params.length; i += 1) { - PyNamedParameter par = params[i].getAsNamed(); + for (int i=first_param_offset; i < params.size(); i += 1) { + PyNamedParameter par = params.get(i).getAsNamed(); // param tuples, non-starred or non-default won't do if (par == null || (! par.isKeywordContainer() && ! par.isPositionalContainer() && !par.hasDefaultValue())) { String par_name; @@ -87,7 +88,7 @@ public class PyArgumentListInspection extends PyInspection { public static void inspectPyArgumentList(PyArgumentList node, ProblemsHolder holder, final TypeEvalContext context, int implicitOffset) { if (node.getParent() instanceof PyClass) return; // class Foo(object) is also an arg list CallArgumentsMapping result = node.analyzeCall(PyResolveContext.noImplicits().withTypeEvalContext(context), implicitOffset); - highlightIncorrectArguments(holder, result); + highlightIncorrectArguments(holder, result, context); highlightMissingArguments(node, holder, result); highlightStarArgumentTypeMismatch(node, holder, context); } @@ -96,7 +97,7 @@ public class PyArgumentListInspection extends PyInspection { inspectPyArgumentList(node, holder, context, 0); } - private static void highlightIncorrectArguments(ProblemsHolder holder, CallArgumentsMapping result) { + private static void highlightIncorrectArguments(ProblemsHolder holder, CallArgumentsMapping result, @NotNull TypeEvalContext context) { for (Map.Entry> argEntry : result.getArgumentFlags().entrySet()) { EnumSet flags = argEntry.getValue(); if (!flags.isEmpty()) { // something's wrong @@ -120,9 +121,9 @@ public class PyArgumentListInspection extends PyInspection { final PyCallExpression.PyMarkedCallee markedCallee = result.getMarkedCallee(); String parameterName = null; if (markedCallee != null) { - final PyParameter[] parameters = markedCallee.getCallable().getParameterList().getParameters(); - for (int i = parameters.length - 1; i >= 0; --i) { - final PyParameter param = parameters[i]; + final List parameters = PyUtil.getParameters(markedCallee.getCallable(), context); + for (int i = parameters.size() - 1; i >= 0; --i) { + final PyParameter param = parameters.get(i); if (param instanceof PyNamedParameter) { final List unmappedParams = result.getUnmappedParams(); if (!((PyNamedParameter)param).isPositionalContainer() && !((PyNamedParameter)param).isKeywordContainer() && diff --git a/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java b/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java index 72aca8cbd9a2..b2d557941f7b 100644 --- a/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java @@ -12,6 +12,7 @@ import com.jetbrains.python.psi.types.PyType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import java.util.List; import java.util.Map; import static com.jetbrains.python.psi.PyFunction.Modifier.CLASSMETHOD; @@ -77,9 +78,9 @@ public class PyCallByClassInspection extends PyInspection { CallArgumentsMapping analysis = arglist.analyzeCall(resolveWithoutImplicits()); final PyCallExpression.PyMarkedCallee markedCallee = analysis.getMarkedCallee(); if (markedCallee != null && markedCallee.getModifier() != STATICMETHOD) { - PyParameter[] params = markedCallee.getCallable().getParameterList().getParameters(); - if (params.length > 0 && params[0] instanceof PyNamedParameter) { - PyNamedParameter first_param = (PyNamedParameter)params[0]; + final List params = PyUtil.getParameters(markedCallee.getCallable(), myTypeEvalContext); + if (params.size() > 0 && params.get(0) instanceof PyNamedParameter) { + PyNamedParameter first_param = (PyNamedParameter)params.get(0); for (Map.Entry entry : analysis.getPlainMappedParams().entrySet()) { // we ignore *arg and **arg which we cannot analyze if (entry.getValue() == first_param) { diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 9002e762105f..757664c8915f 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -63,7 +63,7 @@ public class PyTypeCheckerInspection extends PyInspection { final PyExpression source = node.getForPart().getSource(); if (source != null) { final PyType type = myTypeEvalContext.getType(source); - if (!PyTypeChecker.isUnknown(type) && !PyABCUtil.isSubtype(type, PyNames.ITERABLE)) { + if (type != null && !PyTypeChecker.isUnknown(type) && !PyABCUtil.isSubtype(type, PyNames.ITERABLE)) { registerProblem(source, String.format("Expected 'collections.Iterable', got '%s' instead", PythonDocumentationProvider.getTypeName(type, myTypeEvalContext))); } diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 71c0faac02a2..ac6a5cd69131 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -653,7 +653,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (isDecoratedAsDynamic(cls, true)) { return true; } - if (hasUnresolvedDynamicMember((PyClassType)qtype, refText)) return true; + if (hasUnresolvedDynamicMember((PyClassType)qtype, reference, refText)) return true; } if (qtype instanceof CythonBuiltinType || (qtype instanceof CythonType && reference instanceof PyOperatorReference)) { @@ -668,9 +668,11 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return false; } - private static boolean hasUnresolvedDynamicMember(@NotNull final PyClassType qtype, @NotNull final String refText) { + private static boolean hasUnresolvedDynamicMember(@NotNull final PyClassType qtype, + PsiReference reference, + @NotNull final String refText) { for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { - final Collection resolveResult = provider.getMembers(qtype); + final Collection resolveResult = provider.getMembers(qtype, reference.getElement()); for (PyDynamicMember member : resolveResult) { if (member.getName().equals(refText)) return true; } diff --git a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java index c4ab81b1eaa8..2f54b99a80b1 100644 --- a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java +++ b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java @@ -57,7 +57,8 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel { } private Sdk getSelectedSdk() { - return ((PyPackageManagementService) myPackageManagementService).getSdk(); + PyPackageManagementService service = (PyPackageManagementService)myPackageManagementService; + return service != null ? service.getSdk() : null; } public void updateNotifications(@NotNull final Sdk selectedSdk) { diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 5ade1e62cdca..e1413a826059 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -1238,5 +1238,32 @@ public class PyUtil { } return element; } -} + @NotNull + public static List getParameters(@NotNull Callable callable, @NotNull TypeEvalContext context) { + PyType type = context.getType(callable); + if (type instanceof PyUnionType) { + type = ((PyUnionType)type).excludeNull(); + } + if (type instanceof PyCallableType) { + final PyCallableType callableType = (PyCallableType)type; + final List callableTypeParameters = callableType.getParameters(context); + if (callableTypeParameters != null) { + boolean allParametersDefined = true; + final List parameters = new ArrayList(); + for (PyCallableParameter callableParameter : callableTypeParameters) { + final PyParameter parameter = callableParameter.getParameter(); + if (parameter == null) { + allParametersDefined = false; + break; + } + parameters.add(parameter); + } + if (allParametersDefined) { + return parameters; + } + } + } + return Arrays.asList(callable.getParameterList().getParameters()); + } +} diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index e8cddd605855..7122f4c93bc2 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -3,9 +3,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.types.PyTupleType; -import com.jetbrains.python.psi.types.PyType; -import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,7 +47,7 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { * @param resolved_callee what to map parameters of * @param context optional shared type evaluator / cache. */ - public void mapArguments(PyCallExpression.PyMarkedCallee resolved_callee, @Nullable TypeEvalContext context) { + public void mapArguments(PyCallExpression.PyMarkedCallee resolved_callee, @NotNull TypeEvalContext context) { PyExpression[] arguments = myArgumentList.getArguments(); myMarkedCallee = resolved_callee; List unmatched_args = new LinkedList(); @@ -75,8 +73,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { } } } + final List parameters = PyUtil.getParameters(myMarkedCallee.getCallable(), context); // prepare parameter slots - final PyParameter[] parameters = myMarkedCallee.getCallable().getParameterList().getParameters(); Map slots = new LinkedHashMap(); PyNamedParameter kwd_par = null; // **param PyNamedParameter tuple_par = null; // *param @@ -109,8 +107,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { i += 1; } // rule out 'self' or other implicit params - for (i=0; i < implicit_offset && i < parameters.length; i+=1) { - slots.remove(parameters[i].getAsNamed()); + for (i=0; i < implicit_offset && i < parameters.size(); i+=1) { + slots.remove(parameters.get(i).getAsNamed()); positional_index += 1; } // now params to the left of positional_index are positional. @@ -125,8 +123,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { positional_bound = cnt; break; } - if (cnt < parameters.length && cnt < positional_index) { - final PyParameter par = parameters[cnt]; + if (cnt < parameters.size() && cnt < positional_index) { + final PyParameter par = parameters.get(cnt); PyNamedParameter n_par = par.getAsNamed(); if (n_par != null) { cnt += 1; @@ -203,14 +201,12 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { // map *arg to positional params if possible boolean tuple_arg_not_exhausted = false; boolean tuple_dup_found = false; - if (cnt < parameters.length && cnt < positional_index && myTupleArg != null) { + if (cnt < parameters.size() && cnt < positional_index && myTupleArg != null) { // check length of myTupleArg PyType tuple_arg_type = null; - if (context != null) { - final PyExpression expression = PsiTreeUtil.getChildOfType(myTupleArg, PyExpression.class); - if (expression != null) { - tuple_arg_type = context.getType(expression); - } + final PyExpression expression = PsiTreeUtil.getChildOfType(myTupleArg, PyExpression.class); + if (expression != null) { + tuple_arg_type = context.getType(expression); } int tuple_length; boolean tuple_length_known; @@ -223,8 +219,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { tuple_length_known = false; } int mapped_params_count = 0; - while (cnt < parameters.length && cnt < positional_index && mapped_params_count < tuple_length) { - PyParameter par = parameters[cnt]; + while (cnt < parameters.size() && cnt < positional_index && mapped_params_count < tuple_length) { + PyParameter par = parameters.get(cnt); if (par instanceof PySingleStarParameter) break; PyNamedParameter n_par = par.getAsNamed(); if (slots.containsKey(n_par)) { @@ -257,7 +253,7 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { if ( tuple_length_known && (mapped_params_count < tuple_length) || // not exhausted mapped_params_count == 0 // unknown length must consume at least first param - ) { + ) { tuple_arg_not_exhausted = true; } } @@ -336,7 +332,6 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { markArgument(arg, ArgFlag.IS_UNMAPPED); } } - } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index b9fa2e3be6c1..0a7addcb4f9c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -3,6 +3,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -15,7 +16,10 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.*; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; -import com.jetbrains.python.*; +import com.jetbrains.python.PyElementTypes; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; @@ -53,22 +57,16 @@ public class PyClassImpl extends PyPresentableElementImpl implement private volatile Map myPropertyCache; - private class CachedAncestorsProvider implements CachedValueProvider> { - @Nullable private TypeEvalContext myCachedContext; - + private class CachedAncestorsProvider implements ParameterizedCachedValueProvider, TypeEvalContext> { @Nullable @Override - public Result> compute() { - final TypeEvalContext context = myCachedContext != null ? myCachedContext : TypeEvalContext.codeInsightFallback(); + public CachedValueProvider.Result> compute(@NotNull TypeEvalContext context) { final List ancestorTypes = isNewStyleClass() ? getMROAncestorTypes(context) : getOldStyleAncestorTypes(context); - return Result.create(ancestorTypes, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); - } - - private void setTypeEvalContext(@Nullable TypeEvalContext cachedContext) { - myCachedContext = cachedContext; + return CachedValueProvider.Result.create(ancestorTypes, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } } + private final Key, TypeEvalContext>> myCachedValueKey = Key.create("cached ancestors"); private final CachedAncestorsProvider myCachedAncestorsProvider = new CachedAncestorsProvider(); @Override @@ -1098,14 +1096,9 @@ public class PyClassImpl extends PyPresentableElementImpl implement @NotNull @Override public List getAncestorTypes(@NotNull TypeEvalContext context) { - myCachedAncestorsProvider.setTypeEvalContext(context); - try { - // TODO: Return different cached copies depending on the type eval context parameters - return CachedValuesManager.getManager(getProject()).getCachedValue(this, myCachedAncestorsProvider); - } - finally { - myCachedAncestorsProvider.setTypeEvalContext(null); - } + // TODO: Return different cached copies depending on the type eval context parameters + final CachedValuesManager manager = CachedValuesManager.getManager(getProject()); + return manager.getParameterizedCachedValue(this, myCachedValueKey, myCachedAncestorsProvider, false, context); } @NotNull diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 81392e382669..310641880a04 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -342,6 +342,12 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp @Override public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { + for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { + final PyType type = provider.getCallableType(this, context); + if (type != null) { + return type; + } + } final PyFunctionType type = new PyFunctionType(this); if (getDecoratorList() != null) { return PyUnionType.createWeakType(type); diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index fc31ce2e21a3..9bf0de63425e 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -1,6 +1,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; +import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; @@ -24,6 +25,12 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp } public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { + for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { + final PyType type = provider.getCallableType(this, context); + if (type != null) { + return type; + } + } return new PyFunctionType(this); } diff --git a/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java b/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java index c97a4deffba3..e018a99d541f 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java +++ b/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java @@ -11,6 +11,7 @@ import com.jetbrains.python.psi.impl.PyKeywordArgumentProvider; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.QualifiedResolveResult; import com.jetbrains.python.psi.search.PySuperMethodsSearch; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -50,7 +51,11 @@ public class KeywordArgumentCompletionUtil { visited.add(def); boolean needSelf = def.getContainingClass() != null && def.getModifier() != PyFunction.Modifier.STATICMETHOD; final KwArgParameterCollector collector = new KwArgParameterCollector(needSelf, ret); - def.getParameterList().acceptChildren(collector); + final TypeEvalContext context = TypeEvalContext.userInitiated(def.getContainingFile()); + final List parameters = PyUtil.getParameters(def, context); + for (PyParameter parameter : parameters) { + parameter.accept(collector); + } if (collector.hasKwArgs()) { for (PyKeywordArgumentProvider provider : Extensions.getExtensions(PyKeywordArgumentProvider.EP_NAME)) { final List arguments = provider.getKeywordArguments(def, callExpr); diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableParameterImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableParameterImpl.java new file mode 100644 index 000000000000..27dbf1bf8d35 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/types/PyCallableParameterImpl.java @@ -0,0 +1,57 @@ +package com.jetbrains.python.psi.types; + +import com.jetbrains.python.psi.PyNamedParameter; +import com.jetbrains.python.psi.PyParameter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author vlan + */ +public class PyCallableParameterImpl implements PyCallableParameter { + @Nullable private final String myName; + @Nullable private final PyType myType; + @Nullable private final PyParameter myElement; + + public PyCallableParameterImpl(@Nullable String name, @Nullable PyType type) { + myName = name; + myType = type; + myElement = null; + } + + public PyCallableParameterImpl(@Nullable PyParameter element) { + myName = null; + myType = null; + myElement = element; + } + + @Nullable + @Override + public String getName() { + if (myName != null) { + return myName; + } + else if (myElement != null) { + return myElement.getName(); + } + return null; + } + + @Nullable + @Override + public PyType getType(@NotNull TypeEvalContext context) { + if (myType != null) { + return myType; + } + else if (myElement instanceof PyNamedParameter) { + return context.getType((PyNamedParameter)myElement); + } + return null; + } + + @Nullable + @Override + public PyParameter getParameter() { + return myElement; + } +} diff --git a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index 8b3cb754b437..c1483a2b446b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -1,6 +1,5 @@ package com.jetbrains.python.psi.types; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.ProcessingContext; @@ -19,10 +18,10 @@ import java.util.List; * @author vlan */ public class PyCallableTypeImpl implements PyCallableType { - @Nullable private final List> myParameters; + @Nullable private final List myParameters; @Nullable private final PyType myReturnType; - public PyCallableTypeImpl(@Nullable List> parameters, @Nullable PyType returnType) { + public PyCallableTypeImpl(@Nullable List parameters, @Nullable PyType returnType) { myParameters = parameters; myReturnType = returnType; } @@ -40,7 +39,7 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable @Override - public List> getParameters(@NotNull TypeEvalContext context) { + public List getParameters(@NotNull TypeEvalContext context) { return myParameters; } @@ -61,16 +60,17 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable @Override public String getName() { + final TypeEvalContext context = TypeEvalContext.codeInsightFallback(); return String.format("(%s) -> %s", myParameters != null ? StringUtil.join(myParameters, - new Function, String>() { + new Function() { @Override - public String fun(Pair param) { + public String fun(PyCallableParameter param) { if (param != null) { final StringBuilder builder = new StringBuilder(); - final String name = param.getFirst(); - final PyType type = param.getSecond(); + final String name = param.getName(); + final PyType type = param.getType(context); if (name != null) { builder.append(name); if (type != null) { diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 446aba417165..046bb1fac020 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -135,7 +135,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @NotNull PyResolveContext resolveContext, boolean inherited) { final TypeEvalContext context = resolveContext.getTypeEvalContext(); - PsiElement classMember = resolveByOverridingMembersProviders(this, name); //overriding members provers have priority to normal resolve + PsiElement classMember = resolveByOverridingMembersProviders(this, name, location); //overriding members provers have priority to normal resolve if (classMember != null) { return ResolveResultList.to(classMember); } @@ -211,7 +211,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } if (inherited) { - classMember = resolveByMembersProviders(this, name); //ask providers after real class introspection as providers have less priority + classMember = resolveByMembersProviders(this, name, location); //ask providers after real class introspection as providers have less priority } if (classMember != null) { @@ -223,7 +223,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { if (type instanceof PyClassType) { final PyClass pyClass = ((PyClassType)type).getPyClass(); if (pyClass != null) { - PsiElement superMember = resolveByMembersProviders(new PyClassTypeImpl(pyClass, isDefinition()), name); + PsiElement superMember = resolveByMembersProviders(new PyClassTypeImpl(pyClass, isDefinition()), name, location); if (superMember != null) { return ResolveResultList.to(superMember); @@ -279,7 +279,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override - public List> getParameters(@NotNull TypeEvalContext context) { + public List getParameters(@NotNull TypeEvalContext context) { return null; } @@ -296,9 +296,9 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } @Nullable - private static PsiElement resolveByMembersProviders(PyClassType aClass, String name) { + private static PsiElement resolveByMembersProviders(PyClassType aClass, String name, @Nullable PsiElement location) { for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { - final PsiElement resolveResult = provider.resolveMember(aClass, name); + final PsiElement resolveResult = provider.resolveMember(aClass, name, location); if (resolveResult != null) return resolveResult; } @@ -306,10 +306,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } @Nullable - private static PsiElement resolveByOverridingMembersProviders(PyClassType aClass, String name) { + private static PsiElement resolveByOverridingMembersProviders(PyClassType aClass, String name, @Nullable PsiElement location) { for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { if (provider instanceof PyOverridingClassMembersProvider) { - final PsiElement resolveResult = provider.resolveMember(aClass, name); + final PsiElement resolveResult = provider.resolveMember(aClass, name, location); if (resolveResult != null) return resolveResult; } } @@ -361,7 +361,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { // from providers for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { - for (PyDynamicMember member : provider.getMembers(this)) { + for (PyDynamicMember member : provider.getMembers(this, location)) { final String name = member.getName(); if (!namesAlready.contains(name)) { LookupElementBuilder lookupElementBuilder = LookupElementBuilder.create(name).withIcon(member.getIcon()).withTypeText(getName()); diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 20072ba86284..43ef7ddcc3f7 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -1,6 +1,5 @@ package com.jetbrains.python.psi.types; -import com.intellij.openapi.util.Pair; import com.intellij.util.ProcessingContext; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -37,13 +36,10 @@ public class PyFunctionType implements PyCallableType { @Nullable @Override - public List> getParameters(@NotNull TypeEvalContext context) { - final List> result = new ArrayList>(); + public List getParameters(@NotNull TypeEvalContext context) { + final List result = new ArrayList(); for (PyParameter parameter : myCallable.getParameterList().getParameters()) { - if (parameter instanceof PyNamedParameter) { - final PyNamedParameter namedParameter = (PyNamedParameter)parameter; - result.add(Pair.create(getParameterName(namedParameter), context.getType(namedParameter))); - } + result.add(new PyCallableParameterImpl(parameter)); } return result; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 4c3660dcbdb3..9cd26ffba127 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -1,6 +1,5 @@ package com.jetbrains.python.psi.types; -import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; @@ -145,15 +144,15 @@ public class PyTypeChecker { final PyCallableType expectedCallable = (PyCallableType)expected; final PyCallableType actualCallable = (PyCallableType)actual; if (expectedCallable.isCallable() && actualCallable.isCallable()) { - final List> expectedParameters = expectedCallable.getParameters(context); - final List> actualParameters = actualCallable.getParameters(context); + final List expectedParameters = expectedCallable.getParameters(context); + final List actualParameters = actualCallable.getParameters(context); if (expectedParameters != null && actualParameters != null) { final int size = Math.min(expectedParameters.size(), actualParameters.size()); for (int i = 0; i < size; i++) { - final Pair expectedParam = expectedParameters.get(i); - final Pair actualParam = actualParameters.get(i); + final PyCallableParameter expectedParam = expectedParameters.get(i); + final PyCallableParameter actualParam = actualParameters.get(i); // TODO: Check named and star params, not only positional ones - if (!match(expectedParam.getSecond(), actualParam.getSecond(), context, substitutions, recursive)) { + if (!match(expectedParam.getType(context), actualParam.getType(context), context, substitutions, recursive)) { return false; } } @@ -234,11 +233,11 @@ public class PyTypeChecker { } else if (type instanceof PyCallableType) { final PyCallableType callable = (PyCallableType)type; - final List> parameters = callable.getParameters(context); + final List parameters = callable.getParameters(context); if (parameters != null) { - for (Pair parameter : parameters) { + for (PyCallableParameter parameter : parameters) { if (parameter != null) { - collectGenerics(parameter.getSecond(), context, collected, visited); + collectGenerics(parameter.getType(context), context, collected, visited); } } } @@ -280,12 +279,16 @@ public class PyTypeChecker { } else if (type instanceof PyCallableType) { final PyCallableType callable = (PyCallableType)type; - List> substParams = null; - final List> parameters = callable.getParameters(context); + List substParams = null; + final List parameters = callable.getParameters(context); if (parameters != null) { - substParams = new ArrayList>(); - for (Pair parameter : parameters) { - substParams.add(Pair.create(parameter.getFirst(), substitute(parameter.getSecond(), substitutions, context))); + substParams = new ArrayList(); + for (PyCallableParameter parameter : parameters) { + final PyType substType = substitute(parameter.getType(context), substitutions, context); + final PyCallableParameter subst = parameter.getParameter() != null ? + new PyCallableParameterImpl(parameter.getParameter()) : + new PyCallableParameterImpl(parameter.getName(), substType); + substParams.add(subst); } } final PyType substResult = substitute(callable.getCallType(context, null), substitutions, context); diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index 7aab2400b333..7150ab1413ae 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -230,7 +230,7 @@ public class PyTypeParser { new Function>, ParseResult>, ParseResult>() { @Override public ParseResult fun(Pair>, ParseResult> value) { - final List> parameters = new ArrayList>(); + final List parameters = new ArrayList(); final ParseResult returnResult = value.getSecond(); ParseResult result; final Pair> firstPair = value.getFirst(); @@ -238,10 +238,10 @@ public class PyTypeParser { final ParseResult first = firstPair.getFirst(); final List second = firstPair.getSecond(); result = first; - parameters.add(Pair.create(null, first.getType())); + parameters.add(new PyCallableParameterImpl((String)null, first.getType())); for (ParseResult r : second) { result = result.merge(r); - parameters.add(Pair.create(null, r.getType())); + parameters.add(new PyCallableParameterImpl((String)null, r.getType())); } result = result.merge(returnResult); } diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index c69beca25529..ef6688bc5c61 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -29,17 +29,17 @@ public class PyUnionType implements PyType { @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext) { SmartList ret = new SmartList(); - boolean all_nulls = true; + boolean allNulls = true; for (PyType member : myMembers) { if (member != null) { - List result = member.resolveMember(name, null, direction, resolveContext); + List result = member.resolveMember(name, location, direction, resolveContext); if (result != null) { - all_nulls = false; + allNulls = false; ret.addAll(result); } } } - return all_nulls ? null : ret; + return allNulls ? null : ret; } public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) { diff --git a/python/src/com/jetbrains/python/psi/types/functionalParser/FunctionalParserBase.java b/python/src/com/jetbrains/python/psi/types/functionalParser/FunctionalParserBase.java index c8c571764d5f..f7420b849b18 100644 --- a/python/src/com/jetbrains/python/psi/types/functionalParser/FunctionalParserBase.java +++ b/python/src/com/jetbrains/python/psi/types/functionalParser/FunctionalParserBase.java @@ -35,46 +35,12 @@ public abstract class FunctionalParserBase implements FunctionalParser FunctionalParser, T> token(@NotNull final T type, @Nullable final String text) { - return new FunctionalParserBase, T>() { - @NotNull - @Override - public Pair, State> parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final int pos = state.getPos(); - if (pos >= tokens.size()) { - throw new ParserException("No tokens left", state); - } - final Token token = tokens.get(pos); - if (token.getType().equals(type) && (text == null || token.getText().equals(text))) { - final int newPos = pos + 1; - final State newState = new State(state, newPos, Math.max(newPos, state.getMax())); - return Pair.create(token, newState); - } - final String expected = text != null ? String.format("Token(<%s>, \"%s\")", type, text) : String.format("Token(<%s>)", type); - throw new ParserException(String.format("Expected %s, found %s", expected, token), state); - } - }; + return new TokenParser(type, text); } @NotNull public static FunctionalParser, T> many(@NotNull final FunctionalParser parser) { - return new FunctionalParserBase, T>() { - @NotNull - @Override - public Pair, State> parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final List list = new ArrayList(); - try { - //noinspection InfiniteLoopStatement - while (true) { - final Pair result = parser.parse(tokens, state); - state = result.getSecond(); - list.add(result.getFirst()); - } - } - catch (ParserException e) { - return Pair.create(list, new State(state, state.getPos(), e.getState().getMax())); - } - } - }; + return new ManyParser(parser); } @NotNull @@ -98,45 +64,13 @@ public abstract class FunctionalParserBase implements FunctionalParser cached() { - final FunctionalParser thisParser = this; - return new FunctionalParserBase() { - private Object myKey = null; - private Map>> myCache = new HashMap>>(); - - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - if (myKey != state.getKey()) { - myKey = state.getKey(); - myCache.clear(); - } - final SoftReference> ref = myCache.get(state.getPos()); - if (ref != null) { - final Pair cached = ref.get(); - if (cached != null) { - return cached; - } - } - final Pair result = thisParser.parse(tokens, state); - myCache.put(state.getPos(), new SoftReference>(result)); - return result; - } - }; + return new CachedParser(this); } @NotNull @Override public FunctionalParser, T> then(@NotNull final FunctionalParser parser) { - final FunctionalParser thisParser = this; - return new FunctionalParserBase, T>() { - @NotNull - @Override - public Pair, State> parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final Pair result1 = thisParser.parse(tokens, state); - final Pair result2 = parser.parse(tokens, result1.getSecond()); - return Pair.create(Pair.create(result1.getFirst(), result2.getFirst()), result2.getSecond()); - } - }; + return new ThenParser(this, parser); } @NotNull @@ -154,82 +88,227 @@ public abstract class FunctionalParserBase implements FunctionalParser or(@NotNull final FunctionalParser parser) { - final FunctionalParserBase thisParser = this; - return new FunctionalParserBase() { - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - try { - return thisParser.parse(tokens, state); - } - catch (ParserException e) { - return parser.parse(tokens, new State(state, state.getPos(), e.getState().getMax())); - } - } - }; + return new OrParser(this, parser); } @NotNull @Override public FunctionalParser map(@NotNull final Function f) { - final FunctionalParserBase thisParser = this; - return new FunctionalParserBase() { - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final Pair result = thisParser.parse(tokens, state); - return Pair.create(f.fun(result.getFirst()), result.getSecond()); - } - }; + return new MapParser(this, f); } @NotNull private static FunctionalParser first(@NotNull final FunctionalParser, T> parser) { - return new FunctionalParserBase() { - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final Pair, State> result = parser.parse(tokens, state); - return Pair.create(result.getFirst().getFirst(), result.getSecond()); - } - }; + return new FirstParser(parser); } @NotNull private static FunctionalParser second(@NotNull final FunctionalParser, T> parser) { - return new FunctionalParserBase() { - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final Pair, State> result = parser.parse(tokens, state); - return Pair.create(result.getFirst().getSecond(), result.getSecond()); - } - }; + return new SecondParser(parser); } @NotNull private static FunctionalParser finished() { - return new FunctionalParserBase() { - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - final int pos = state.getPos(); - if (pos >= tokens.size()) { - return Pair.create(null, state); - } - throw new ParserException(String.format("Expected end of input, found %s", tokens.get(pos)), state); - } - }; + return new FinishedParser(); } @NotNull private static FunctionalParser pure(@Nullable final R value) { - return new FunctionalParserBase() { - @NotNull - @Override - public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { - return Pair.create(value, state); + return new PureParser(value); + } + + private static class TokenParser extends FunctionalParserBase, T> { + @NotNull private final T myType; + @Nullable private final String myText; + + public TokenParser(@NotNull T type, @Nullable String text) { + myType = type; + myText = text; + } + + @NotNull + @Override + public Pair, State> parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final int pos = state.getPos(); + if (pos >= tokens.size()) { + throw new ParserException("No tokens left", state); } - }; + final Token token = tokens.get(pos); + if (token.getType().equals(myType) && (myText == null || token.getText().equals(myText))) { + final int newPos = pos + 1; + final State newState = new State(state, newPos, Math.max(newPos, state.getMax())); + return Pair.create(token, newState); + } + final String expected = myText != null ? String.format("Token(<%s>, \"%s\")", myType, myText) : String.format("Token(<%s>)", myType); + throw new ParserException(String.format("Expected %s, found %s", expected, token), state); + } + } + + private static class ManyParser extends FunctionalParserBase, T> { + @NotNull private final FunctionalParser myParser; + + public ManyParser(@NotNull FunctionalParser parser) { + myParser = parser; + } + + @NotNull + @Override + public Pair, State> parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final List list = new ArrayList(); + try { + //noinspection InfiniteLoopStatement + while (true) { + final Pair result = myParser.parse(tokens, state); + state = result.getSecond(); + list.add(result.getFirst()); + } + } + catch (ParserException e) { + return Pair.create(list, new State(state, state.getPos(), e.getState().getMax())); + } + } + } + + private static class CachedParser extends FunctionalParserBase { + @NotNull private final FunctionalParser myParser; + @Nullable private Object myKey; + @NotNull private Map>> myCache; + + public CachedParser(@NotNull FunctionalParser parser) { + myParser = parser; + myKey = null; + myCache = new HashMap>>(); + } + + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + if (myKey != state.getKey()) { + myKey = state.getKey(); + myCache.clear(); + } + final SoftReference> ref = myCache.get(state.getPos()); + if (ref != null) { + final Pair cached = ref.get(); + if (cached != null) { + return cached; + } + } + final Pair result = myParser.parse(tokens, state); + myCache.put(state.getPos(), new SoftReference>(result)); + return result; + } + } + + private static class OrParser extends FunctionalParserBase { + @NotNull private final FunctionalParserBase myFirst; + @NotNull private final FunctionalParser mySecond; + + public OrParser(@NotNull FunctionalParserBase first, @NotNull FunctionalParser second) { + myFirst = first; + mySecond = second; + } + + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + try { + return myFirst.parse(tokens, state); + } + catch (ParserException e) { + return mySecond.parse(tokens, new State(state, state.getPos(), e.getState().getMax())); + } + } + } + + private static class FirstParser extends FunctionalParserBase { + @NotNull private final FunctionalParser, T> myParser; + + public FirstParser(@NotNull FunctionalParser, T> parser) { + myParser = parser; + } + + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final Pair, State> result = myParser.parse(tokens, state); + return Pair.create(result.getFirst().getFirst(), result.getSecond()); + } + } + + private static class SecondParser extends FunctionalParserBase { + @NotNull private final FunctionalParser, T> myParser; + + public SecondParser(@NotNull FunctionalParser, T> parser) { + myParser = parser; + } + + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final Pair, State> result = myParser.parse(tokens, state); + return Pair.create(result.getFirst().getSecond(), result.getSecond()); + } + } + + private static class FinishedParser extends FunctionalParserBase { + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final int pos = state.getPos(); + if (pos >= tokens.size()) { + return Pair.create(null, state); + } + throw new ParserException(String.format("Expected end of input, found %s", tokens.get(pos)), state); + } + } + + private static class PureParser extends FunctionalParserBase { + @Nullable private final R myValue; + + public PureParser(@Nullable R value) { + myValue = value; + } + + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + return Pair.create(myValue, state); + } + } + + private static class ThenParser extends FunctionalParserBase, T> { + @NotNull private final FunctionalParser myFirst; + @NotNull private final FunctionalParser mySecond; + + public ThenParser(@NotNull FunctionalParser first, @NotNull FunctionalParser second) { + myFirst = first; + mySecond = second; + } + + @NotNull + @Override + public Pair, State> parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final Pair result1 = myFirst.parse(tokens, state); + final Pair result2 = mySecond.parse(tokens, result1.getSecond()); + return Pair.create(Pair.create(result1.getFirst(), result2.getFirst()), result2.getSecond()); + } + } + + private static class MapParser extends FunctionalParserBase { + @NotNull private final FunctionalParserBase myParser; + @NotNull private final Function myFunction; + + public MapParser(@NotNull FunctionalParserBase parser, @NotNull Function function) { + myParser = parser; + myFunction = function; + } + + @NotNull + @Override + public Pair parse(@NotNull List> tokens, @NotNull State state) throws ParserException { + final Pair result = myParser.parse(tokens, state); + return Pair.create(myFunction.fun(result.getFirst()), result.getSecond()); + } } } diff --git a/python/testData/inspections/PyArgumentListInspection/slice.py b/python/testData/inspections/PyArgumentListInspection/slice.py new file mode 100644 index 000000000000..486eb2ecd158 --- /dev/null +++ b/python/testData/inspections/PyArgumentListInspection/slice.py @@ -0,0 +1,5 @@ +print(slice()) +print(slice(1)) +print(slice(1, 2)) +print(slice(1, 2, 3)) +print(slice(1, 2, 3, 4)) diff --git a/python/testData/inspections/PyArgumentListInspection/xRange.py b/python/testData/inspections/PyArgumentListInspection/xRange.py new file mode 100644 index 000000000000..2eaede119bad --- /dev/null +++ b/python/testData/inspections/PyArgumentListInspection/xRange.py @@ -0,0 +1,5 @@ +print(xrange()) +print(xrange(1)) +print(xrange(1, 2)) +print(xrange(1, 2, 3)) +print(xrange(1, 2, 3, 4)) diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index 105893830283..bc1bdc8cb412 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -1,6 +1,5 @@ package com.jetbrains.python; -import com.intellij.openapi.util.Pair; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.types.*; @@ -235,13 +234,18 @@ public class PyTypeParserTest extends PyTestCase { assertInstanceOf(type, PyCallableType.class); final PyCallableType callableType = (PyCallableType)type; assertNotNull(callableType); - final PyType returnType = callableType.getCallType(getTypeEvalContext(), null); + final TypeEvalContext context = getTypeEvalContext(); + final PyType returnType = callableType.getCallType(context, null); assertInstanceOf(returnType, PyGenericType.class); - final List> parameterTypes = callableType.getParameters(getTypeEvalContext()); + final List parameterTypes = callableType.getParameters(context); assertNotNull(parameterTypes); assertEquals(2, parameterTypes.size()); - assertEquals("int", parameterTypes.get(0).getSecond().getName()); - assertEquals("T", parameterTypes.get(1).getSecond().getName()); + final PyType type0 = parameterTypes.get(0).getType(context); + assertNotNull(type0); + assertEquals("int", type0.getName()); + final PyType type1 = parameterTypes.get(1).getType(context); + assertNotNull(type1); + assertEquals("T", type1.getName()); } public void testCallableWithoutArgs() { @@ -253,7 +257,7 @@ public class PyTypeParserTest extends PyTestCase { final PyType returnType = callableType.getCallType(getTypeEvalContext(), null); assertNotNull(returnType); assertEquals("int", returnType.getName()); - final List> parameterTypes = callableType.getParameters(getTypeEvalContext()); + final List parameterTypes = callableType.getParameters(getTypeEvalContext()); assertNotNull(parameterTypes); assertEquals(0, parameterTypes.size()); } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java index 0454cd0d322f..e8b9a9797884 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyArgumentListInspectionTest.java @@ -103,6 +103,16 @@ public class PyArgumentListInspectionTest extends PyTestCase { doTest(); } + // PY-9978 + public void testXRange() { + doTest(); + } + + // PY-9978 + public void testSlice() { + doTest(); + } + public void testPy3k() { PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON30); try {