From b641a0a7ce8f16a5aafece4a2fd0a466c5172244 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Thu, 5 Apr 2012 17:55:41 +0400 Subject: [PATCH] Avoid endless loop in formatter in case of the recursive alignment rules --- .../AbstractBlockAlignmentProcessor.java | 4 ++-- .../formatting/BlockAlignmentProcessor.java | 4 ++-- .../intellij/formatting/FormatProcessor.java | 21 +++++++++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java index 256a370879af..945a8c453d3f 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockAlignmentProcessor.java @@ -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 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", diff --git a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java index a7dbd6448cf7..c00bdd6da16c 100644 --- a/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/BlockAlignmentProcessor.java @@ -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> alignmentMappings; @NotNull public final Map> backwardShiftedAlignedBlocks; - @NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions; + @NotNull public final CommonCodeStyleSettings.IndentOptions indentOptions; public Context(@NotNull Document document, @NotNull AlignmentImpl alignment, diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index c14dbeff1743..ae8a514bd9ee 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -85,6 +85,14 @@ class FormatProcessor { private final Map> myAlignmentMappings = new HashMap>(); + /** + * 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. + *

+ * This container holds 'bad alignment' objects that should not be processed. + */ + private final Set myAlignmentsToSkip = new HashSet(); + 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; } }