|
65 | 65 | import groovyjarjarasm.asm.MethodVisitor;
|
66 | 66 |
|
67 | 67 | import java.util.ArrayList;
|
| 68 | +import java.util.Arrays; |
68 | 69 | import java.util.List;
|
69 | 70 | import java.util.Map;
|
70 | 71 | import java.util.concurrent.atomic.AtomicInteger;
|
| 72 | +import static java.util.stream.Collectors.joining; |
71 | 73 |
|
72 | 74 | import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
|
73 | 75 | import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
|
@@ -422,7 +424,8 @@ protected static boolean isPrivateBridgeMethodsCallAllowed(final ClassNode recei
|
422 | 424 | }
|
423 | 425 |
|
424 | 426 | @Override
|
425 |
| - protected void loadArguments(final List<Expression> argumentList, final Parameter[] para) { |
| 427 | + protected void loadArguments(final List<Expression> argumentList, final Parameter[] parameters) { |
| 428 | + /* GRECLIPSE edit -- GROOVY-9918 |
426 | 429 | if (para.length == 0) return;
|
427 | 430 | ClassNode lastParaType = para[para.length - 1].getOriginType();
|
428 | 431 | AsmClassGenerator acg = controller.getAcg();
|
@@ -492,6 +495,80 @@ protected void loadArguments(final List<Expression> argumentList, final Paramete
|
492 | 495 | visitArgument(arguments[i], para[i].getType());
|
493 | 496 | }
|
494 | 497 | }
|
| 498 | + */ |
| 499 | + final int nArgs = argumentList.size(), nPrms = parameters.length; if (nPrms == 0) return; |
| 500 | + |
| 501 | + ClassNode classNode = controller.getClassNode(); |
| 502 | + TypeChooser typeChooser = controller.getTypeChooser(); |
| 503 | + ClassNode lastArgType = nArgs == 0 ? null : typeChooser.resolveType(argumentList.get(nArgs - 1), classNode); |
| 504 | + ClassNode lastPrmType = parameters[nPrms - 1].getOriginType(); |
| 505 | + |
| 506 | + // target is variadic and args are too many or one short or just enough with array compatibility |
| 507 | + if (lastPrmType.isArray() && (nArgs > nPrms || nArgs == nPrms - 1 |
| 508 | + || (nArgs == nPrms && !lastArgType.isArray() |
| 509 | + && (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType, lastPrmType.getComponentType()) |
| 510 | + || ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastPrmType.getComponentType()))) |
| 511 | + )) { |
| 512 | + OperandStack operandStack = controller.getOperandStack(); |
| 513 | + int stackLength = operandStack.getStackLength() + nArgs; |
| 514 | + // first arguments/parameters as usual |
| 515 | + for (int i = 0; i < nPrms - 1; i += 1) { |
| 516 | + visitArgument(argumentList.get(i), parameters[i].getType()); |
| 517 | + } |
| 518 | + // wrap remaining arguments in an array for last parameter |
| 519 | + List<Expression> lastArgs = new ArrayList<>(); |
| 520 | + for (int i = nPrms - 1; i < nArgs; i += 1) { |
| 521 | + lastArgs.add(argumentList.get(i)); |
| 522 | + } |
| 523 | + ArrayExpression array = new ArrayExpression(lastPrmType.getComponentType(), lastArgs); |
| 524 | + array.visit(controller.getAcg()); |
| 525 | + // adjust stack length |
| 526 | + while (operandStack.getStackLength() < stackLength) { |
| 527 | + operandStack.push(ClassHelper.OBJECT_TYPE); |
| 528 | + } |
| 529 | + if (nArgs == nPrms - 1) { |
| 530 | + operandStack.remove(1); |
| 531 | + } |
| 532 | + } else if (nArgs == nPrms) { |
| 533 | + for (int i = 0; i < nArgs; i += 1) { |
| 534 | + visitArgument(argumentList.get(i), parameters[i].getType()); |
| 535 | + } |
| 536 | + } else { // call with default arguments |
| 537 | + Expression[] arguments = new Expression[nPrms]; |
| 538 | + for (int i = 0, j = 0; i < nPrms; i += 1) { |
| 539 | + Parameter p = parameters[i]; |
| 540 | + ClassNode pType = p.getType(); |
| 541 | + Expression a = (j < nArgs ? argumentList.get(j) : null); |
| 542 | + ClassNode aType = (a == null ? null : typeChooser.resolveType(a, classNode)); |
| 543 | + |
| 544 | + Expression expression = getInitialExpression(p); // default argument |
| 545 | + if (expression != null && !compatibleArgumentType(aType, pType)) { |
| 546 | + arguments[i] = expression; |
| 547 | + } else if (a != null) { |
| 548 | + arguments[i] = a; |
| 549 | + j += 1; |
| 550 | + } else { |
| 551 | + controller.getSourceUnit().addFatalError("Binding failed" + |
| 552 | + " for arguments [" + argumentList.stream().map(arg -> typeChooser.resolveType(arg, classNode).toString(false)).collect(joining(", ")) + "]" + |
| 553 | + " and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(joining(", ")) + "]", getCurrentCall()); |
| 554 | + } |
| 555 | + } |
| 556 | + for (int i = 0; i < nArgs; i += 1) { |
| 557 | + visitArgument(arguments[i], parameters[i].getType()); |
| 558 | + } |
| 559 | + } |
| 560 | + // GRECLIPSE end |
| 561 | + } |
| 562 | + |
| 563 | + private static Expression getInitialExpression(final Parameter parameter) { |
| 564 | + Expression initialExpression = parameter.getNodeMetaData(StaticTypesMarker.INITIAL_EXPRESSION); |
| 565 | + if (initialExpression == null && parameter.hasInitialExpression()) { |
| 566 | + initialExpression = parameter.getInitialExpression(); |
| 567 | + } |
| 568 | + if (initialExpression == null && parameter.getNodeMetaData(Verifier.INITIAL_EXPRESSION) != null) { |
| 569 | + initialExpression = parameter.getNodeMetaData(Verifier.INITIAL_EXPRESSION); |
| 570 | + } |
| 571 | + return initialExpression; |
495 | 572 | }
|
496 | 573 |
|
497 | 574 | private void visitArgument(final Expression argumentExpr, final ClassNode parameterType) {
|
|
0 commit comments