Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1866,15 +1866,39 @@ public J visitArgument(KtValueArgument argument, ExecutionContext data) {

@Override
public J visitBinaryExpression(KtBinaryExpression expression, ExecutionContext data) {
assert expression.getLeft() != null;
assert expression.getRight() != null;
// Collect left-spine of nested binary expressions to process iteratively,
// avoiding StackOverflowError on deeply nested expressions (e.g. 2000+ concatenations)
List<KtBinaryExpression> spine = new ArrayList<>();
KtExpression leftmost = expression;
while (leftmost instanceof KtBinaryExpression) {
spine.add((KtBinaryExpression) leftmost);
leftmost = ((KtBinaryExpression) leftmost).getLeft();
}

// Visit the deepest left operand (not a binary expression)
assert leftmost != null;
J leftJ = leftmost.accept(this, data);

// Process each binary expression from innermost to outermost
J result = null;
for (int i = spine.size() - 1; i >= 0; i--) {
KtBinaryExpression binExpr = spine.get(i);
assert binExpr.getRight() != null;

Expression left = convertToExpression(leftJ).withPrefix(Space.EMPTY);
result = visitSingleBinaryExpression(binExpr, left, data);
leftJ = result;
}

return result;
}

private J visitSingleBinaryExpression(KtBinaryExpression expression, Expression left, ExecutionContext data) {
KtOperationReferenceExpression operationReference = expression.getOperationReference();
J.Binary.Type javaBinaryType = mapJBinaryType(operationReference);
J.AssignmentOperation.Type assignmentOperationType = javaBinaryType == null ? mapAssignmentOperationType(operationReference) : null;
K.Binary.Type kotlinBinaryType = javaBinaryType == null && assignmentOperationType == null ? mapKBinaryType(operationReference) : null;

Expression left = convertToExpression(expression.getLeft().accept(this, data)).withPrefix(Space.EMPTY);
Expression right = convertToExpression((expression.getRight()).accept(this, data))
.withPrefix(prefix(expression.getRight()));
JavaType type = type(expression);
Expand Down Expand Up @@ -1921,7 +1945,7 @@ public J visitBinaryExpression(KtBinaryExpression expression, ExecutionContext d
));
}

return mapFunctionCall(expression, data);
return mapFunctionCall(expression, left, data);
}

private J.AssignmentOperation.@Nullable Type mapAssignmentOperationType(KtOperationReferenceExpression operationReference) {
Expand Down Expand Up @@ -3398,12 +3422,12 @@ else if (elementType == KtTokens.OROR)
}
}

private J.MethodInvocation mapFunctionCall(KtBinaryExpression expression, ExecutionContext data) {
private J.MethodInvocation mapFunctionCall(KtBinaryExpression expression, Expression precomputedLeft, ExecutionContext data) {
Markers markers = Markers.EMPTY
.addIfAbsent(new Infix(randomId()))
.addIfAbsent(new Extension(randomId()));

Expression selectExp = convertToExpression(requireNonNull(expression.getLeft()).accept(this, data).withPrefix(prefix(expression.getLeft())));
Expression selectExp = precomputedLeft.withPrefix(prefix(expression.getLeft()));
JRightPadded<Expression> select = padRight(selectExp, Space.EMPTY);
J.Identifier name = (J.Identifier) expression.getOperationReference().accept(this, data); // createIdentifier(operation, Space.EMPTY, methodInvocationType(expression));

Expand Down