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 PyExpression arg = argEntry.getKey(); if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP)) { holder.registerProblem(arg, PyBundle.message("INSP.duplicate.argument")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP_KWD)) { holder.registerProblem(arg, PyBundle.message("INSP.duplicate.doublestar.arg")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_DUP_TUPLE)) { holder.registerProblem(arg, PyBundle.message("INSP.duplicate.star.arg")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_POS_PAST_KWD)) { holder.registerProblem( arg, PyBundle.message("INSP.cannot.appear.past.keyword.arg"), ProblemHighlightType.ERROR); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_UNMAPPED)) { holder.registerProblem(arg, PyBundle.message("INSP.unexpected.arg")); } if (flags.contains(CallArgumentsMapping.ArgFlag.IS_TOO_LONG)) { final PyCallExpression.PyMarkedCallee markedCallee = result.getMarkedCallee(); String parameterName = null; if (markedCallee != null) { 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() && param.getDefaultValue() == null && !unmappedParams.contains(param)) { parameterName = param.getName(); break; } } } holder.registerProblem( arg, parameterName != null ? PyBundle.message( "INSP.multiple.values.resolve.to.positional.$0", parameterName) : PyBundle.message("INSP.more.args.that.pos.params")); } } } } }
@Override public void visitPyDecoratorList(final PyDecoratorList node) { PyDecorator[] decorators = node.getDecorators(); for (PyDecorator deco : decorators) { if (deco.hasArgumentList()) continue; final PyCallExpression.PyMarkedCallee markedCallee = deco.resolveCallee(resolveWithoutImplicits()); if (markedCallee != null && !markedCallee.isImplicitlyResolved()) { final Callable callable = markedCallee.getCallable(); int firstParamOffset = markedCallee.getImplicitOffset(); final List<PyParameter> params = PyUtil.getParameters(callable, myTypeEvalContext); final PyNamedParameter allegedFirstParam = params.size() < firstParamOffset ? null : params.get(firstParamOffset - 1).getAsNamed(); if (allegedFirstParam == null || allegedFirstParam.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 = firstParamOffset; i < params.size(); i += 1) { final PyParameter parameter = params.get(i); if (parameter instanceof PySingleStarParameter) continue; final PyNamedParameter par = parameter.getAsNamed(); // param tuples, non-starred or non-default won't do if (par == null || (!par.isKeywordContainer() && !par.isPositionalContainer() && !par.hasDefaultValue())) { String parameterName = par != null ? par.getName() : "(...)"; registerProblem( deco, PyBundle.message("INSP.parameter.$0.unfilled", parameterName)); } } } } // else: this case is handled by arglist visitor } }
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); final PyCallExpression.PyMarkedCallee callee = result.getMarkedCallee(); if (callee != null) { final Callable callable = callee.getCallable(); // Decorate functions may have different parameter lists. We don't match arguments with // parameters of decorators yet if (callable instanceof PyFunction && PyUtil.hasCustomDecorators((PyFunction) callable)) { return; } } highlightIncorrectArguments(holder, result, context); highlightMissingArguments(node, holder, result); highlightStarArgumentTypeMismatch(node, holder, context); }