diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 0fc4a0591414..de4191afcd9a 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -717,9 +717,18 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo // We want to align chained method calls only if method target is explicitly specified, i.e. we don't want to align methods // chain like 'recursive().recursive().recursive()' but want to align calls like 'foo.recursive().recursive().recursive()' boolean callPointDefined = false; + List lookAheadNodes = null; + boolean afterIdentifier = false; - while (!nodes.isEmpty()) { - ArrayList subNodes = readToNextDot(nodes); + while (!nodes.isEmpty() || lookAheadNodes != null) { + final List subNodes; + if (lookAheadNodes == null) { + subNodes = readToNextDot(nodes); + } + else { + subNodes = new ArrayList(lookAheadNodes); + lookAheadNodes = null; + } Alignment alignmentToUseForSubBlock = null; // Just create a no-aligned sub-block if we don't need to bother with it's alignment (either due to end-user @@ -743,6 +752,18 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (callPointDefined && currentSubBlockIsMethodCall) { alignmentToUseForSubBlock = chainedCallsAlignment; } + else if (afterIdentifier && lastNodeType == JavaTokenType.IDENTIFIER) { + // Align method call to the last field access. Example: + // MyClass.staticField + // .foo(); + lookAheadNodes = readToNextDot(nodes); + if (lookAheadNodes != null && !lookAheadNodes.isEmpty() + && lookAheadNodes.get(lookAheadNodes.size() - 1).getElementType() == JavaElementType.EXPRESSION_LIST) + { + alignmentToUseForSubBlock = chainedCallsAlignment; + } + } + afterIdentifier = lastNodeType == JavaTokenType.IDENTIFIER; subBlocks.add(createSyntheticBlock(subNodes, wrap, alignmentToUseForSubBlock)); } @@ -750,7 +771,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), blockWrap); } - private Block createSyntheticBlock(final ArrayList subNodes, final Wrap wrap, @Nullable final Alignment alignment) { + private Block createSyntheticBlock(final List subNodes, final Wrap wrap, @Nullable final Alignment alignment) { final ArrayList subBlocks = new ArrayList(); final ASTNode firstNode = subNodes.get(0); if (firstNode.getElementType() == JavaTokenType.DOT) { @@ -768,7 +789,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } } - private List createJavaBlocks(final ArrayList subNodes) { + private List createJavaBlocks(final List subNodes) { final ArrayList result = new ArrayList(); for (ASTNode node : subNodes) { result.add(createJavaBlock(node, getSettings(), Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), null, @@ -777,7 +798,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo return result; } - private static ArrayList readToNextDot(final ArrayList nodes) { + private static List readToNextDot(final ArrayList nodes) { final ArrayList result = new ArrayList(); result.add(nodes.remove(0)); for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java index 5becdd5f43f3..79537e097c43 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java @@ -36,6 +36,18 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest { doTest(); } + public void testMethodAndChainedField() throws Exception { + // Inspired by IDEA-79806 + + getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true; + doMethodTest( + "Holder.INSTANCE\n" + + " .foo();", + "Holder.INSTANCE\n" + + " .foo();" + ); + } + public void testMultipleMethodAnnotationsCommentedInTheMiddle() throws Exception { getSettings().BLANK_LINES_AFTER_CLASS_HEADER = 1; getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA).INDENT_SIZE = 4;