Explicitly release range markers created by PostprocessReformattingAspect - fails in case of great document changes number within the same transaction

This commit is contained in:
Denis.Zhdanov
2013-07-02 14:28:51 +04:00
parent 73f2dcbf9e
commit 39b27d23b0
@@ -18,6 +18,7 @@ package com.intellij.psi.impl.source;
import com.intellij.formatting.FormatTextRanges;
import com.intellij.lang.ASTNode;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationAdapter;
import com.intellij.openapi.application.ApplicationListener;
import com.intellij.openapi.application.ApplicationManager;
@@ -46,6 +47,7 @@ import com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade;
import com.intellij.psi.impl.source.codeStyle.IndentHelperImpl;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
@@ -295,33 +297,44 @@ public class PostprocessReformattingAspect implements PomModelAspect {
final VirtualFile virtualFile = key.getVirtualFile();
if (!virtualFile.isValid()) return;
final TreeSet<PostprocessFormattingTask> postprocessTasks = new TreeSet<PostprocessFormattingTask>();
// process all roots in viewProvider to find marked for reformat before elements and create appropriate range markers
handleReformatMarkers(key, postprocessTasks);
final TreeSet<PostprocessFormattingTask> postProcessTasks = new TreeSet<PostprocessFormattingTask>();
Collection<Disposable> toDispose = ContainerUtilRt.newArrayList();
try {
// process all roots in viewProvider to find marked for reformat before elements and create appropriate range markers
handleReformatMarkers(key, postProcessTasks);
toDispose.addAll(postProcessTasks);
// then we create ranges by changed nodes. One per node. There ranges can intersect. Ranges are sorted by end offset.
if (astNodes != null) createActionsMap(astNodes, key, postprocessTasks);
// then we create ranges by changed nodes. One per node. There ranges can intersect. Ranges are sorted by end offset.
if (astNodes != null) createActionsMap(astNodes, key, postProcessTasks);
if ("true".equals(System.getProperty("check.psi.is.valid")) && ApplicationManager.getApplication().isUnitTestMode()) {
checkPsiIsCorrect(key);
if ("true".equals(System.getProperty("check.psi.is.valid")) && ApplicationManager.getApplication().isUnitTestMode()) {
checkPsiIsCorrect(key);
}
while (!postProcessTasks.isEmpty()) {
// now we have to normalize actions so that they not intersect and ordered in most appropriate way
// (free reformatting -> reindent -> formatting under reindent)
final List<PostponedAction> normalizedActions = normalizeAndReorderPostponedActions(postProcessTasks, document);
toDispose.addAll(normalizedActions);
// only in following loop real changes in document are made
for (final PostponedAction normalizedAction : normalizedActions) {
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myPsiManager.getProject());
boolean old = settings.ENABLE_JAVADOC_FORMATTING;
settings.ENABLE_JAVADOC_FORMATTING = false;
try {
normalizedAction.execute(key);
}
finally {
settings.ENABLE_JAVADOC_FORMATTING = old;
}
}
}
}
while (!postprocessTasks.isEmpty()) {
// now we have to normalize actions so that they not intersect and ordered in most appropriate way
// (free reformatting -> reindent -> formatting under reindent)
final List<PostponedAction> normalizedActions = normalizeAndReorderPostponedActions(postprocessTasks, document);
// only in following loop real changes in document are made
for (final PostponedAction normalizedAction : normalizedActions) {
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myPsiManager.getProject());
boolean old = settings.ENABLE_JAVADOC_FORMATTING;
settings.ENABLE_JAVADOC_FORMATTING = false;
try {
normalizedAction.execute(key);
}
finally {
settings.ENABLE_JAVADOC_FORMATTING = old;
}
finally {
for (Disposable disposable : toDispose) {
//noinspection SSBasedInspection
disposable.dispose();
}
}
}
@@ -599,10 +612,10 @@ public class PostprocessReformattingAspect implements PomModelAspect {
return codeFormatter;
}
private abstract static class PostprocessFormattingTask implements Comparable<PostprocessFormattingTask>, Segment {
private final RangeMarker myRange;
private abstract static class PostprocessFormattingTask implements Comparable<PostprocessFormattingTask>, Segment, Disposable {
@NotNull private final RangeMarker myRange;
public PostprocessFormattingTask(RangeMarker rangeMarker) {
public PostprocessFormattingTask(@NotNull RangeMarker rangeMarker) {
myRange = rangeMarker;
}
@@ -621,6 +634,7 @@ public class PostprocessReformattingAspect implements PomModelAspect {
return diff;
}
@NotNull
public RangeMarker getRange() {
return myRange;
}
@@ -634,6 +648,12 @@ public class PostprocessReformattingAspect implements PomModelAspect {
public int getEndOffset() {
return myRange.getEndOffset();
}
public void dispose() {
if (myRange.isValid()) {
myRange.dispose();
}
}
}
private static class ReformatTask extends PostprocessFormattingTask {
@@ -661,7 +681,7 @@ public class PostprocessReformattingAspect implements PomModelAspect {
}
}
private interface PostponedAction {
private interface PostponedAction extends Disposable {
void execute(FileViewProvider viewProvider);
}
@@ -677,6 +697,10 @@ public class PostprocessReformattingAspect implements PomModelAspect {
final CodeFormatterFacade codeFormatter = getFormatterFacade(viewProvider);
codeFormatter.processText(viewProvider.getPsi(viewProvider.getBaseLanguage()), myRanges.ensureNonEmpty(), false);
}
@Override
public void dispose() {
}
}
private static class ReindentRangesAction implements PostponedAction {
@@ -700,6 +724,16 @@ public class PostprocessReformattingAspect implements PomModelAspect {
if (indentAdjustment != 0) adjustIndentationInRange(psiFile, document, whitespaces, indentAdjustment);
}
}
@Override
public void dispose() {
for (Pair<Integer, RangeMarker> pair : myRangesToReindent) {
RangeMarker marker = pair.second;
if (marker.isValid()) {
marker.dispose();
}
}
}
}
@TestOnly