mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Closes PY-32, PY-64 (a nice number coincidence).
This commit is contained in:
@@ -3,13 +3,19 @@ package com.jetbrains.python;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.lang.parameterInfo.*;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import static com.jetbrains.python.psi.PyCallExpression.*;
|
||||
import static com.jetbrains.python.psi.PyCallExpression.Flag;
|
||||
import static com.jetbrains.python.psi.PyCallExpression.PyMarkedFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentList, PyCallExpression.PyMarkedFunction> {
|
||||
public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentList, PyArgumentList.AnalysisResult> {
|
||||
|
||||
public boolean couldShowInLookup() {
|
||||
return true;
|
||||
@@ -18,31 +24,17 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
|
||||
return new Object[0]; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
public Object[] getParametersForDocumentation(final PyCallExpression.PyMarkedFunction p, final ParameterInfoContext context) {
|
||||
public Object[] getParametersForDocumentation(final PyArgumentList.AnalysisResult p, final ParameterInfoContext context) {
|
||||
return new Object[0]; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
public PyArgumentList findElementForParameterInfo(final CreateParameterInfoContext context) {
|
||||
PyArgumentList result = findArgumentList(context);
|
||||
if (result != null) {
|
||||
PyCallExpression callExpression = result.getCallExpression(); /*PsiTreeUtil.getParentOfType(result, PyCallExpression.class);*/
|
||||
if (callExpression == null) return null;
|
||||
/*
|
||||
boolean is_inst = callExpression.isByInstance();
|
||||
PyElement callee = callExpression.resolveCallee();
|
||||
if (callee instanceof PyClass) { // constructor call
|
||||
final PyClass cls = (PyClass)callee;
|
||||
callee = cls.findMethodByName("__init__");
|
||||
is_inst |= true;
|
||||
}
|
||||
if (!(callee instanceof PyFunction)) return null;
|
||||
PyFunction function = (PyFunction) callee;
|
||||
|
||||
context.setItemsToShow(new Object[] { new PyCallExpression.PyMarkedFunction(function, is_inst) });
|
||||
*/
|
||||
context.setItemsToShow(new Object[] { callExpression.resolveCallee() });
|
||||
PyArgumentList arglist = findArgumentList(context);
|
||||
if (arglist != null) {
|
||||
PyArgumentList.AnalysisResult result = arglist.analyzeCall();
|
||||
context.setItemsToShow(new Object[] { result });
|
||||
}
|
||||
return result;
|
||||
return arglist;
|
||||
}
|
||||
|
||||
private static PyArgumentList findArgumentList(final ParameterInfoContext context) {
|
||||
@@ -74,43 +66,78 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
|
||||
return true;
|
||||
}
|
||||
|
||||
public void updateUI(final PyMarkedFunction p, final ParameterInfoUIContext context) {
|
||||
if (p == null) return;
|
||||
final PyFunction py_function = p.getFunction();
|
||||
public void updateUI(final PyArgumentList.AnalysisResult result, final ParameterInfoUIContext context) {
|
||||
if (result == null) return;
|
||||
PyMarkedFunction marked = result.getMarkedFunction();
|
||||
if (marked == null) return;
|
||||
final PyFunction py_function = marked.getFunction();
|
||||
if (py_function == null) return; // resolution failed
|
||||
final PyParameterList parameterList = py_function.getParameterList();
|
||||
final PyParameter[] params = parameterList.getParameters();
|
||||
int currentParameterIndex = context.getCurrentParameterIndex() >= 0 ? context.getCurrentParameterIndex():params.length;
|
||||
final PyParameter[] params = py_function.getParameterList().getParameters();
|
||||
final PyArgumentList arglist = result.getArgumentList();
|
||||
int arg_index = context.getCurrentParameterIndex() >= 0 ? context.getCurrentParameterIndex():params.length;
|
||||
|
||||
int highlightStartOffset = -1;
|
||||
int highlightEndOffset = -1;
|
||||
|
||||
StringBuilder signatureBuilder = new StringBuilder();
|
||||
|
||||
for(int i=0; i<params.length; i++) {
|
||||
if (i == currentParameterIndex) {
|
||||
highlightStartOffset = signatureBuilder.length();
|
||||
}
|
||||
if (params [i].isPositionalContainer()) {
|
||||
signatureBuilder.append("*");
|
||||
}
|
||||
else if (i == 0 && p.getFlags().contains(Flag.IMPLICIT_FIRST_ARG)) {
|
||||
currentParameterIndex += 1;
|
||||
continue;
|
||||
}
|
||||
else if (params [i].isKeywordContainer()) {
|
||||
signatureBuilder.append("**");
|
||||
}
|
||||
signatureBuilder.append(params [i].getName());
|
||||
if (i == currentParameterIndex) {
|
||||
highlightEndOffset = signatureBuilder.length();
|
||||
}
|
||||
if (i < params.length-1) {
|
||||
signatureBuilder.append(", ");
|
||||
}
|
||||
// param texts
|
||||
String[] param_texts = new String[params.length];
|
||||
for (int i = 0; i < param_texts.length; i += 1) {
|
||||
StringBuilder strb = new StringBuilder();
|
||||
final PyParameter param = params[i];
|
||||
if (param.isKeywordContainer()) strb.append("**");
|
||||
else if (param.isPositionalContainer()) strb.append("*");
|
||||
strb.append(param.getName());
|
||||
PyExpression default_v = param.getDefaultValue();
|
||||
if (default_v != null) strb.append("=").append(PyResolveUtil.getReadableRepr(default_v));
|
||||
if (i < param_texts.length-1) strb.append(",");
|
||||
param_texts[i] = strb.toString();
|
||||
}
|
||||
|
||||
// formatting
|
||||
Map<PyParameter, Integer> param_indexes = new HashMap<PyParameter, Integer>();
|
||||
for (int i=0; i < params.length; i += 1) param_indexes.put(params[i], i);
|
||||
EnumSet<ParameterInfoUIContextEx.Flag>[] flags = (EnumSet<ParameterInfoUIContextEx.Flag>[])Array.newInstance(EnumSet.class, params.length);
|
||||
// ^^ gotta hate the covariance issues
|
||||
for (int i =0; i < flags.length; i += 1) flags[i] = EnumSet.noneOf(ParameterInfoUIContextEx.Flag.class);
|
||||
|
||||
if (marked.getFlags().contains(Flag.IMPLICIT_FIRST_ARG)) {
|
||||
//arg_index -= 1; // argument 0 is parameter 1, thus kipping para,eter 0 which is 'self'
|
||||
flags[0].add(ParameterInfoUIContextEx.Flag.STRIKEOUT); // show but mark as absent
|
||||
}
|
||||
int cur_arg_index = 0;
|
||||
for (PyExpression arg : arglist.getArguments()) {
|
||||
if (cur_arg_index == arg_index) {
|
||||
PyParameter param = result.getPlainMappedParams().get(arg);
|
||||
if (param != null) {
|
||||
final Integer param_index = param_indexes.get(param);
|
||||
if (param_index < flags.length) {
|
||||
flags[param_index].add(ParameterInfoUIContextEx.Flag.HIGHLIGHT);
|
||||
}
|
||||
}
|
||||
else if (arg == result.getTupleArg()) {
|
||||
// mark all params that map to *arg
|
||||
for (PyParameter tpar : result.getTupleMappedParams()) {
|
||||
final Integer param_index = param_indexes.get(tpar);
|
||||
if (param_index != null && param_index.intValue() < flags.length) flags[param_index.intValue()].add(ParameterInfoUIContextEx.Flag.HIGHLIGHT);
|
||||
}
|
||||
}
|
||||
else if (arg == result.getKwdArg()) {
|
||||
// mark all params that map to **arg
|
||||
for (PyParameter tpar : result.getKwdMappedParams()) {
|
||||
final Integer param_index = param_indexes.get(tpar);
|
||||
if (param_index != null && param_index < flags.length) flags[param_index].add(ParameterInfoUIContextEx.Flag.HIGHLIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
// else: stay unhilited
|
||||
cur_arg_index += 1;
|
||||
}
|
||||
|
||||
|
||||
if (context instanceof ParameterInfoUIContextEx) {
|
||||
final ParameterInfoUIContextEx pic = (ParameterInfoUIContextEx)context;
|
||||
pic.setupUIComponentPresentation(param_texts, flags, false, context.getDefaultParameterColor());
|
||||
}
|
||||
/*
|
||||
context.setupUIComponentPresentation(signatureBuilder.toString(), highlightStartOffset, highlightEndOffset, false, false, false,
|
||||
context.getDefaultParameterColor());
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ package com.jetbrains.python.psi;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* Represents an argument list of a function call.
|
||||
* User: yole
|
||||
* Date: 29.05.2005
|
||||
* Time: 13:44:24
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface PyArgumentList extends PyElement {
|
||||
|
||||
@@ -39,4 +39,79 @@ public interface PyArgumentList extends PyElement {
|
||||
@Nullable
|
||||
PyCallExpression getCallExpression();
|
||||
|
||||
/**
|
||||
* Tries to map the argument list to callee's idea of parameters.
|
||||
* @return a result object with mappings and diagnostic flags.
|
||||
*/
|
||||
AnalysisResult analyzeCall();
|
||||
|
||||
/**
|
||||
* Flags to mark analysis results for an argument.
|
||||
* Theoretically can be used together, but currently only make sense as a single value per argument.
|
||||
*/
|
||||
enum ArgFlag {
|
||||
/** duplicate plain */ IS_DUP,
|
||||
/** unexpected */ IS_UNMAPPED,
|
||||
/** duplicate **arg */ IS_DUP_KWD,
|
||||
/** duplicate *arg */ IS_DUP_TUPLE,
|
||||
/** positional past keyword */ IS_POS_PAST_KWD
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Result of analysis of argument list application to the callee.
|
||||
* Contains neatly arranged lists and mappinga between arguments and parameters,
|
||||
* including error diagnostics.
|
||||
*/
|
||||
interface AnalysisResult {
|
||||
|
||||
/**
|
||||
* @return A mapping parameter->argument for non-starred parameters (but includes starred argument).
|
||||
*/
|
||||
@NotNull Map<PyExpression, PyParameter> getPlainMappedParams();
|
||||
|
||||
/**
|
||||
* @return First *arg, or null.
|
||||
*/
|
||||
@Nullable
|
||||
PyStarArgument getTupleArg();
|
||||
|
||||
/**
|
||||
* @return A list of parameters mapped to a *arg.
|
||||
*/
|
||||
@NotNull List<PyParameter> getTupleMappedParams();
|
||||
|
||||
/**
|
||||
* @return First **arg, or null.
|
||||
*/
|
||||
@Nullable
|
||||
PyStarArgument getKwdArg();
|
||||
|
||||
/**
|
||||
* @return A list of parameters mapped to an **arg.
|
||||
*/
|
||||
@NotNull List<PyParameter> getKwdMappedParams();
|
||||
|
||||
/**
|
||||
* @return A list of parameters for which no arguments were found ('missing').
|
||||
*/
|
||||
@NotNull
|
||||
List<PyParameter> getUnmappedParams();
|
||||
|
||||
|
||||
/**
|
||||
* @return Lists all args with their flags.
|
||||
* @see ArgFlag
|
||||
*/
|
||||
Map<PyExpression, EnumSet<ArgFlag>> getArgumentFlags();
|
||||
|
||||
/**
|
||||
* @return result of a resolveCallee() against the function call to which the paramater list belongs.
|
||||
*/
|
||||
@Nullable
|
||||
PyCallExpression.PyMarkedFunction getMarkedFunction();
|
||||
|
||||
PyArgumentList getArgumentList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
@@ -28,7 +28,7 @@ import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
|
||||
public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList {
|
||||
public PyArgumentListImpl(ASTNode astNode) {
|
||||
@@ -246,4 +246,326 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList
|
||||
}
|
||||
}
|
||||
|
||||
public AnalysisResult analyzeCall() {
|
||||
AnalysisResultImpl ret = new AnalysisResultImpl();
|
||||
PyExpression[] arguments = getArguments();
|
||||
// declaration-based checks
|
||||
// proper arglist is: [positional,...][name=value,...][*tuple,][**dict]
|
||||
// following the spec: http://docs.python.org/ref/calls.html
|
||||
PyCallExpression call = getCallExpression();
|
||||
if (call != null) {
|
||||
PyCallExpression.PyMarkedFunction resolved_callee = call.resolveCallee();
|
||||
ret.my_marked_func = resolved_callee;
|
||||
if (resolved_callee != null) {
|
||||
PyFunction func = resolved_callee.getFunction();
|
||||
boolean implicit_self = resolved_callee.getFlags().contains(PyCallExpression.Flag.IMPLICIT_FIRST_ARG);
|
||||
PyParameter[] params = func.getParameterList().getParameters();
|
||||
// prepare args and slots
|
||||
List<PyExpression> unmatched_args = new LinkedList<PyExpression>();
|
||||
Collections.addAll(unmatched_args, arguments);
|
||||
Map<String, PyExpression> param_slots = new HashMap<String, PyExpression>();
|
||||
PyParameter kwd_slot = null; // the *tuple. might be just boolean, but this way debugging is easier
|
||||
PyParameter tuple_slot = null; // the **kwd
|
||||
PyStarArgument kwd_arg = null;
|
||||
PyStarArgument tuple_arg = null;
|
||||
// all slots are initially empty, *x and **x are not among slots
|
||||
for (PyParameter a_param : params) {
|
||||
if (a_param.isPositionalContainer()) tuple_slot = a_param;
|
||||
else if (a_param.isKeywordContainer()) kwd_slot = a_param;
|
||||
else param_slots.put(a_param.getName(), null);
|
||||
}
|
||||
// look for star args
|
||||
for (PyExpression arg : arguments) {
|
||||
if (arg instanceof PyStarArgument) {
|
||||
final PyStarArgument star_arg = (PyStarArgument)arg;
|
||||
if (star_arg.isKeyword()) {
|
||||
if (kwd_arg == null) kwd_arg = star_arg;
|
||||
else {
|
||||
ret.markArgument(arg, ArgFlag.IS_DUP_KWD);
|
||||
//getHolder().createErrorAnnotation(arg, "duplicate **arg");
|
||||
unmatched_args.remove(arg); // error. ignore later
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tuple_arg == null) {
|
||||
tuple_arg = star_arg;
|
||||
}
|
||||
else {
|
||||
ret.markArgument(arg, ArgFlag.IS_DUP_TUPLE);
|
||||
//getHolder().createErrorAnnotation(arg, "duplicate *arg");
|
||||
unmatched_args.remove(arg); // error. ignore later
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// rule out 'self'
|
||||
int param_index = 0;
|
||||
if (implicit_self && (params.length > 0)) {
|
||||
param_slots.remove(params[0].getName()); // the self param
|
||||
param_index = 1;
|
||||
}
|
||||
boolean seen_tuple_arg = false;
|
||||
boolean seen_kwd_arg = false;
|
||||
ListIterator<PyExpression> unmatched_arg_iter = unmatched_args.listIterator();
|
||||
// check positional args
|
||||
while (unmatched_arg_iter.hasNext() && (param_index < params.length)) {
|
||||
PyExpression arg = unmatched_arg_iter.next(); // current arg
|
||||
PyParameter param = params[param_index]; // its matching param
|
||||
if (
|
||||
arg instanceof PyKeywordArgument || arg instanceof PyStarArgument ||
|
||||
param.isKeywordContainer() || param.isPositionalContainer()
|
||||
) {
|
||||
seen_tuple_arg |= (arg == tuple_arg);
|
||||
seen_kwd_arg |= (arg == kwd_arg);
|
||||
unmatched_arg_iter.previous(); // step back
|
||||
break;
|
||||
}
|
||||
param_slots.put(param.getName(), arg); // it cannot yet contain this name unless function definition is broken
|
||||
ret.my_plain_mapped_params.put(arg, param);
|
||||
unmatched_arg_iter.remove(); // it has been matched
|
||||
param_index += 1;
|
||||
}
|
||||
if (!seen_kwd_arg) { // **kwd arg is the last; if it's present, checking the rest would be useless
|
||||
if (!seen_tuple_arg) { // any pos args can only come before *arg
|
||||
// some pos args might go to a *param
|
||||
if (tuple_slot != null) {
|
||||
while (unmatched_arg_iter.hasNext()) {
|
||||
PyExpression arg = unmatched_arg_iter.next();
|
||||
if (arg instanceof PyKeywordArgument) {
|
||||
unmatched_arg_iter.previous(); // step back
|
||||
break;
|
||||
}
|
||||
ret.my_plain_mapped_params.put(arg, tuple_slot);
|
||||
unmatched_arg_iter.remove(); // consumed as nameless
|
||||
}
|
||||
}
|
||||
}
|
||||
// check named args
|
||||
boolean seen_kwd = false;
|
||||
while (unmatched_arg_iter.hasNext()) {
|
||||
PyExpression arg = unmatched_arg_iter.next();
|
||||
if (arg instanceof PyKeywordArgument) {
|
||||
if (!seen_kwd_arg && !seen_tuple_arg) {
|
||||
final String argname = ((PyKeywordArgument)arg).getKeyword();
|
||||
if (param_slots.containsKey(argname)) { // slot is known
|
||||
if (param_slots.get(argname) == null) { // slot is not filled
|
||||
param_slots.put(argname, arg);
|
||||
// we'll put() it to ret.my_plain_mapped_params later
|
||||
seen_kwd = true;
|
||||
}
|
||||
else {
|
||||
//getHolder().createErrorAnnotation(arg, "duplicate arg '" + argname + "'");
|
||||
ret.markArgument(arg, ArgFlag.IS_DUP);
|
||||
}
|
||||
unmatched_arg_iter.remove(); // it has been matched or flagged, forget
|
||||
}
|
||||
// else: ignore unknown arg, we'll deal with them later
|
||||
}
|
||||
else {
|
||||
ret.markArgument(arg, ArgFlag.IS_UNMAPPED);
|
||||
//getHolder().createErrorAnnotation(arg, "cannot appear past an *arg");
|
||||
unmatched_arg_iter.remove(); // it has been flagged, forget
|
||||
}
|
||||
}
|
||||
else if (seen_kwd && (arg != kwd_arg)) {
|
||||
ret.markArgument(arg, ArgFlag.IS_POS_PAST_KWD);
|
||||
//getHolder().createErrorAnnotation(arg, "non-keyword arg after keyword arg");
|
||||
unmatched_arg_iter.remove(); // it has been flagged, forget
|
||||
}
|
||||
seen_tuple_arg |= (arg == tuple_arg);
|
||||
seen_kwd_arg |= (arg == kwd_arg);
|
||||
}
|
||||
// some named args might go to a **kwd param
|
||||
if (kwd_slot != null) {
|
||||
unmatched_arg_iter = unmatched_args.listIterator(); // anew
|
||||
while (unmatched_arg_iter.hasNext()) {
|
||||
PyExpression arg = unmatched_arg_iter.next();
|
||||
if (arg instanceof PyKeywordArgument) {
|
||||
ret.my_plain_mapped_params.put(arg, kwd_slot);
|
||||
unmatched_arg_iter.remove(); // consumed by **kwd
|
||||
}
|
||||
// no else: name errors are all detected above
|
||||
}
|
||||
}
|
||||
}
|
||||
if (seen_tuple_arg) { // link remaining params to *arg if present
|
||||
for (PyParameter param : params) {
|
||||
final String param_name = param.getName();
|
||||
if (
|
||||
(param.getDefaultValue() == null) && // has no default value
|
||||
param_slots.containsKey(param_name) && // known as a slot
|
||||
(param_slots.get(param_name) == null) // the slot yet unfilled
|
||||
) {
|
||||
param_slots.put(param_name, tuple_arg);
|
||||
unmatched_args.remove(tuple_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (seen_kwd_arg) { // link remaining params to **kwarg if present
|
||||
for (PyParameter param : params) {
|
||||
final String param_name = param.getName();
|
||||
if (
|
||||
(param.getDefaultValue() == null) && // has no default value
|
||||
param_slots.containsKey(param_name) && // known as a slot
|
||||
(param_slots.get(param_name) == null) // the slot yet unfilled
|
||||
) {
|
||||
param_slots.put(param_name, kwd_arg);
|
||||
unmatched_args.remove(kwd_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
// check and collect all yet unfilled params without default values
|
||||
Map<String, PyParameter> unfilled_params = new HashMap<String, PyParameter>();
|
||||
for (PyParameter param : params) {
|
||||
final String param_name = param.getName();
|
||||
if (
|
||||
(param.getDefaultValue() == null) && // has no default value
|
||||
param_slots.containsKey(param_name) && // known as a slot
|
||||
(param_slots.get(param_name) == null) // the slot yet unfilled
|
||||
) {
|
||||
if (tuple_arg != null) {
|
||||
// An *arg, if present, fills all positional params
|
||||
param_slots.put(param_name, tuple_arg);
|
||||
unmatched_args.remove(tuple_arg);
|
||||
}
|
||||
else {
|
||||
unfilled_params.put(param_name, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
// *arg and **kwarg are not in slots list; write any *param or **param off to them if present.
|
||||
if (kwd_arg != null && kwd_slot != null) {
|
||||
ret.my_kwd_mapped_params.add(kwd_slot);
|
||||
unmatched_args.remove(kwd_arg);
|
||||
}
|
||||
if (tuple_arg != null && tuple_slot != null) {
|
||||
ret.my_tuple_mapped_params.add(tuple_slot);
|
||||
unmatched_args.remove(tuple_arg);
|
||||
}
|
||||
// any args left?
|
||||
for (PyExpression arg : unmatched_args) {
|
||||
//getHolder().createErrorAnnotation(arg, "unexpected arg");
|
||||
ret.markArgument(arg, ArgFlag.IS_UNMAPPED);
|
||||
}
|
||||
// any params still unfilled?
|
||||
for (final PyParameter param : unfilled_params.values()) {
|
||||
// getHolder().createErrorAnnotation(close_paren, "parameter '" + param_name + "' unfilled");
|
||||
ret.my_unmapped_params.add(param);
|
||||
}
|
||||
// copy the mapping of args
|
||||
for (PyParameter param : params) {
|
||||
PyExpression arg = param_slots.get(param.getName());
|
||||
if (arg != null) {
|
||||
if (arg instanceof PyStarArgument) {
|
||||
PyStarArgument star_arg = (PyStarArgument)arg;
|
||||
if (star_arg.isKeyword()) ret.my_kwd_mapped_params.add(param);
|
||||
else ret.my_tuple_mapped_params.add(param);
|
||||
}
|
||||
else ret.my_plain_mapped_params.put(arg, param);
|
||||
}
|
||||
}
|
||||
// copy starred args
|
||||
ret.my_kwd_arg = kwd_arg;
|
||||
ret.my_tuple_arg = tuple_arg;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
protected /*static*/ class AnalysisResultImpl implements AnalysisResult {
|
||||
|
||||
protected Map<PyExpression, PyParameter> my_plain_mapped_params;
|
||||
protected PyStarArgument my_tuple_arg;
|
||||
protected PyStarArgument my_kwd_arg;
|
||||
protected List<PyParameter> my_tuple_mapped_params;
|
||||
protected List<PyParameter> my_kwd_mapped_params;
|
||||
protected List<PyParameter> my_unmapped_params;
|
||||
protected Map<PyExpression, EnumSet<ArgFlag>> my_arg_flags;
|
||||
protected PyCallExpression.PyMarkedFunction my_marked_func;
|
||||
|
||||
public AnalysisResultImpl() {
|
||||
// full of empty containers
|
||||
my_plain_mapped_params = new HashMap<PyExpression, PyParameter>();
|
||||
my_tuple_mapped_params = new ArrayList<PyParameter>();
|
||||
my_kwd_mapped_params = new ArrayList<PyParameter>();
|
||||
my_unmapped_params = new ArrayList<PyParameter>();
|
||||
my_arg_flags = new HashMap<PyExpression, EnumSet<ArgFlag>>();
|
||||
my_marked_func = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A mapping argument->parameter for non-starred arguments (but includes starred parameters).
|
||||
*/
|
||||
public @NotNull Map<PyExpression, PyParameter> getPlainMappedParams() {
|
||||
return my_plain_mapped_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return First *arg, or null.
|
||||
*/
|
||||
public PyStarArgument getTupleArg(){
|
||||
return my_tuple_arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A list of parameters mapped to an *arg.
|
||||
*/
|
||||
public @NotNull List<PyParameter> getTupleMappedParams(){
|
||||
return my_tuple_mapped_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return First **arg, or null.
|
||||
*/
|
||||
public PyStarArgument getKwdArg(){
|
||||
return my_kwd_arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A list of parameters mapped to an **arg.
|
||||
*/
|
||||
public @NotNull List<PyParameter> getKwdMappedParams(){
|
||||
return my_kwd_mapped_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A list of parameters for which no arguments were found ('missing').
|
||||
*/
|
||||
public @NotNull
|
||||
List<PyParameter> getUnmappedParams(){
|
||||
return my_unmapped_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return result of a resolveCallee() against the function call to which the paramater list belongs.
|
||||
*/
|
||||
@Nullable
|
||||
public PyCallExpression.PyMarkedFunction getMarkedFunction() {
|
||||
return my_marked_func;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lists all args with their flags.
|
||||
*/
|
||||
public Map<PyExpression, EnumSet<ArgFlag>> getArgumentFlags(){
|
||||
return my_arg_flags;
|
||||
}
|
||||
|
||||
public PyArgumentList getArgumentList() {
|
||||
return PyArgumentListImpl.this; // that is, 'outer'
|
||||
}
|
||||
|
||||
protected PyExpression markArgument(PyExpression arg, ArgFlag... flags) {
|
||||
EnumSet<ArgFlag> argflags = my_arg_flags.get(arg);
|
||||
if (argflags == null) {
|
||||
argflags = EnumSet.noneOf(ArgFlag.class);
|
||||
}
|
||||
argflags.addAll(Arrays.asList(flags));
|
||||
my_arg_flags.put(arg, argflags);
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
def f():
|
||||
def q():
|
||||
return t<ref>arget
|
||||
target = 1
|
||||
Reference in New Issue
Block a user