From 08148e87d7b87464379dfa8e322706e530793bac Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 19 Aug 2015 16:57:50 +0300 Subject: [PATCH] Changed the API for arguments-paramters mapping to PyCallExpression.mapArguments() Moved CallArgumentsMappingImpl to PyCallExpressionHelper.mapArguments() and switched from returning a map of mapped parameters to a class that will contain more info about mappings. --- .../python/psi/PyCallExpression.java | 26 ++- .../PyArgumentEqualDefaultInspection.java | 5 +- .../inspections/PyCallByClassInspection.java | 7 +- .../PyPropertyDefinitionInspection.java | 5 +- .../quickfix/PyRemoveParameterQuickFix.java | 7 +- .../psi/impl/CallArgumentsMappingImpl.java | 185 +----------------- .../psi/impl/PyCallExpressionHelper.java | 171 ++++++++++++++++ .../python/psi/impl/PyCallExpressionImpl.java | 6 + .../python/psi/impl/PyDecoratorImpl.java | 6 + .../python/psi/impl/PyNamedParameterImpl.java | 8 +- .../python/psi/types/PyTypeChecker.java | 7 +- .../introduce/IntroduceHandler.java | 8 +- 12 files changed, 231 insertions(+), 210 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java index a2e0a1cb6a42..1a130c734f33 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java @@ -22,6 +22,8 @@ import com.jetbrains.python.psi.resolve.PyResolveContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** * Represents an entire call expression, like foo() or foo.bar[1]('x'). */ @@ -114,6 +116,9 @@ public interface PyCallExpression extends PyCallSiteExpression { @Nullable PyMarkedCallee resolveCallee(PyResolveContext resolveContext, int implicitOffset); + @NotNull + PyArgumentsMapping mapArguments(@NotNull PyResolveContext resolveContext); + /** * Checks if the unqualified name of the callee matches any of the specified names * @@ -122,7 +127,6 @@ public interface PyCallExpression extends PyCallSiteExpression { */ boolean isCalleeText(@NotNull String... nameCandidates); - /** * Checks if the qualified name of the callee matches any of the specified names provided by provider. * @see com.jetbrains.python.nameResolver @@ -131,6 +135,26 @@ public interface PyCallExpression extends PyCallSiteExpression { */ boolean isCallee(@NotNull FQNamesProvider... name); + class PyArgumentsMapping { + @Nullable private final PyMarkedCallee myCallee; + @NotNull private final Map myMappedParameters; + + public PyArgumentsMapping(@Nullable PyMarkedCallee markedCallee, @NotNull Map mappedParameters) { + myCallee = markedCallee; + myMappedParameters = mappedParameters; + } + + @Nullable + public PyMarkedCallee getMarkedCallee() { + return myCallee; + } + + @NotNull + public Map getMappedParameters() { + return myMappedParameters; + } + } + /** * Couples function with a flag describing the way it is called. */ diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java index 0250f439ccac..cd06a6d19e81 100644 --- a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java @@ -23,7 +23,6 @@ import com.intellij.psi.PsiReference; import com.jetbrains.python.PyBundle; import com.jetbrains.python.inspections.quickfix.RemoveArgumentEqualDefaultQuickFix; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.CallArgumentsMappingImpl; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.types.PyClassType; import org.jetbrains.annotations.Nls; @@ -98,9 +97,9 @@ public class PyArgumentEqualDefaultInspection extends PyInspection { } private void checkArguments(PyCallExpression callExpr, PyExpression[] arguments) { - final Map mapping = CallArgumentsMappingImpl.map(callExpr, getResolveContext()); + final PyCallExpression.PyArgumentsMapping mapping = callExpr.mapArguments(getResolveContext()); Set problemElements = new HashSet(); - for (Map.Entry e : mapping.entrySet()) { + for (Map.Entry e : mapping.getMappedParameters().entrySet()) { PyExpression defaultValue = e.getValue().getDefaultValue(); if (defaultValue != null) { PyExpression key = e.getKey(); diff --git a/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java b/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java index 6a73b89829ad..bbce4a658b25 100644 --- a/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCallByClassInspection.java @@ -22,7 +22,6 @@ import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.CallArgumentsMappingImpl; import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyType; import org.jetbrains.annotations.Nls; @@ -91,13 +90,13 @@ public class PyCallByClassInspection extends PyInspection { PyClass qual_class = qual_class_type.getPyClass(); final PyArgumentList arglist = call.getArgumentList(); if (arglist != null) { - final PyCallExpression.PyMarkedCallee markedCallee = call.resolveCallee(getResolveContext()); + final PyCallExpression.PyArgumentsMapping mapping = call.mapArguments(getResolveContext()); + final PyCallExpression.PyMarkedCallee markedCallee = mapping.getMarkedCallee(); if (markedCallee != null && markedCallee.getModifier() != STATICMETHOD) { final List params = PyUtil.getParameters(markedCallee.getCallable(), myTypeEvalContext); if (params.size() > 0 && params.get(0) instanceof PyNamedParameter) { PyNamedParameter first_param = (PyNamedParameter)params.get(0); - final Map mapping = CallArgumentsMappingImpl.map(call, getResolveContext()); - for (Map.Entry entry : mapping.entrySet()) { + for (Map.Entry entry : mapping.getMappedParameters().entrySet()) { // we ignore *arg and **arg which we cannot analyze if (entry.getValue() == first_param) { PyExpression first_arg = entry.getKey(); diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 406889e39058..80cade67f175 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -34,7 +34,6 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.inspections.quickfix.PyUpdatePropertySignatureQuickFix; import com.jetbrains.python.inspections.quickfix.RenameParameterQuickFix; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.CallArgumentsMappingImpl; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyNoneType; @@ -121,8 +120,8 @@ public class PyPropertyDefinitionInspection extends PyInspection { final PyArgumentList arglist = call.getArgumentList(); assert arglist != null : "Property call has null arglist"; // we assume fget, fset, fdel, doc names - final Map mapping = CallArgumentsMappingImpl.map(call, getResolveContext()); - for (Map.Entry entry : mapping.entrySet()) { + final PyCallExpression.PyArgumentsMapping mapping = call.mapArguments(getResolveContext()); + for (Map.Entry entry : mapping.getMappedParameters().entrySet()) { final String paramName = entry.getValue().getName(); PyExpression argument = PyUtil.peelArgument(entry.getKey()); checkPropertyCallArgument(paramName, argument, node.getContainingFile()); diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java index f25d013664bf..7e942a445ece 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java @@ -27,7 +27,6 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.documentation.PyDocumentationSettings; import com.jetbrains.python.editor.PythonDocCommentUtil; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.CallArgumentsMappingImpl; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.refactoring.PyRefactoringUtil; import org.jetbrains.annotations.NonNls; @@ -64,9 +63,9 @@ public class PyRemoveParameterQuickFix implements LocalQuickFix { if (callExpression instanceof PyCallExpression) { final PyArgumentList argumentList = ((PyCallExpression)callExpression).getArgumentList(); if (argumentList != null) { - final Map mapping = CallArgumentsMappingImpl.map((PyCallExpression)callExpression, - PyResolveContext.noImplicits()); - for (Map.Entry parameterEntry : mapping.entrySet()) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits(); + final PyCallExpression.PyArgumentsMapping mapping = ((PyCallExpression)callExpression).mapArguments(resolveContext); + for (Map.Entry parameterEntry : mapping.getMappedParameters().entrySet()) { if (parameterEntry.getValue().equals(element)) { parameterEntry.getKey().delete(); } diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index 6d501d44cc3c..32aa224bbbd2 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -18,7 +18,6 @@ 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.resolve.PyResolveContext; import com.jetbrains.python.psi.types.PyTupleType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -55,180 +54,6 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { myArgumentList = arglist; } - @NotNull - public static Map map(@NotNull PyCallExpression callExpression, - @NotNull PyResolveContext resolveContext) { - return map(callExpression, 0, resolveContext); - } - - @NotNull - public static Map map(@NotNull PyCallExpression callExpression, - int implicitArgumentOffset, - @NotNull PyResolveContext resolveContext) { - final Map results = new LinkedHashMap(); - final PyArgumentList argumentList = callExpression.getArgumentList(); - final PyCallExpression.PyMarkedCallee markedCallee = callExpression.resolveCallee(resolveContext, implicitArgumentOffset); - if (markedCallee != null && argumentList != null) { - final TypeEvalContext context = resolveContext.getTypeEvalContext(); - final List allParameters = PyUtil.getParameters(markedCallee.getCallable(), context); - final List parameters = dropImplicitParameters(allParameters, markedCallee.getImplicitOffset()); - final List arguments = Arrays.asList(argumentList.getArguments()); - - final List positionalArguments = filterPositionalArguments(arguments); - final List keywordArguments = filterKeywordArguments(arguments); - final List variadicPositionalArguments = filterVariadicPositionalArguments(arguments); - final List variadicKeywordArguments = filterVariadicKeywordArguments(arguments); - - boolean seenSingleStar = false; - final List unmappedParameters = new ArrayList(); - for (PyParameter parameter : parameters) { - if (parameter instanceof PyNamedParameter) { - final PyNamedParameter namedParameter = (PyNamedParameter)parameter; - final String parameterName = namedParameter.getName(); - if (namedParameter.isPositionalContainer()) { - if (variadicPositionalArguments.size() == 1) { - results.put(variadicPositionalArguments.remove(0), namedParameter); - } - else { - positionalArguments.clear(); - variadicPositionalArguments.clear(); - } - } - else if (namedParameter.isKeywordContainer()) { - if (variadicKeywordArguments.size() == 1) { - results.put(variadicKeywordArguments.remove(0), namedParameter); - } - else { - keywordArguments.clear(); - variadicKeywordArguments.clear(); - } - } - else if (seenSingleStar) { - final PyExpression keywordArgument = removeKeywordArgument(keywordArguments, parameterName); - if (keywordArgument != null) { - results.put(keywordArgument, namedParameter); - } - else if (variadicKeywordArguments.isEmpty()) { - unmappedParameters.add(namedParameter); - } - } - else { - if (!positionalArguments.isEmpty()) { - final PyExpression positionalArgument = next(positionalArguments); - if (positionalArgument != null) { - results.put(positionalArgument, namedParameter); - } - else { - unmappedParameters.add(namedParameter); - } - } - else { - final PyKeywordArgument keywordArgument = removeKeywordArgument(keywordArguments, parameterName); - if (keywordArgument != null) { - results.put(keywordArgument, namedParameter); - } - else if (variadicPositionalArguments.isEmpty() || variadicKeywordArguments.isEmpty()) { - unmappedParameters.add(namedParameter); - } - } - } - } - else if (parameter instanceof PyTupleParameter) { - unmappedParameters.add(parameter); - } - else if (parameter instanceof PySingleStarParameter) { - seenSingleStar = true; - } - else { - unmappedParameters.add(parameter); - } - } - } - return results; - } - - @Nullable - private static PyKeywordArgument removeKeywordArgument(@NotNull List arguments, @Nullable String name) { - PyKeywordArgument result = null; - for (PyKeywordArgument argument : arguments) { - final String keyword = argument.getKeyword(); - if (keyword != null && keyword.equals(name)) { - result = argument; - break; - } - } - if (result != null) { - arguments.remove(result); - } - return result; - } - - @NotNull - private static List filterPositionalArguments(@NotNull List arguments) { - final List results = new ArrayList(); - for (PyExpression argument : arguments) { - if (isPositionalArg(argument)) { - results.add(argument); - } - } - return results; - } - - @NotNull - private static List filterKeywordArguments(@NotNull List arguments) { - final List results = new ArrayList(); - for (PyExpression argument : arguments) { - if (argument instanceof PyKeywordArgument) { - results.add((PyKeywordArgument)argument); - } - } - return results; - } - - @NotNull - private static List filterVariadicPositionalArguments(@NotNull List arguments) { - final List results = new ArrayList(); - for (PyExpression argument : arguments) { - if (argument != null && isVariadicPositionalArgument(argument)) { - results.add(argument); - } - } - return results; - } - - @NotNull - private static List filterVariadicKeywordArguments(@NotNull List arguments) { - final List results = new ArrayList(); - for (PyExpression argument : arguments) { - if (argument != null && isVariadicKeywordArgument(argument)) { - results.add(argument); - } - } - return results; - } - - private static boolean isVariadicKeywordArgument(@NotNull PyExpression argument) { - return argument instanceof PyStarArgument && ((PyStarArgument)argument).isKeyword(); - } - - private static boolean isVariadicPositionalArgument(@NotNull PyExpression argument) { - return argument instanceof PyStarArgument && !((PyStarArgument)argument).isKeyword(); - } - - @Nullable - private static T next(@NotNull List list) { - return list.isEmpty() ? null : list.remove(0); - } - - @NotNull - private static List dropImplicitParameters(@NotNull List parameters, int offset) { - final ArrayList results = new ArrayList(parameters); - for (int i = 0; i < offset && !results.isEmpty(); i++) { - results.remove(0); - } - return results; - } - /** * Maps arguments of a call to parameters of a callee. * must contain already resolved callee with flags set appropriately. @@ -423,11 +248,11 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { // NOTE: ignores the structure of nested-tuple params! if (tuple_par != null) { i = 0; - while (i < arguments.length && mapped_args.contains(arguments[i]) && isPositionalArg(arguments[i])) { + while (i < arguments.length && mapped_args.contains(arguments[i]) && PyCallExpressionHelper.isPositionalArgument(arguments[i])) { i += 1; // skip first mapped args } - if (i < arguments.length && isPositionalArg(arguments[i])) { - while (i < arguments.length && !mapped_args.contains(arguments[i]) && isPositionalArg(arguments[i])) { + if (i < arguments.length && PyCallExpressionHelper.isPositionalArgument(arguments[i])) { + while (i < arguments.length && !mapped_args.contains(arguments[i]) && PyCallExpressionHelper.isPositionalArgument(arguments[i])) { myPlainMappedParams.put(arguments[i], tuple_par); mapped_args.add(arguments[i]); i += 1; @@ -550,10 +375,6 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { } } - private static boolean isPositionalArg(PyExpression arg) { - return !(arg instanceof PyKeywordArgument) && !(arg instanceof PyStarArgument); - } - /** * @return A mapping argument->parameter for non-starred arguments (but includes starred parameters). */ diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index f87e0bd99e7b..00c122c7d11d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -631,4 +631,175 @@ public class PyCallExpressionHelper { final PyExpression callee = expression.getCallee(); return (callee != null) && NameResolverTools.isName(callee, namesProviders); } + + @NotNull + public static PyCallExpression.PyArgumentsMapping mapArguments(@NotNull PyCallExpression callExpression, + @NotNull PyResolveContext resolveContext) { + final Map mappedParameters = new LinkedHashMap(); + final PyArgumentList argumentList = callExpression.getArgumentList(); + final PyCallExpression.PyMarkedCallee markedCallee = callExpression.resolveCallee(resolveContext); + if (markedCallee != null && argumentList != null) { + final TypeEvalContext context = resolveContext.getTypeEvalContext(); + final List allParameters = PyUtil.getParameters(markedCallee.getCallable(), context); + final List parameters = dropImplicitParameters(allParameters, markedCallee.getImplicitOffset()); + final List arguments = Arrays.asList(argumentList.getArguments()); + + final List positionalArguments = filterPositionalArguments(arguments); + final List keywordArguments = filterKeywordArguments(arguments); + final List variadicPositionalArguments = filterVariadicPositionalArguments(arguments); + final List variadicKeywordArguments = filterVariadicKeywordArguments(arguments); + + boolean seenSingleStar = false; + final List unmappedParameters = new ArrayList(); + for (PyParameter parameter : parameters) { + if (parameter instanceof PyNamedParameter) { + final PyNamedParameter namedParameter = (PyNamedParameter)parameter; + final String parameterName = namedParameter.getName(); + if (namedParameter.isPositionalContainer()) { + if (variadicPositionalArguments.size() == 1) { + mappedParameters.put(variadicPositionalArguments.remove(0), namedParameter); + } + else { + positionalArguments.clear(); + variadicPositionalArguments.clear(); + } + } + else if (namedParameter.isKeywordContainer()) { + if (variadicKeywordArguments.size() == 1) { + mappedParameters.put(variadicKeywordArguments.remove(0), namedParameter); + } + else { + keywordArguments.clear(); + variadicKeywordArguments.clear(); + } + } + else if (seenSingleStar) { + final PyExpression keywordArgument = removeKeywordArgument(keywordArguments, parameterName); + if (keywordArgument != null) { + mappedParameters.put(keywordArgument, namedParameter); + } + else if (variadicKeywordArguments.isEmpty()) { + unmappedParameters.add(namedParameter); + } + } + else { + if (!positionalArguments.isEmpty()) { + final PyExpression positionalArgument = next(positionalArguments); + if (positionalArgument != null) { + mappedParameters.put(positionalArgument, namedParameter); + } + else { + unmappedParameters.add(namedParameter); + } + } + else { + final PyKeywordArgument keywordArgument = removeKeywordArgument(keywordArguments, parameterName); + if (keywordArgument != null) { + mappedParameters.put(keywordArgument, namedParameter); + } + else if (variadicPositionalArguments.isEmpty() || variadicKeywordArguments.isEmpty()) { + unmappedParameters.add(namedParameter); + } + } + } + } + else if (parameter instanceof PyTupleParameter) { + unmappedParameters.add(parameter); + } + else if (parameter instanceof PySingleStarParameter) { + seenSingleStar = true; + } + else { + unmappedParameters.add(parameter); + } + } + } + return new PyCallExpression.PyArgumentsMapping(markedCallee, mappedParameters); + } + + @Nullable + private static PyKeywordArgument removeKeywordArgument(@NotNull List arguments, @Nullable String name) { + PyKeywordArgument result = null; + for (PyKeywordArgument argument : arguments) { + final String keyword = argument.getKeyword(); + if (keyword != null && keyword.equals(name)) { + result = argument; + break; + } + } + if (result != null) { + arguments.remove(result); + } + return result; + } + + @NotNull + private static List filterPositionalArguments(@NotNull List arguments) { + final List results = new ArrayList(); + for (PyExpression argument : arguments) { + if (isPositionalArgument(argument)) { + results.add(argument); + } + } + return results; + } + + @NotNull + private static List filterKeywordArguments(@NotNull List arguments) { + final List results = new ArrayList(); + for (PyExpression argument : arguments) { + if (argument instanceof PyKeywordArgument) { + results.add((PyKeywordArgument)argument); + } + } + return results; + } + + @NotNull + private static List filterVariadicPositionalArguments(@NotNull List arguments) { + final List results = new ArrayList(); + for (PyExpression argument : arguments) { + if (argument != null && isVariadicPositionalArgument(argument)) { + results.add(argument); + } + } + return results; + } + + @NotNull + private static List filterVariadicKeywordArguments(@NotNull List arguments) { + final List results = new ArrayList(); + for (PyExpression argument : arguments) { + if (argument != null && isVariadicKeywordArgument(argument)) { + results.add(argument); + } + } + return results; + } + + private static boolean isVariadicKeywordArgument(@NotNull PyExpression argument) { + return argument instanceof PyStarArgument && ((PyStarArgument)argument).isKeyword(); + } + + private static boolean isVariadicPositionalArgument(@NotNull PyExpression argument) { + return argument instanceof PyStarArgument && !((PyStarArgument)argument).isKeyword(); + } + + @Nullable + private static T next(@NotNull List list) { + return list.isEmpty() ? null : list.remove(0); + } + + @NotNull + private static List dropImplicitParameters(@NotNull List parameters, int offset) { + final ArrayList results = new ArrayList(parameters); + for (int i = 0; i < offset && !results.isEmpty(); i++) { + results.remove(0); + } + return results; + } + + static boolean isPositionalArgument(@Nullable PyExpression argument) { + return !(argument instanceof PyKeywordArgument) && !(argument instanceof PyStarArgument); + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java index 722b769da580..f2011b372ddb 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java @@ -102,6 +102,12 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress return PyCallExpressionHelper.resolveCallee(this, resolveContext, offset); } + @NotNull + @Override + public PyArgumentsMapping mapArguments(@NotNull PyResolveContext resolveContext) { + return PyCallExpressionHelper.mapArguments(this, resolveContext); + } + @Override public boolean isCalleeText(@NotNull String... nameCandidates) { return PyCallExpressionHelper.isCalleeText(this, nameCandidates); diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java index 6aba3ea3658b..73cf915e0202 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java @@ -157,6 +157,12 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase im return callee; } + @NotNull + @Override + public PyArgumentsMapping mapArguments(@NotNull PyResolveContext resolveContext) { + return PyCallExpressionHelper.mapArguments(this, resolveContext); + } + @Override public PyCallable resolveCalleeFunction(PyResolveContext resolveContext) { return PyCallExpressionHelper.resolveCalleeFunction(this, resolveContext); diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index d38c5060fab4..2c541faafecc 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -269,8 +269,8 @@ public class PyNamedParameterImpl extends PyBaseElementImpl mapping = CallArgumentsMappingImpl.map(call, resolveContext); - for (Map.Entry entry : mapping.entrySet()) { + final PyCallExpression.PyArgumentsMapping mapping = call.mapArguments(resolveContext); + for (Map.Entry entry : mapping.getMappedParameters().entrySet()) { if (entry.getValue() == PyNamedParameterImpl.this) { final PyExpression argument = entry.getKey(); if (argument != null) { @@ -393,8 +393,8 @@ public class PyNamedParameterImpl extends PyBaseElementImpl mapping = CallArgumentsMappingImpl.map(callExpression, resolveContext); - for (Map.Entry entry : mapping.entrySet()) { + final PyCallExpression.PyArgumentsMapping mapping = callExpression.mapArguments(resolveContext); + for (Map.Entry entry : mapping.getMappedParameters().entrySet()) { if (entry.getKey() == element) { return entry.getValue(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 0adb036bb99c..d4edb85a0180 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -24,7 +24,6 @@ import com.intellij.util.ArrayUtil; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.CallArgumentsMappingImpl; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; @@ -458,8 +457,8 @@ public class PyTypeChecker { final PyArgumentList args = call.getArgumentList(); if (args != null) { final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); - final Map arguments = CallArgumentsMappingImpl.map(call, resolveContext); - final PyCallExpression.PyMarkedCallee markedCallee = call.resolveCallee(resolveContext); + final PyCallExpression.PyArgumentsMapping mapping = call.mapArguments(resolveContext); + final PyCallExpression.PyMarkedCallee markedCallee = mapping.getMarkedCallee(); if (markedCallee != null) { final PyCallable callable = markedCallee.getCallable(); if (callable instanceof PyFunction) { @@ -474,7 +473,7 @@ public class PyTypeChecker { else { receiver = null; } - return new AnalyzeCallResults(callable, receiver, arguments); + return new AnalyzeCallResults(callable, receiver, mapping.getMappedParameters()); } } } diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java index 2bbdc109f59d..c370343e0ee4 100644 --- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java +++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java @@ -47,7 +47,6 @@ import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonStringUtil; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.CallArgumentsMappingImpl; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.types.PyNoneType; import com.jetbrains.python.psi.types.PyType; @@ -229,10 +228,9 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { final PyCallExpression callExpr = argList.getCallExpression(); if (callExpr != null) { final PyResolveContext resolveContext = PyResolveContext.noImplicits(); - final PyCallExpression.PyMarkedCallee markedCallee = callExpr.resolveCallee(resolveContext); - if (markedCallee != null) { - final Map mapping = CallArgumentsMappingImpl.map(callExpr, resolveContext); - final PyNamedParameter namedParameter = mapping.get(expression); + final PyCallExpression.PyArgumentsMapping mapping = callExpr.mapArguments(resolveContext); + if (mapping.getMarkedCallee() != null) { + final PyNamedParameter namedParameter = mapping.getMappedParameters().get(expression); if (namedParameter != null) { candidates.add(namedParameter.getName()); }