diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java index 5d41de0fec43..b29b7fd66d38 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/SimpleJavaBlock.java @@ -24,11 +24,15 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaDocElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.StdTokenSets; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class SimpleJavaBlock extends AbstractJavaBlock { @@ -102,7 +106,11 @@ public class SimpleJavaBlock extends AbstractJavaBlock { } else { return super.getChildAttributes(newChildIndex); } - } else { + } + else if (myNode.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) { + return new ChildAttributes(Indent.getNormalIndent(), null); + } + else { return super.getChildAttributes(newChildIndex); } } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java index efbe3362dbff..9bc24c09f564 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java @@ -19,6 +19,8 @@ import com.intellij.formatting.*; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.common.AbstractBlock; import org.jetbrains.annotations.NotNull; @@ -84,13 +86,36 @@ public class SyntheticCodeBlock implements Block, JavaBlock{ } public String toString() { - final ASTNode treeNode = ((AbstractBlock)mySubBlocks.get(0)).getNode(); + ASTNode treeNode = null; + Block child = mySubBlocks.get(0); + while (treeNode == null) { + if (child instanceof AbstractBlock) { + treeNode = ((AbstractBlock)child).getNode(); + } + else if (child instanceof SyntheticCodeBlock) { + child = ((SyntheticCodeBlock)child).mySubBlocks.get(0); + } + else { + break; + } + } final TextRange textRange = getTextRange(); - return treeNode.getPsi().getContainingFile().getText().subSequence(textRange.getStartOffset(), textRange.getEndOffset()).toString(); + if (treeNode != null) { + PsiElement psi = treeNode.getPsi(); + if (psi != null) { + PsiFile file = psi.getContainingFile(); + if (file != null) { + return file.getText().subSequence(textRange.getStartOffset(), textRange.getEndOffset()) + " " + textRange; + } + } + } + return getClass().getName() + ": " + textRange; } public ASTNode getFirstTreeNode() { - return AbstractJavaBlock.getTreeNode(mySubBlocks.get(0)); + ASTNode result = AbstractJavaBlock.getTreeNode(mySubBlocks.get(0)); + assert result != null; + return result; } public void setChildAttributes(final ChildAttributes childAttributes) { diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 452adacfeabf..72421e87eefb 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -1128,8 +1128,9 @@ class FormatProcessor { } private static int getNewChildPosition(final AbstractBlockWrapper parent, final int offset) { - if (!(parent instanceof CompositeBlockWrapper)) return 0; - final List subBlocks = ((CompositeBlockWrapper)parent).getChildren(); + AbstractBlockWrapper parentBlockToUse = getLastNestedCompositeBlockForSameRange(parent); + if (!(parentBlockToUse instanceof CompositeBlockWrapper)) return 0; + final List subBlocks = ((CompositeBlockWrapper)parentBlockToUse).getChildren(); //noinspection ConstantConditions if (subBlocks != null) { for (int i = 0; i < subBlocks.size(); i++) { @@ -1159,7 +1160,7 @@ class FormatProcessor { private AbstractBlockWrapper getParentFor(final int offset, LeafBlockWrapper block) { AbstractBlockWrapper previous = getPreviousIncompleteBlock(block, offset); if (previous != null) { - return previous; + return getLastNestedCompositeBlockForSameRange(previous); } else { return getParentFor(offset, (AbstractBlockWrapper)block); @@ -1215,12 +1216,47 @@ class FormatProcessor { @Nullable private static AbstractBlockWrapper getLastChildOf(final AbstractBlockWrapper currentResult) { - if (!(currentResult instanceof CompositeBlockWrapper)) return null; - final List subBlocks = ((CompositeBlockWrapper)currentResult).getChildren(); + AbstractBlockWrapper parentBlockToUse = getLastNestedCompositeBlockForSameRange(currentResult); + if (!(parentBlockToUse instanceof CompositeBlockWrapper)) return null; + final List subBlocks = ((CompositeBlockWrapper)parentBlockToUse).getChildren(); if (subBlocks.isEmpty()) return null; return subBlocks.get(subBlocks.size() - 1); } + /** + * There is a possible case that particular block is a composite block that contains number of nested composite blocks + * that all target the same text range. This method allows to derive the most nested block that shares the same range (if any). + * + * @param block block to check + * @return the most nested block of the given one that shares the same text range if any; given block otherwise + */ + @NotNull + private static AbstractBlockWrapper getLastNestedCompositeBlockForSameRange(@NotNull final AbstractBlockWrapper block) { + if (!(block instanceof CompositeBlockWrapper)) { + return block; + } + + AbstractBlockWrapper result = block; + AbstractBlockWrapper candidate = block; + while (true) { + List subBlocks = ((CompositeBlockWrapper)candidate).getChildren(); + if (subBlocks == null || subBlocks.size() != 1) { + break; + } + + candidate = subBlocks.get(0); + if (candidate.getStartOffset() == block.getStartOffset() && candidate.getEndOffset() == block.getEndOffset() + && candidate instanceof CompositeBlockWrapper) + { + result = candidate; + } + else { + break; + } + } + return result; + } + private void processBlocksBefore(final int offset) { while (true) { myAlignAgain.clear();