Avoid endless loop in formatter in case of the recursive alignment rules

This commit is contained in:
Denis.Zhdanov
2012-04-05 17:56:18 +04:00
parent feec26f8e4
commit b641a0a7ce
3 changed files with 16 additions and 13 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -85,7 +85,7 @@ public abstract class AbstractBlockAlignmentProcessor implements BlockAlignmentP
// alignment of blocks located before them and post error every time we detect endless cycle.
Set<LeafBlockWrapper> blocksCausedRealignment = context.backwardShiftedAlignedBlocks.get(offsetResponsibleBlock);
if (blocksCausedRealignment != null && blocksCausedRealignment.contains(context.targetBlock)) {
LOG.error(String.format("Please create dedicated ticket at the tracker with the content of the current editor attached!%n%n"
LOG.error(String.format("Please create dedicated ticket at the tracker with the content of the current editor attached%n%n"
+ "Formatting error - code block %s is set to be shifted right because of its alignment with "
+ "block %s more than once. I.e. moving the former block because of alignment algorithm causes "
+ "subsequent block to be shifted right as well - cyclic dependency. Debug info: %s",
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ public interface BlockAlignmentProcessor {
@NotNull public final LeafBlockWrapper targetBlock;
@NotNull public final Map<AbstractBlockWrapper, Set<AbstractBlockWrapper>> alignmentMappings;
@NotNull public final Map<LeafBlockWrapper, Set<LeafBlockWrapper>> backwardShiftedAlignedBlocks;
@NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions;
@NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions;
public Context(@NotNull Document document,
@NotNull AlignmentImpl alignment,
@@ -85,6 +85,14 @@ class FormatProcessor {
private final Map<AbstractBlockWrapper, Set<AbstractBlockWrapper>> myAlignmentMappings
= new HashMap<AbstractBlockWrapper, Set<AbstractBlockWrapper>>();
/**
* There is a possible case that we detect a 'cycled alignment' rules (see {@link #myBackwardShiftedAlignedBlocks}). We want
* just to skip processing for such alignments then.
* <p/>
* This container holds 'bad alignment' objects that should not be processed.
*/
private final Set<Alignment> myAlignmentsToSkip = new HashSet<Alignment>();
private LeafBlockWrapper myWrapCandidate = null;
private LeafBlockWrapper myFirstWrappedBlockOnLine = null;
@@ -617,7 +625,7 @@ class FormatProcessor {
AlignmentImpl alignment = CoreFormatterUtil.getAlignment(myCurrentBlock);
WhiteSpace whiteSpace = myCurrentBlock.getWhiteSpace();
if (alignment == null) {
if (alignment == null || myAlignmentsToSkip.contains(alignment)) {
if (whiteSpace.containsLineFeeds()) {
adjustSpacingByIndentOffset();
}
@@ -637,11 +645,11 @@ class FormatProcessor {
myDocument, alignment, myCurrentBlock, myAlignmentMappings, myBackwardShiftedAlignedBlocks, myIndentOption
);
BlockAlignmentProcessor.Result result = alignmentProcessor.applyAlignment(context);
final LeafBlockWrapper offsetResponsibleBlock = alignment.getOffsetRespBlockBefore(myCurrentBlock);
switch (result) {
case TARGET_BLOCK_PROCESSED_NOT_ALIGNED: return true;
case TARGET_BLOCK_ALIGNED: storeAlignmentMapping(); return true;
case BACKWARD_BLOCK_ALIGNED:
LeafBlockWrapper offsetResponsibleBlock = alignment.getOffsetRespBlockBefore(myCurrentBlock);
if (offsetResponsibleBlock == null) {
return true;
}
@@ -654,13 +662,8 @@ class FormatProcessor {
onCurrentLineChanged();
return false;
case UNABLE_TO_ALIGN_BACKWARD_BLOCK:
if (whiteSpace.containsLineFeeds()) {
adjustSpacingByIndentOffset();
}
else {
whiteSpace.arrangeSpaces(myCurrentBlock.getSpaceProperty());
}
return true;
myAlignmentsToSkip.add(alignment);
return false;
default: return true;
}
}