Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2013-08-07 13:07:20 +04:00
43 changed files with 577 additions and 303 deletions
@@ -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;
}
}
+2
View File
@@ -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));
@@ -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)) {
@@ -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) {
@@ -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);
}
@@ -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) {
@@ -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 {