diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java index 2c76dcfd1d70..87418726fb1c 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java @@ -20,10 +20,11 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.*; import static com.intellij.psi.impl.PsiImplUtil.isTypeAnnotation; @@ -34,6 +35,8 @@ public final class JavaFormatterUtil { private static final TokenSet ASSIGNMENT_ELEMENT_TYPES = TokenSet .create(JavaElementType.ASSIGNMENT_EXPRESSION, JavaElementType.LOCAL_VARIABLE, JavaElementType.FIELD); + private static final int CALL_EXPRESSION_DEPTH = 2500; + private JavaFormatterUtil() { } /** @@ -524,19 +527,31 @@ public final class JavaFormatterUtil { * */ public static void collectCallExpressionNodes(@NotNull List nodes, @NotNull ASTNode node) { - ASTNode child = node.getFirstChildNode(); - while (child != null) { - if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - IElementType type = child.getElementType(); - if (type == JavaElementType.METHOD_CALL_EXPRESSION || - type == JavaElementType.REFERENCE_EXPRESSION) { - collectCallExpressionNodes(nodes, child); - } - else { - nodes.add(child); - } + ArrayDeque stack = new ArrayDeque<>(CALL_EXPRESSION_DEPTH); + stack.addLast(node.getFirstChildNode()); + while (!stack.isEmpty()) { + if (stack.size() >= CALL_EXPRESSION_DEPTH) { + throw new IllegalStateException("Too long call chain! " + node); } - child = child.getTreeNext(); + ASTNode currentNode = stack.removeLast(); + if (!FormatterUtil.containsWhiteSpacesOnly(currentNode)) { + IElementType type = currentNode.getElementType(); + if (type == JavaElementType.METHOD_CALL_EXPRESSION || + type == JavaElementType.REFERENCE_EXPRESSION) { + ASTNode firstChild = currentNode.getFirstChildNode(); + currentNode = FormatterUtil.getNextNonWhitespaceSibling(currentNode); + ContainerUtil.addIfNotNull(stack, currentNode); + ContainerUtil.addIfNotNull(stack, firstChild); + } + else { + nodes.add(currentNode); + currentNode = FormatterUtil.getNextNonWhitespaceSibling(currentNode); + ContainerUtil.addIfNotNull(stack, currentNode); + } + } else { + currentNode = FormatterUtil.getNextNonWhitespaceSibling(currentNode); + ContainerUtil.addIfNotNull(stack, currentNode); + } } } }