EA-54811 - avoid InjectedCodeFoldingPass seeing outdated PSI for injected fragments

This commit is contained in:
Dmitry Batrak
2014-06-19 11:54:59 +04:00
parent 631e97a85c
commit b21e515794
6 changed files with 54 additions and 44 deletions
@@ -15,11 +15,8 @@
*/
package com.intellij.openapi.editor.impl;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.daemon.impl.CodeFoldingPassFactory;
import com.intellij.mock.MockProgressIndicator;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.EditorTestUtil;
import com.intellij.testFramework.LightCodeInsightTestCase;
@@ -43,14 +40,7 @@ public class FoldingExceptionTest extends LightCodeInsightTestCase {
}
private static void runFoldingPass() {
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(getProject());
psiDocumentManager.commitAllDocuments();
PsiFile psiFile = psiDocumentManager.getPsiFile(myEditor.getDocument());
assertNotNull(psiFile);
CodeFoldingPassFactory factory = getProject().getComponent(CodeFoldingPassFactory.class);
TextEditorHighlightingPass highlightingPass = factory.createHighlightingPass(psiFile, myEditor);
highlightingPass.collectInformation(new MockProgressIndicator());
highlightingPass.doApplyInformationToEditor();
PsiDocumentManager.getInstance(ourProject).commitAllDocuments();
EditorTestUtil.runTextEditorHighlightingPass(myEditor, CodeFoldingPassFactory.class);
}
}
@@ -159,17 +159,24 @@ public class FoldingUpdate {
final List<EditorWindow> injectedEditors = new ArrayList<EditorWindow>();
final List<PsiFile> injectedFiles = new ArrayList<PsiFile>();
final List<FoldingMap> maps = new ArrayList<FoldingMap>();
for (DocumentWindow injectedDocument : injectedDocuments) {
PsiFile injectedFile = PsiDocumentManager.getInstance(project).getPsiFile(injectedDocument);
if (injectedFile == null || !injectedFile.isValid() || !injectedDocument.isValid()) continue;
Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
if (!(injectedEditor instanceof EditorWindow)) continue;
for (final DocumentWindow injectedDocument : injectedDocuments) {
if (!injectedDocument.isValid()) {
continue;
}
InjectedLanguageUtil.enumerate(injectedDocument, file, new PsiLanguageInjectionHost.InjectedPsiVisitor() {
@Override
public void visit(@NotNull PsiFile injectedFile, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
if (!injectedFile.isValid()) return;
Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
if (!(injectedEditor instanceof EditorWindow)) return;
injectedEditors.add((EditorWindow)injectedEditor);
injectedFiles.add(injectedFile);
final FoldingMap map = new FoldingMap();
maps.add(map);
getFoldingsFor(injectedFile, injectedDocument, map, false);
injectedEditors.add((EditorWindow)injectedEditor);
injectedFiles.add(injectedFile);
final FoldingMap map = new FoldingMap();
maps.add(map);
getFoldingsFor(injectedFile, injectedDocument, map, false);
}
});
}
return new Runnable() {
@@ -43,7 +43,6 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -141,18 +140,9 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
if (indicator != null && indicator.isCanceled()) return false;
if (documentManager.isUncommited(hostDocument) || !hostPsiFile.isValid()) return false; // will be committed later
Segment[] ranges = documentWindow.getHostRanges();
Segment rangeMarker = ranges.length > 0 ? ranges[0] : null;
PsiElement element = rangeMarker == null ? null : hostPsiFile.findElementAt(rangeMarker.getStartOffset());
if (element == null) {
synchronized (PsiLock.LOCK) {
injected.remove(documentWindow);
}
return true;
}
final DocumentWindow[] stillInjectedDocument = {null};
// it is here where the reparse happens and old file contents replaced
InjectedLanguageUtil.enumerate(element, hostPsiFile, true, new PsiLanguageInjectionHost.InjectedPsiVisitor() {
InjectedLanguageUtil.enumerate(documentWindow, hostPsiFile, new PsiLanguageInjectionHost.InjectedPsiVisitor() {
@Override
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
stillInjectedDocument[0] = (DocumentWindow)injectedPsi.getViewProvider().getDocument();
@@ -92,6 +92,17 @@ public class InjectedLanguageUtil {
return ((DocumentWindowImpl)myFileViewProvider.getDocument()).getShreds();
}
public static void enumerate(@NotNull DocumentWindow documentWindow,
@NotNull PsiFile hostPsiFile,
@NotNull PsiLanguageInjectionHost.InjectedPsiVisitor visitor) {
Segment[] ranges = documentWindow.getHostRanges();
Segment rangeMarker = ranges.length > 0 ? ranges[0] : null;
PsiElement element = rangeMarker == null ? null : hostPsiFile.findElementAt(rangeMarker.getStartOffset());
if (element != null) {
enumerate(element, hostPsiFile, true, visitor);
}
}
public static boolean enumerate(@NotNull PsiElement host, @NotNull PsiLanguageInjectionHost.InjectedPsiVisitor visitor) {
PsiFile containingFile = host.getContainingFile();
return enumerate(host, containingFile, true, visitor);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -15,10 +15,8 @@
*/
package com.intellij.psi.formatter;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.daemon.impl.CodeFoldingPassFactory;
import com.intellij.lang.Language;
import com.intellij.mock.MockProgressIndicator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.CommandProcessor;
@@ -42,6 +40,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.testFramework.EditorTestUtil;
import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.LocalTimeCounter;
@@ -199,7 +198,7 @@ public abstract class FormatterTestCase extends LightPlatformTestCase {
assertEquals(file.getText(), document.getText());
if (false && doCheckDocumentUpdate()) {
makeFolding(file, editor);
EditorTestUtil.runTextEditorHighlightingPass(editor, CodeFoldingPassFactory.class);
}
try {
if (doReformatRangeTest) {
@@ -225,13 +224,6 @@ public abstract class FormatterTestCase extends LightPlatformTestCase {
assertEquals(textAfter, file.getText());
}
protected static void makeFolding(final PsiFile file, final EditorImpl editor) {
final CodeFoldingPassFactory factory = getProject().getComponent(CodeFoldingPassFactory.class);
final TextEditorHighlightingPass highlightingPass = factory.createHighlightingPass(file, editor);
highlightingPass.collectInformation(new MockProgressIndicator());
highlightingPass.doApplyInformationToEditor();
}
@SuppressWarnings({"UNUSED_SYMBOL"})
private void checkPsi(final PsiFile file, String textAfter) {
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@@ -15,7 +15,10 @@
*/
package com.intellij.testFramework;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory;
import com.intellij.ide.DataManager;
import com.intellij.mock.MockProgressIndicator;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
@@ -32,10 +35,13 @@ import com.intellij.openapi.editor.impl.SoftWrapModelImpl;
import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType;
import com.intellij.openapi.editor.impl.softwrap.SoftWrapPainter;
import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapApplianceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -432,6 +438,20 @@ public class EditorTestUtil {
return ref.get();
}
public static <T extends TextEditorHighlightingPassFactory> void runTextEditorHighlightingPass(@NotNull Editor editor, @NotNull Class<T> passFactory) {
Project project = editor.getProject();
assertNotNull(project);
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
PsiFile psiFile = psiDocumentManager.getPsiFile(editor.getDocument());
assertNotNull(psiFile);
T factory = project.getComponent(passFactory);
TextEditorHighlightingPass pass = factory.createHighlightingPass(psiFile, editor);
assertNotNull(pass);
pass.collectInformation(new MockProgressIndicator());
pass.applyInformationToEditor();
}
public static class CaretAndSelectionState {
public final List<CaretInfo> carets = new ArrayList<CaretInfo>();
@Nullable