IDEA-65777 No alignment when pressing Enter in multiline implements list

1. Added ability to align class lbrace to the first reference of incomplete 'implements' list;
2. Corresponding test is added;
This commit is contained in:
Denis Zhdanov
2011-02-28 10:12:01 +03:00
parent 701d391f3d
commit 0cc9b49335
6 changed files with 230 additions and 78 deletions
@@ -106,7 +106,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
final CodeStyleSettings settings, final JavaWrapManager wrapManager,
@NotNull final AlignmentStrategy alignmentStrategy, AlignmentInColumnsHelper alignmentInColumnsHelper)
{
super(node, wrap, alignmentStrategy.getAlignment(node.getElementType()));
super(node, wrap, createBlockAlignment(alignmentStrategy, node));
mySettings = settings;
myIndentSettings = settings.getIndentOptions(StdFileTypes.JAVA);
myIndent = indent;
@@ -115,6 +115,16 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
myAlignmentInColumnsHelper = alignmentInColumnsHelper;
}
@Nullable
private static Alignment createBlockAlignment(@NotNull AlignmentStrategy strategy, @NotNull ASTNode node) {
// There is a possible case that 'implements' section is incomplete (e.g. ends with comma). We may want to align lbrace
// to the first implemented interface reference then.
if (node.getElementType() == JavaElementType.IMPLEMENTS_LIST) {
return null;
}
return strategy.getAlignment(node.getElementType());
}
public static Block createJavaBlock(final ASTNode child,
final CodeStyleSettings settings,
final Indent indent,
@@ -168,7 +178,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return block;
}
else if (isLikeExtendsList(elementType)) {
return new ExtendsListBlock(child, wrap, alignment, settings);
return new ExtendsListBlock(child, wrap, alignmentStrategy, settings);
}
else if (elementType == JavaElementType.CODE_BLOCK) {
return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings);
@@ -330,10 +340,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
else if (nodeType == JavaElementType.FOR_STATEMENT) {
return createAlignment(mySettings.ALIGN_MULTILINE_FOR, null);
}
else if (nodeType == JavaElementType.EXTENDS_LIST) {
return createAlignment(mySettings.ALIGN_MULTILINE_EXTENDS_LIST, null);
}
else if (nodeType == JavaElementType.IMPLEMENTS_LIST) {
else if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) {
return createAlignment(mySettings.ALIGN_MULTILINE_EXTENDS_LIST, null);
}
else if (nodeType == JavaElementType.THROWS_LIST) {
@@ -349,13 +356,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
return createAlignment(mySettings.ALIGN_MULTILINE_BINARY_OPERATION, defaultAlignment);
}
else if (nodeType == JavaElementType.CLASS) {
else if (nodeType == JavaElementType.CLASS || nodeType == JavaElementType.METHOD) {
return Alignment.createAlignment();
}
else if (nodeType == JavaElementType.METHOD) {
return Alignment.createAlignment();
}
else if (nodeType == JavaElementType.MODIFIER_LIST) {
return myAlignment;
}
@@ -514,9 +517,15 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
result.add(new SimpleJavaBlock(child, defaultWrap, alignmentStrategy, childIndent, mySettings));
}
else {
final Block block =
createJavaBlock(child, mySettings, childIndent, arrangeChildWrap(child, defaultWrap),
AlignmentStrategy.wrap(arrangeChildAlignment(child, alignmentStrategy)), childOffset);
AlignmentStrategy alignmentStrategyToUse = AlignmentStrategy.wrap(arrangeChildAlignment(child, alignmentStrategy));
if (myAlignmentStrategy != null && myAlignmentStrategy.getAlignment(nodeType, childType) != null
&& (nodeType == JavaElementType.IMPLEMENTS_LIST || nodeType == JavaElementType.CLASS))
{
alignmentStrategyToUse = myAlignmentStrategy;
}
final Block block = createJavaBlock(
child, mySettings, childIndent, arrangeChildWrap(child, defaultWrap), alignmentStrategyToUse, childOffset
);
if (childType == JavaElementType.MODIFIER_LIST && containsAnnotations(child)) {
myAnnotationWrap = Wrap.createWrap(getWrapType(getAnnotationWrapType(child)), true);
@@ -524,12 +533,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (block instanceof AbstractJavaBlock) {
final AbstractJavaBlock javaBlock = (AbstractJavaBlock)block;
if (nodeType == JavaElementType.METHOD_CALL_EXPRESSION && childType == JavaElementType.REFERENCE_EXPRESSION) {
javaBlock.setReservedWrap(getReservedWrap(nodeType), nodeType);
javaBlock.setReservedWrap(getReservedWrap(childType), childType);
}
else if (nodeType == JavaElementType.REFERENCE_EXPRESSION &&
childType == JavaElementType.METHOD_CALL_EXPRESSION) {
if ((nodeType == JavaElementType.METHOD_CALL_EXPRESSION && childType == JavaElementType.REFERENCE_EXPRESSION)
|| (nodeType == JavaElementType.REFERENCE_EXPRESSION && childType == JavaElementType.METHOD_CALL_EXPRESSION))
{
javaBlock.setReservedWrap(getReservedWrap(nodeType), nodeType);
javaBlock.setReservedWrap(getReservedWrap(childType), childType);
}
@@ -596,7 +602,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
@NotNull private static ASTNode findLastFieldInGroup(final ASTNode child) {
final PsiTypeElement typeElement = ((PsiVariable)child.getPsi()).getTypeElement();
PsiElement psi = child.getPsi();
if (psi == null) {
return child;
}
final PsiTypeElement typeElement = ((PsiVariable)psi).getTypeElement();
if (typeElement == null) return child;
ASTNode lastChildNode = child.getLastChildNode();
@@ -613,7 +623,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|| StdTokenSets.COMMENT_BIT_SET.contains(currentNode.getElementType())) {
}
else if (currentNode.getElementType() == JavaElementType.FIELD) {
if (((PsiVariable)currentNode.getPsi()).getTypeElement() != typeElement) {
if (((PsiVariable)psi).getTypeElement() != typeElement) {
return currentResult;
}
else {
@@ -786,7 +796,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
private static boolean containsAnnotations(final ASTNode child) {
return ((PsiModifierList)child.getPsi()).getAnnotations().length > 0;
PsiElement psi = child.getPsi();
if (!(psi instanceof PsiModifierList)) {
return false;
}
return ((PsiModifierList)psi).getAnnotations().length > 0;
}
private int getAnnotationWrapType(@NotNull ASTNode child) {
@@ -1094,18 +1108,15 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (psiNode instanceof PsiClass) {
return mySettings.CLASS_BRACE_STYLE;
}
else if (psiNode instanceof PsiMethod) {
return mySettings.METHOD_BRACE_STYLE;
}
else if (psiNode instanceof PsiCodeBlock && psiNode.getParent() != null && psiNode.getParent() instanceof PsiMethod) {
else if (psiNode instanceof PsiMethod
|| (psiNode instanceof PsiCodeBlock && psiNode.getParent() != null && psiNode.getParent() instanceof PsiMethod))
{
return mySettings.METHOD_BRACE_STYLE;
}
else {
return mySettings.BRACE_STYLE;
}
}
protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent) {
@@ -1269,14 +1280,16 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
child = child.getTreeNext();
AlignmentStrategy varDeclarationAlignmentStrategy
= AlignmentStrategy.createAlignmentPerTypeStrategy(VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, true);
= AlignmentStrategy.createAlignmentPerTypeStrategy(VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, JavaElementType.FIELD, true);
while (child != null) {
// We consider that subsequent fields shouldn't be aligned if they are separated by blank line(s).
if (!FormatterUtil.containsWhiteSpacesOnly(child)) {
if (!ElementType.JAVA_COMMENT_BIT_SET.contains(child.getElementType()) && !shouldUseVarDeclarationAlignment(child)) {
// Reset var declaration alignment.
varDeclarationAlignmentStrategy = AlignmentStrategy.createAlignmentPerTypeStrategy(VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, true);
varDeclarationAlignmentStrategy = AlignmentStrategy.createAlignmentPerTypeStrategy(
VAR_DECLARATION_ELEMENT_TYPES_TO_ALIGN, JavaElementType.FIELD, true
);
}
final boolean rBrace = isRBrace(child);
Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent);
@@ -17,6 +17,7 @@ package com.intellij.psi.formatter.java;
import com.intellij.formatting.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.formatter.common.AbstractBlock;
@@ -45,7 +46,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
final Alignment alignment,
final Indent indent,
final CodeStyleSettings settings) {
super(node, wrap, alignment, indent, settings);
super(node, wrap, getAlignmentStrategy(alignment, node, settings), indent, settings);
if (isSwitchCodeBlock() && !settings.INDENT_CASE_FROM_SWITCH) {
myChildrenIndent = 0;
}
@@ -54,6 +55,37 @@ public class CodeBlockBlock extends AbstractJavaBlock {
}
}
/**
* There is a possible case that 'implements' section is incomplete (e.g. ends with comma). We may want to align lbrace
* to the comma then.
*
* @param alignment block alignment
* @param baseNode base AST node
* @return alignment strategy to use for the given node
*/
private static AlignmentStrategy getAlignmentStrategy(Alignment alignment, ASTNode baseNode, @NotNull CodeStyleSettings settings) {
if (baseNode.getElementType() != JavaElementType.CLASS || !settings.ALIGN_MULTILINE_EXTENDS_LIST) {
return AlignmentStrategy.wrap(alignment);
}
for (ASTNode node = baseNode.getLastChildNode(); node != null; node = FormattingAstUtil.getPrevNonWhiteSpaceNode(node)) {
if (node.getElementType() != JavaElementType.IMPLEMENTS_LIST) {
continue;
}
ASTNode lastChildNode = node.getLastChildNode();
if (lastChildNode != null && lastChildNode.getElementType() == JavaTokenType.ERROR_ELEMENT) {
Alignment alignmentToUse = alignment;
if (alignment == null) {
alignmentToUse = Alignment.createAlignment();
}
return AlignmentStrategy.wrap(
alignmentToUse, false, JavaTokenType.LBRACE, JavaElementType.JAVA_CODE_REFERENCE, node.getElementType()
);
}
break;
}
return AlignmentStrategy.wrap(alignment);
}
private boolean isSwitchCodeBlock() {
return myNode.getTreeParent().getElementType() == ElementType.SWITCH_STATEMENT;
}
@@ -19,6 +19,7 @@ import com.intellij.formatting.Alignment;
import com.intellij.formatting.Block;
import com.intellij.formatting.Indent;
import com.intellij.formatting.Wrap;
import com.intellij.formatting.alignment.AlignmentStrategy;
import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
@@ -31,6 +32,10 @@ public class ExtendsListBlock extends AbstractJavaBlock{
public ExtendsListBlock(final ASTNode node, final Wrap wrap, final Alignment alignment, CodeStyleSettings settings) {
super(node, wrap, alignment, Indent.getNoneIndent(), settings);
}
public ExtendsListBlock(final ASTNode node, final Wrap wrap, final AlignmentStrategy alignmentStrategy, CodeStyleSettings settings) {
super(node, wrap, alignmentStrategy, Indent.getNoneIndent(), settings);
}
protected List<Block> buildChildren() {
final ArrayList<Block> result = new ArrayList<Block>();
@@ -52,8 +57,13 @@ public class ExtendsListBlock extends AbstractJavaBlock{
}
result.add(createJavaBlock(child, mySettings, myChildIndent, arrangeChildWrap(child, childWrap), alignment));
} else {
if (myAlignmentStrategy != null) {
Alignment candidate = myAlignmentStrategy.getAlignment(child.getElementType());
if (candidate != null) {
alignment = myChildAlignment = candidate;
}
}
processChild(elementsExceptKeyword, child, myChildAlignment, childWrap, myChildIndent);
}
}
child = child.getTreeNext();
@@ -67,9 +77,7 @@ public class ExtendsListBlock extends AbstractJavaBlock{
}
private boolean alignList() {
if (myNode.getElementType() == ElementType.EXTENDS_LIST) {
return mySettings.ALIGN_MULTILINE_EXTENDS_LIST;
} else if (myNode.getElementType() == ElementType.IMPLEMENTS_LIST) {
if (myNode.getElementType() == ElementType.EXTENDS_LIST || myNode.getElementType() == ElementType.IMPLEMENTS_LIST) {
return mySettings.ALIGN_MULTILINE_EXTENDS_LIST;
} else if (myNode.getElementType() == ElementType.THROWS_LIST) {
return mySettings.ALIGN_MULTILINE_THROWS_LIST;
@@ -154,7 +154,7 @@ class InitialInfoBuilder {
}
myCurrentWhiteSpace.append(blockStartOffset, myModel, myOptions);
boolean isReadOnly = isReadOnly(textRange, rootBlockIsRightBlock);
boolean isReadOnly = isReadOnly(rootBlock, rootBlockIsRightBlock);
ReadOnlyBlockInformationProvider previousProvider = myReadOnlyBlockInformationProvider;
try {
@@ -320,11 +320,49 @@ class InitialInfoBuilder {
}
}
private boolean isReadOnly(final TextRange textRange, boolean rootIsRightBlock) {
if (myAffectedRanges == null) return false;
return myAffectedRanges.isReadOnly(textRange, rootIsRightBlock);
private boolean isReadOnly(final Block block, boolean rootIsRightBlock) {
if (myAffectedRanges == null || !myAffectedRanges.isReadOnly(block.getTextRange(), rootIsRightBlock)) {
return false;
}
if (!block.isIncomplete()) {
return true;
}
// There is a possible case that particular sub-block has an alignment and we don't want to loose information about it by
// excluding that sub-block from the processing.
List<Block> blocks = block.getSubBlocks();
for (Block subBlock : blocks) {
if (hasAlignmentInTree(subBlock)) {
return false;
}
}
return true;
}
/**
* Allows to answer if given block or any of its sub-blocks has defined alignment to use.
*
* @param block root block to check
* @return <code>true</code> if given block or any of its sub-blocks has defined alignment to use;
* <code>false</code> otherwise
*/
private static boolean hasAlignmentInTree(@NotNull Block block) {
Stack<Block> blocks = new Stack<Block>();
blocks.push(block);
while (!blocks.isEmpty()) {
Block blockToProcess = blocks.pop();
if (blockToProcess.getAlignment() != null) {
return true;
}
for (Block subBlock : blockToProcess.getSubBlocks()) {
blocks.push(subBlock);
}
}
return false;
}
public Map<AbstractBlockWrapper, Block> getBlockToInfoMap() {
return myResult;
}
@@ -17,43 +17,68 @@ package com.intellij.formatting.alignment;
import com.intellij.formatting.Alignment;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static java.util.Arrays.asList;
/**
* <code>GoF 'Strategy'</code> for {@link Alignment} retrieval.
*/
public abstract class AlignmentStrategy {
/** <code>GoF 'Strategy'</code> for {@link Alignment} retrieval. */
public abstract class AlignmentStrategy {
private static final AlignmentStrategy NULL_STRATEGY = new SharedAlignmentStrategy(null);
private static final AlignmentStrategy NULL_STRATEGY = wrap(null);
/**
* @return shared strategy instance that returns <code>null</code> all the time
*/
/** @return shared strategy instance that returns <code>null</code> all the time */
public static AlignmentStrategy getNullStrategy() {
return NULL_STRATEGY;
}
/**
* Constructs strategy that returns given alignment for all elements except those which types are delivered as a trailing argument.
* Delegates the processing to {@link #wrap(Alignment, boolean, IElementType...)} with <code>'true'</code> as the second argument
*
* @param alignment target alignment to wrap
* @param typesToIgnore types of the elements for which <code>null</code> should be returned on subsequent calls
* to {@link #getAlignment(IElementType)}
* @return strategy that returns given alignment all the time for elements which types are not defined
* as <code>'types to ignore'</code>; <code>null</code> is returned for them
* @param alignment
* @param filterTypes
* @return
*/
public static AlignmentStrategy wrap(Alignment alignment, IElementType ... typesToIgnore) {
return new SharedAlignmentStrategy(alignment, typesToIgnore);
public static AlignmentStrategy wrap(Alignment alignment, IElementType... filterTypes) {
return new SharedAlignmentStrategy(alignment, true, filterTypes);
}
/**
* Constructs strategy that returns given alignment for all elements which types pass through the target filter.
*
* @param alignment target alignment to wrap
* @param ignoreFilterTypes flag that defines if given alignment should be returned for all elements with given types or
* all elements except those with the given types
* @param filterTypes element types that should be used for filtering on subsequent calls
* to {@link #getAlignment(IElementType)}
* @return strategy that returns given alignment all the time for elements which types pass through the target
* filter; <code>null</code> otherwise
*/
public static AlignmentStrategy wrap(Alignment alignment, boolean ignoreFilterTypes, IElementType... filterTypes) {
return new SharedAlignmentStrategy(alignment, ignoreFilterTypes, filterTypes);
}
/**
* Delegates to {@link #createAlignmentPerTypeStrategy(Collection, IElementType, boolean)} with no parent type
* check (<code>null</code> is delivered as a parent type).
*
* @param targetTypes target child types
* @param allowBackwardShift flag that defines if backward alignment shift is allowed
* @return alignment strategy for the given arguments
*/
public static AlignmentPerTypeStrategy createAlignmentPerTypeStrategy(@NotNull Collection<IElementType> targetTypes,
boolean allowBackwardShift)
{
return new AlignmentPerTypeStrategy(targetTypes, null, allowBackwardShift);
}
/**
* Creates strategy that creates and caches one alignment per given type internally and returns it on subsequent calls
* to {@link #getAlignment(IElementType)} for elements which type is listed at the given collection. <code>null</code>
* is returned from {@link #getAlignment(IElementType)} for elements which types are not listed at the given collection.
* to {@link #getAlignment(IElementType, IElementType)} for elements which type is listed at the given collection and parent type
* (if defined) is the same as the given one; <code>null</code> is returned from {@link #getAlignment(IElementType, IElementType)} for all
* other elements.
* <p/>
* This strategy is assumed to be used at following situations - suppose we want to align code blocks that doesn't belong
* to the same parent but have similar structure, e.g. variable declaration assignments like the one below:
@@ -64,19 +89,41 @@ public abstract class AlignmentStrategy {
* We can provide parent blocks of that target blocks with the same instance of this alignment strategy and let them eventually
* reuse the same alignment objects for target sub-blocks of the same type.
*
* @param targetTypes target types for which cached alignment should be returned
* @param allowBackwardShift flag that specifies if former aligned element may be shifted to right in order to align
* to subsequent element (e.g. <code>'='</code> block of <code>'int start = 1'</code> statement
* below is shifted one symbol right in order to align to the <code>'='</code> block
* of <code>'int finish = 1'</code> statement)
* @return alignment retrieval strategy that follows the rules described above
* @param targetTypes target types for which cached alignment should be returned
* @param parentType target parent type
* @param allowBackwardShift flag that specifies if former aligned element may be shifted to right in order to align
* to subsequent element (e.g. <code>'='</code> block of <code>'int start = 1'</code> statement
* below is shifted one symbol right in order to align to the <code>'='</code> block
* of <code>'int finish = 1'</code> statement)
* @return alignment retrieval strategy that follows the rules described above
*/
public static AlignmentPerTypeStrategy createAlignmentPerTypeStrategy(Collection<IElementType> targetTypes, boolean allowBackwardShift) {
return new AlignmentPerTypeStrategy(targetTypes, allowBackwardShift);
public static AlignmentPerTypeStrategy createAlignmentPerTypeStrategy(
@NotNull Collection<IElementType> targetTypes, @Nullable IElementType parentType, boolean allowBackwardShift)
{
return new AlignmentPerTypeStrategy(targetTypes, parentType, allowBackwardShift);
}
/**
* Delegates the processing to {@link #getAlignment(IElementType, IElementType)} without parent element type
* filtering (<code>null</code> is used as parent element type).
*
* @param childType target child type
* @return alignment to use
*/
@Nullable
public abstract Alignment getAlignment(IElementType elementType);
public Alignment getAlignment(@Nullable IElementType childType) {
return getAlignment(null, childType);
}
/**
* Requests current strategy for alignment to use for the child of the given type assuming that parent node has the given type.
*
* @param parentType parent type to use for filtering (if not <code>null</code>)
* @param childType child type to use for filtering (if not <code>null</code>)
* @return alignment to use for the given arguments
*/
@Nullable
public abstract Alignment getAlignment(@Nullable IElementType parentType, @Nullable IElementType childType);
/**
* Stands for {@link AlignmentStrategy} implementation that is configured to return single pre-configured {@link Alignment} object
@@ -84,17 +131,20 @@ public abstract class AlignmentStrategy {
*/
private static class SharedAlignmentStrategy extends AlignmentStrategy {
private final Set<IElementType> myDisableElementTypes = new HashSet<IElementType>();
private final Alignment myAlignment;
private final Set<IElementType> myFilterElementTypes = new HashSet<IElementType>();
SharedAlignmentStrategy(Alignment alignment, IElementType ... disabledElementTypes) {
private final Alignment myAlignment;
private final boolean myIgnoreFilterTypes;
private SharedAlignmentStrategy(Alignment alignment, boolean ignoreFilterTypes, IElementType... disabledElementTypes) {
myAlignment = alignment;
myDisableElementTypes.addAll(asList(disabledElementTypes));
myIgnoreFilterTypes = ignoreFilterTypes;
myFilterElementTypes.addAll(asList(disabledElementTypes));
}
@Nullable
public Alignment getAlignment(IElementType elementType) {
return myDisableElementTypes.contains(elementType) ? null : myAlignment;
public Alignment getAlignment(@Nullable IElementType parentType, @Nullable IElementType childType) {
return (myFilterElementTypes.contains(childType) ^ myIgnoreFilterTypes) ? myAlignment : null;
}
}
@@ -105,9 +155,12 @@ public abstract class AlignmentStrategy {
public static class AlignmentPerTypeStrategy extends AlignmentStrategy {
private final Map<IElementType, Alignment> myAlignments = new HashMap<IElementType, Alignment>();
private final boolean myAllowBackwardShift;
private final IElementType myParentType;
private final boolean myAllowBackwardShift;
AlignmentPerTypeStrategy(Collection<IElementType> targetElementTypes, boolean allowBackwardShift) {
AlignmentPerTypeStrategy(Collection<IElementType> targetElementTypes, IElementType parentType, boolean allowBackwardShift) {
myParentType = parentType;
myAllowBackwardShift = allowBackwardShift;
for (IElementType elementType : targetElementTypes) {
myAlignments.put(elementType, Alignment.createAlignment(myAllowBackwardShift));
@@ -115,8 +168,11 @@ public abstract class AlignmentStrategy {
}
@Override
public Alignment getAlignment(IElementType elementType) {
return myAlignments.get(elementType);
public Alignment getAlignment(@Nullable IElementType parentType, @Nullable IElementType childType) {
if (myParentType != null && parentType != null && myParentType != parentType) {
return null;
}
return myAlignments.get(childType);
}
public void renewAlignment(IElementType elementType) {
@@ -34,6 +34,7 @@ public abstract class AbstractBlock implements ASTBlock {
protected final Alignment myAlignment;
private List<Block> mySubBlocks;
private Boolean myIncomplete;
protected AbstractBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment) {
myNode = node;
@@ -79,6 +80,7 @@ public abstract class AbstractBlock implements ASTBlock {
return new ChildAttributes(getChildIndent(), getFirstChildAlignment());
}
@Nullable
private Alignment getFirstChildAlignment() {
List<Block> subBlocks = getSubBlocks();
for (final Block subBlock : subBlocks) {
@@ -96,7 +98,10 @@ public abstract class AbstractBlock implements ASTBlock {
}
public boolean isIncomplete() {
return FormatterUtil.isIncompleted(getNode());
if (myIncomplete == null) {
myIncomplete = FormatterUtil.isIncompleted(getNode());
}
return myIncomplete;
}
@Override