mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-64989 Regression: Smart Indent doesn't indent properly after hitting Enter on an indented line
1. Corrected smart indent processing for incomplete chained method call expression; 2. Corresponding test is added; 3. Green code policy is applied;
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1128,8 +1128,9 @@ class FormatProcessor {
|
||||
}
|
||||
|
||||
private static int getNewChildPosition(final AbstractBlockWrapper parent, final int offset) {
|
||||
if (!(parent instanceof CompositeBlockWrapper)) return 0;
|
||||
final List<AbstractBlockWrapper> subBlocks = ((CompositeBlockWrapper)parent).getChildren();
|
||||
AbstractBlockWrapper parentBlockToUse = getLastNestedCompositeBlockForSameRange(parent);
|
||||
if (!(parentBlockToUse instanceof CompositeBlockWrapper)) return 0;
|
||||
final List<AbstractBlockWrapper> 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<AbstractBlockWrapper> subBlocks = ((CompositeBlockWrapper)currentResult).getChildren();
|
||||
AbstractBlockWrapper parentBlockToUse = getLastNestedCompositeBlockForSameRange(currentResult);
|
||||
if (!(parentBlockToUse instanceof CompositeBlockWrapper)) return null;
|
||||
final List<AbstractBlockWrapper> 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<AbstractBlockWrapper> 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();
|
||||
|
||||
Reference in New Issue
Block a user