mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+7
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
<orderEntry type="module" module-name="IntelliLang-python" />
|
||||
<orderEntry type="module" module-name="IntelliLang-xml" />
|
||||
<orderEntry type="module" module-name="ini4idea" />
|
||||
<orderEntry type="module" module-name="textmate" />
|
||||
<orderEntry type="module" module-name="coffeescript" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -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<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context);
|
||||
List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import java.util.Collection;
|
||||
public interface PyClassMembersProvider {
|
||||
ExtensionPointName<PyClassMembersProvider> EP_NAME = ExtensionPointName.create("Pythonid.pyClassMembersProvider");
|
||||
|
||||
Collection<PyDynamicMember> getMembers(PyClassType clazz);
|
||||
Collection<PyDynamicMember> getMembers(PyClassType clazz, @Nullable PsiElement location);
|
||||
|
||||
@Nullable
|
||||
PsiElement resolveMember(PyClassType clazz, String name);
|
||||
PsiElement resolveMember(PyClassType clazz, String name, @Nullable PsiElement location);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ import java.util.Collections;
|
||||
*/
|
||||
public class PyClassMembersProviderBase implements PyClassMembersProvider {
|
||||
@Override
|
||||
public Collection<PyDynamicMember> getMembers(PyClassType clazz) {
|
||||
public Collection<PyDynamicMember> getMembers(PyClassType clazz, PsiElement location) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement resolveMember(PyClassType clazz, String name) {
|
||||
final Collection<PyDynamicMember> members = getMembers(clazz);
|
||||
public PsiElement resolveMember(PyClassType clazz, String name, PsiElement location) {
|
||||
final Collection<PyDynamicMember> members = getMembers(clazz, location);
|
||||
return resolveMemberByName(members, clazz, name);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String> methods) {
|
||||
registerReturnType(classQualifiedName, methods, mySelfTypeCallback);
|
||||
}
|
||||
|
||||
@@ -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<PyArgumentLi
|
||||
final PyArgumentList argList = prevResult.getArgumentList();
|
||||
if (!argList.isValid()) return;
|
||||
// really we need to redo analysis every UI update; findElementForParameterInfo isn't called while typing
|
||||
final CallArgumentsMapping argumentsMapping = argList.analyzeCall(PyResolveContext.noImplicits());
|
||||
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(argList.getContainingFile());
|
||||
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(typeEvalContext);
|
||||
final CallArgumentsMapping argumentsMapping = argList.analyzeCall(resolveContext);
|
||||
final PyMarkedCallee marked = argumentsMapping.getMarkedCallee();
|
||||
if (marked == null) return; // resolution failed
|
||||
final Callable callable = marked.getCallable();
|
||||
|
||||
final List<PyParameter> parameterList = Arrays.asList(callable.getParameterList().getParameters());
|
||||
final List<PyParameter> parameterList = PyUtil.getParameters(callable, typeEvalContext);
|
||||
final List<PyNamedParameter> namedParameters = new ArrayList<PyNamedParameter>(parameterList.size());
|
||||
|
||||
// param -> hint index. indexes are not contiguous, because some hints are parentheses.
|
||||
@@ -123,7 +126,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
|
||||
// formatting of hints: hint index -> flags. this includes flags for parens.
|
||||
final Map<Integer, EnumSet<ParameterInfoUIContextEx.Flag>> hintFlags = new HashMap<Integer, EnumSet<ParameterInfoUIContextEx.Flag>>();
|
||||
|
||||
final List<String> hintsList = buildParameterListHint(callable, namedParameters, parameterToIndex, hintFlags);
|
||||
final List<String> 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<PyArgumentLi
|
||||
/**
|
||||
* builds the textual picture and the list of named parameters
|
||||
*
|
||||
* @param callable is a parameter list owner
|
||||
* @param parameters parameters of a callable
|
||||
* @param namedParameters used to collect all named parameters of callable
|
||||
* @param parameterToIndex used to collect info about parameter indexes
|
||||
* @param hintFlags mark parameter as deprecated/highlighted/strikeout
|
||||
*/
|
||||
private static List<String> buildParameterListHint(@NotNull final Callable callable,
|
||||
private static List<String> buildParameterListHint(@NotNull List<PyParameter> parameters,
|
||||
@NotNull final List<PyNamedParameter> namedParameters,
|
||||
@NotNull final Map<PyNamedParameter, Integer> parameterToIndex,
|
||||
@NotNull final Map<Integer, EnumSet<ParameterInfoUIContextEx.Flag>> hintFlags) {
|
||||
|
||||
final List<String> hintsList = new ArrayList<String>();
|
||||
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));
|
||||
|
||||
+2
-1
@@ -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<List<PyDynamicMember>> mySocketMembersKey = Key.create("socket.members");
|
||||
|
||||
@Override
|
||||
public Collection<PyDynamicMember> getMembers(PyClassType classType) {
|
||||
public Collection<PyDynamicMember> getMembers(PyClassType classType, PsiElement location) {
|
||||
PyClass clazz = classType.getPyClass();
|
||||
final String qualifiedName = clazz.getQualifiedName();
|
||||
if ("socket._socketobject".equals(qualifiedName)) {
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public class PyUserSkeletonsLineMarkerProvider implements LineMarkerProvider {
|
||||
final PyElement skeleton = getUserSkeleton(element);
|
||||
if (skeleton != null) {
|
||||
result.add(new LineMarkerInfo<PsiElement>(
|
||||
element, element.getTextRange(), ICON, Pass.VISIBLE_LINE_MARKERS,
|
||||
element, element.getTextRange(), ICON, Pass.UPDATE_OVERRIDEN_MARKERS,
|
||||
new Function<PsiElement, String>() {
|
||||
@Override
|
||||
public String fun(PsiElement e) {
|
||||
|
||||
+10
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TypeModel> parameterModels = null;
|
||||
final List<Pair<String, PyType>> parameters = type.getParameters(myContext);
|
||||
final List<PyCallableParameter> parameters = type.getParameters(myContext);
|
||||
if (parameters != null) {
|
||||
parameterModels = new ArrayList<TypeModel>();
|
||||
for (Pair<String, PyType> 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<PyParameter, TypeModel>() {
|
||||
@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);
|
||||
|
||||
|
||||
@@ -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<String> cat = new ChainIterable<String>();
|
||||
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<PyParameter> parameters = PyUtil.getParameters(fun, context);
|
||||
final String paramStr = "(" +
|
||||
StringUtil.join(parameters,
|
||||
new Function<PyParameter, String>() {
|
||||
@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<String> 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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<PyParameter> 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<PyExpression, EnumSet<CallArgumentsMapping.ArgFlag>> argEntry : result.getArgumentFlags().entrySet()) {
|
||||
EnumSet<CallArgumentsMapping.ArgFlag> 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<PyParameter> 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<PyNamedParameter> unmappedParams = result.getUnmappedParams();
|
||||
if (!((PyNamedParameter)param).isPositionalContainer() && !((PyNamedParameter)param).isKeywordContainer() &&
|
||||
|
||||
@@ -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<PyParameter> 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<PyExpression, PyNamedParameter> entry : analysis.getPlainMappedParams().entrySet()) {
|
||||
// we ignore *arg and **arg which we cannot analyze
|
||||
if (entry.getValue() == first_param) {
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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<PyDynamicMember> resolveResult = provider.getMembers(qtype);
|
||||
final Collection<PyDynamicMember> resolveResult = provider.getMembers(qtype, reference.getElement());
|
||||
for (PyDynamicMember member : resolveResult) {
|
||||
if (member.getName().equals(refText)) return true;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1238,5 +1238,32 @@ public class PyUtil {
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PyParameter> 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<PyCallableParameter> callableTypeParameters = callableType.getParameters(context);
|
||||
if (callableTypeParameters != null) {
|
||||
boolean allParametersDefined = true;
|
||||
final List<PyParameter> parameters = new ArrayList<PyParameter>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PyExpression> unmatched_args = new LinkedList<PyExpression>();
|
||||
@@ -75,8 +73,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<PyParameter> parameters = PyUtil.getParameters(myMarkedCallee.getCallable(), context);
|
||||
// prepare parameter slots
|
||||
final PyParameter[] parameters = myMarkedCallee.getCallable().getParameterList().getParameters();
|
||||
Map<PyNamedParameter, PyExpression> slots = new LinkedHashMap<PyNamedParameter, PyExpression>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PyClassStub> implement
|
||||
|
||||
private volatile Map<String, Property> myPropertyCache;
|
||||
|
||||
private class CachedAncestorsProvider implements CachedValueProvider<List<PyClassLikeType>> {
|
||||
@Nullable private TypeEvalContext myCachedContext;
|
||||
|
||||
private class CachedAncestorsProvider implements ParameterizedCachedValueProvider<List<PyClassLikeType>, TypeEvalContext> {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<List<PyClassLikeType>> compute() {
|
||||
final TypeEvalContext context = myCachedContext != null ? myCachedContext : TypeEvalContext.codeInsightFallback();
|
||||
public CachedValueProvider.Result<List<PyClassLikeType>> compute(@NotNull TypeEvalContext context) {
|
||||
final List<PyClassLikeType> 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<ParameterizedCachedValue<List<PyClassLikeType>, TypeEvalContext>> myCachedValueKey = Key.create("cached ancestors");
|
||||
private final CachedAncestorsProvider myCachedAncestorsProvider = new CachedAncestorsProvider();
|
||||
|
||||
@Override
|
||||
@@ -1098,14 +1096,9 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PyClassLikeType> 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
|
||||
|
||||
@@ -342,6 +342,12 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -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<PyParameter> 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<String> arguments = provider.getKeywordArguments(def, callExpr);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Pair<String, PyType>> myParameters;
|
||||
@Nullable private final List<PyCallableParameter> myParameters;
|
||||
@Nullable private final PyType myReturnType;
|
||||
|
||||
public PyCallableTypeImpl(@Nullable List<Pair<String, PyType>> parameters, @Nullable PyType returnType) {
|
||||
public PyCallableTypeImpl(@Nullable List<PyCallableParameter> parameters, @Nullable PyType returnType) {
|
||||
myParameters = parameters;
|
||||
myReturnType = returnType;
|
||||
}
|
||||
@@ -40,7 +39,7 @@ public class PyCallableTypeImpl implements PyCallableType {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
public List<PyCallableParameter> 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<Pair<String, PyType>, String>() {
|
||||
new Function<PyCallableParameter, String>() {
|
||||
@Override
|
||||
public String fun(Pair<String, PyType> 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) {
|
||||
|
||||
@@ -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<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
public List<PyCallableParameter> 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());
|
||||
|
||||
@@ -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<Pair<String, PyType>> getParameters(@NotNull TypeEvalContext context) {
|
||||
final List<Pair<String, PyType>> result = new ArrayList<Pair<String, PyType>>();
|
||||
public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) {
|
||||
final List<PyCallableParameter> result = new ArrayList<PyCallableParameter>();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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<Pair<String, PyType>> expectedParameters = expectedCallable.getParameters(context);
|
||||
final List<Pair<String, PyType>> actualParameters = actualCallable.getParameters(context);
|
||||
final List<PyCallableParameter> expectedParameters = expectedCallable.getParameters(context);
|
||||
final List<PyCallableParameter> 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<String, PyType> expectedParam = expectedParameters.get(i);
|
||||
final Pair<String, PyType> 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<Pair<String, PyType>> parameters = callable.getParameters(context);
|
||||
final List<PyCallableParameter> parameters = callable.getParameters(context);
|
||||
if (parameters != null) {
|
||||
for (Pair<String, PyType> 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<Pair<String, PyType>> substParams = null;
|
||||
final List<Pair<String, PyType>> parameters = callable.getParameters(context);
|
||||
List<PyCallableParameter> substParams = null;
|
||||
final List<PyCallableParameter> parameters = callable.getParameters(context);
|
||||
if (parameters != null) {
|
||||
substParams = new ArrayList<Pair<String, PyType>>();
|
||||
for (Pair<String, PyType> parameter : parameters) {
|
||||
substParams.add(Pair.create(parameter.getFirst(), substitute(parameter.getSecond(), substitutions, context)));
|
||||
substParams = new ArrayList<PyCallableParameter>();
|
||||
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);
|
||||
|
||||
@@ -230,7 +230,7 @@ public class PyTypeParser {
|
||||
new Function<Pair<Pair<ParseResult, List<ParseResult>>, ParseResult>, ParseResult>() {
|
||||
@Override
|
||||
public ParseResult fun(Pair<Pair<ParseResult, List<ParseResult>>, ParseResult> value) {
|
||||
final List<Pair<String, PyType>> parameters = new ArrayList<Pair<String, PyType>>();
|
||||
final List<PyCallableParameter> parameters = new ArrayList<PyCallableParameter>();
|
||||
final ParseResult returnResult = value.getSecond();
|
||||
ParseResult result;
|
||||
final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst();
|
||||
@@ -238,10 +238,10 @@ public class PyTypeParser {
|
||||
final ParseResult first = firstPair.getFirst();
|
||||
final List<ParseResult> second = firstPair.getSecond();
|
||||
result = first;
|
||||
parameters.add(Pair.<String, PyType>create(null, first.getType()));
|
||||
parameters.add(new PyCallableParameterImpl((String)null, first.getType()));
|
||||
for (ParseResult r : second) {
|
||||
result = result.merge(r);
|
||||
parameters.add(Pair.<String, PyType>create(null, r.getType()));
|
||||
parameters.add(new PyCallableParameterImpl((String)null, r.getType()));
|
||||
}
|
||||
result = result.merge(returnResult);
|
||||
}
|
||||
|
||||
@@ -29,17 +29,17 @@ public class PyUnionType implements PyType {
|
||||
@NotNull AccessDirection direction,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
SmartList<RatedResolveResult> ret = new SmartList<RatedResolveResult>();
|
||||
boolean all_nulls = true;
|
||||
boolean allNulls = true;
|
||||
for (PyType member : myMembers) {
|
||||
if (member != null) {
|
||||
List<? extends RatedResolveResult> result = member.resolveMember(name, null, direction, resolveContext);
|
||||
List<? extends RatedResolveResult> 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) {
|
||||
|
||||
+204
-125
@@ -35,46 +35,12 @@ public abstract class FunctionalParserBase<R, T> implements FunctionalParser<R,
|
||||
|
||||
@NotNull
|
||||
public static <T> FunctionalParser<Token<T>, T> token(@NotNull final T type, @Nullable final String text) {
|
||||
return new FunctionalParserBase<Token<T>, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<Token<T>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final int pos = state.getPos();
|
||||
if (pos >= tokens.size()) {
|
||||
throw new ParserException("No tokens left", state);
|
||||
}
|
||||
final Token<T> 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<T>(type, text);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <R, T> FunctionalParser<List<R>, T> many(@NotNull final FunctionalParser<R, T> parser) {
|
||||
return new FunctionalParserBase<List<R>, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<List<R>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final List<R> list = new ArrayList<R>();
|
||||
try {
|
||||
//noinspection InfiniteLoopStatement
|
||||
while (true) {
|
||||
final Pair<R, State> 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<R, T>(parser);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -98,45 +64,13 @@ public abstract class FunctionalParserBase<R, T> implements FunctionalParser<R,
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionalParser<R, T> cached() {
|
||||
final FunctionalParser<R, T> thisParser = this;
|
||||
return new FunctionalParserBase<R, T>() {
|
||||
private Object myKey = null;
|
||||
private Map<Integer, SoftReference<Pair<R, State>>> myCache = new HashMap<Integer, SoftReference<Pair<R, State>>>();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
if (myKey != state.getKey()) {
|
||||
myKey = state.getKey();
|
||||
myCache.clear();
|
||||
}
|
||||
final SoftReference<Pair<R, State>> ref = myCache.get(state.getPos());
|
||||
if (ref != null) {
|
||||
final Pair<R, State> cached = ref.get();
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
final Pair<R, State> result = thisParser.parse(tokens, state);
|
||||
myCache.put(state.getPos(), new SoftReference<Pair<R, State>>(result));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return new CachedParser<R, T>(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <R2> FunctionalParser<Pair<R, R2>, T> then(@NotNull final FunctionalParser<R2, T> parser) {
|
||||
final FunctionalParser<R, T> thisParser = this;
|
||||
return new FunctionalParserBase<Pair<R, R2>, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<Pair<R, R2>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<R, State> result1 = thisParser.parse(tokens, state);
|
||||
final Pair<R2, State> result2 = parser.parse(tokens, result1.getSecond());
|
||||
return Pair.create(Pair.create(result1.getFirst(), result2.getFirst()), result2.getSecond());
|
||||
}
|
||||
};
|
||||
return new ThenParser<R, R2, T>(this, parser);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -154,82 +88,227 @@ public abstract class FunctionalParserBase<R, T> implements FunctionalParser<R,
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionalParser<R, T> or(@NotNull final FunctionalParser<R, T> parser) {
|
||||
final FunctionalParserBase<R, T> thisParser = this;
|
||||
return new FunctionalParserBase<R, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> 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<R, T>(this, parser);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <R2> FunctionalParser<R2, T> map(@NotNull final Function<R, R2> f) {
|
||||
final FunctionalParserBase<R, T> thisParser = this;
|
||||
return new FunctionalParserBase<R2, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R2, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<R, State> result = thisParser.parse(tokens, state);
|
||||
return Pair.create(f.fun(result.getFirst()), result.getSecond());
|
||||
}
|
||||
};
|
||||
return new MapParser<R2, T, R>(this, f);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <R, R2, T> FunctionalParser<R, T> first(@NotNull final FunctionalParser<Pair<R, R2>, T> parser) {
|
||||
return new FunctionalParserBase<R, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<Pair<R, R2>, State> result = parser.parse(tokens, state);
|
||||
return Pair.create(result.getFirst().getFirst(), result.getSecond());
|
||||
}
|
||||
};
|
||||
return new FirstParser<R, T, R2>(parser);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <R, R2, T> FunctionalParser<R2, T> second(@NotNull final FunctionalParser<Pair<R, R2>, T> parser) {
|
||||
return new FunctionalParserBase<R2, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R2, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<Pair<R, R2>, State> result = parser.parse(tokens, state);
|
||||
return Pair.create(result.getFirst().getSecond(), result.getSecond());
|
||||
}
|
||||
};
|
||||
return new SecondParser<R2, T, R>(parser);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <T> FunctionalParser<Object, T> finished() {
|
||||
return new FunctionalParserBase<Object, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<Object, State> parse(@NotNull List<Token<T>> 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<T>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <R, T> FunctionalParser<R, T> pure(@Nullable final R value) {
|
||||
return new FunctionalParserBase<R, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
return Pair.create(value, state);
|
||||
return new PureParser<R, T>(value);
|
||||
}
|
||||
|
||||
private static class TokenParser<T> extends FunctionalParserBase<Token<T>, 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<Token<T>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final int pos = state.getPos();
|
||||
if (pos >= tokens.size()) {
|
||||
throw new ParserException("No tokens left", state);
|
||||
}
|
||||
};
|
||||
final Token<T> 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<R, T> extends FunctionalParserBase<List<R>, T> {
|
||||
@NotNull private final FunctionalParser<R, T> myParser;
|
||||
|
||||
public ManyParser(@NotNull FunctionalParser<R, T> parser) {
|
||||
myParser = parser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<List<R>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final List<R> list = new ArrayList<R>();
|
||||
try {
|
||||
//noinspection InfiniteLoopStatement
|
||||
while (true) {
|
||||
final Pair<R, State> 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<R, T> extends FunctionalParserBase<R, T> {
|
||||
@NotNull private final FunctionalParser<R, T> myParser;
|
||||
@Nullable private Object myKey;
|
||||
@NotNull private Map<Integer, SoftReference<Pair<R, State>>> myCache;
|
||||
|
||||
public CachedParser(@NotNull FunctionalParser<R, T> parser) {
|
||||
myParser = parser;
|
||||
myKey = null;
|
||||
myCache = new HashMap<Integer, SoftReference<Pair<R, State>>>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
if (myKey != state.getKey()) {
|
||||
myKey = state.getKey();
|
||||
myCache.clear();
|
||||
}
|
||||
final SoftReference<Pair<R, State>> ref = myCache.get(state.getPos());
|
||||
if (ref != null) {
|
||||
final Pair<R, State> cached = ref.get();
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
final Pair<R, State> result = myParser.parse(tokens, state);
|
||||
myCache.put(state.getPos(), new SoftReference<Pair<R, State>>(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class OrParser<R, T> extends FunctionalParserBase<R, T> {
|
||||
@NotNull private final FunctionalParserBase<R, T> myFirst;
|
||||
@NotNull private final FunctionalParser<R, T> mySecond;
|
||||
|
||||
public OrParser(@NotNull FunctionalParserBase<R, T> first, @NotNull FunctionalParser<R, T> second) {
|
||||
myFirst = first;
|
||||
mySecond = second;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> 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<R, T, R2> extends FunctionalParserBase<R, T> {
|
||||
@NotNull private final FunctionalParser<Pair<R, R2>, T> myParser;
|
||||
|
||||
public FirstParser(@NotNull FunctionalParser<Pair<R, R2>, T> parser) {
|
||||
myParser = parser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<Pair<R, R2>, State> result = myParser.parse(tokens, state);
|
||||
return Pair.create(result.getFirst().getFirst(), result.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
private static class SecondParser<R2, T, R> extends FunctionalParserBase<R2, T> {
|
||||
@NotNull private final FunctionalParser<Pair<R, R2>, T> myParser;
|
||||
|
||||
public SecondParser(@NotNull FunctionalParser<Pair<R, R2>, T> parser) {
|
||||
myParser = parser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R2, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<Pair<R, R2>, State> result = myParser.parse(tokens, state);
|
||||
return Pair.create(result.getFirst().getSecond(), result.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
private static class FinishedParser<T> extends FunctionalParserBase<Object, T> {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<Object, State> parse(@NotNull List<Token<T>> 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<R, T> extends FunctionalParserBase<R, T> {
|
||||
@Nullable private final R myValue;
|
||||
|
||||
public PureParser(@Nullable R value) {
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
return Pair.create(myValue, state);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThenParser<R, R2, T> extends FunctionalParserBase<Pair<R, R2>, T> {
|
||||
@NotNull private final FunctionalParser<R, T> myFirst;
|
||||
@NotNull private final FunctionalParser<R2, T> mySecond;
|
||||
|
||||
public ThenParser(@NotNull FunctionalParser<R, T> first, @NotNull FunctionalParser<R2, T> second) {
|
||||
myFirst = first;
|
||||
mySecond = second;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<Pair<R, R2>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<R, State> result1 = myFirst.parse(tokens, state);
|
||||
final Pair<R2, State> result2 = mySecond.parse(tokens, result1.getSecond());
|
||||
return Pair.create(Pair.create(result1.getFirst(), result2.getFirst()), result2.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
private static class MapParser<R2, T, R> extends FunctionalParserBase<R2, T> {
|
||||
@NotNull private final FunctionalParserBase<R, T> myParser;
|
||||
@NotNull private final Function<R, R2> myFunction;
|
||||
|
||||
public MapParser(@NotNull FunctionalParserBase<R, T> parser, @NotNull Function<R, R2> function) {
|
||||
myParser = parser;
|
||||
myFunction = function;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<R2, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state) throws ParserException {
|
||||
final Pair<R, State> result = myParser.parse(tokens, state);
|
||||
return Pair.create(myFunction.fun(result.getFirst()), result.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
print(slice(<warning descr="Parameter 'start' unfilled">)</warning>)
|
||||
print(slice(1))
|
||||
print(slice(1, 2))
|
||||
print(slice(1, 2, 3))
|
||||
print(slice(1, 2, 3, <warning descr="Unexpected argument">4</warning>))
|
||||
@@ -0,0 +1,5 @@
|
||||
print(xrange(<warning descr="Parameter 'start' unfilled">)</warning>)
|
||||
print(xrange(1))
|
||||
print(xrange(1, 2))
|
||||
print(xrange(1, 2, 3))
|
||||
print(xrange(1, 2, 3, <warning descr="Unexpected argument">4</warning>))
|
||||
@@ -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<Pair<String, PyType>> parameterTypes = callableType.getParameters(getTypeEvalContext());
|
||||
final List<PyCallableParameter> 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<Pair<String, PyType>> parameterTypes = callableType.getParameters(getTypeEvalContext());
|
||||
final List<PyCallableParameter> parameterTypes = callableType.getParameters(getTypeEvalContext());
|
||||
assertNotNull(parameterTypes);
|
||||
assertEquals(0, parameterTypes.size());
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user