diff --git a/java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java b/java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java
new file mode 100644
index 000000000000..214d2bcfef47
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java
@@ -0,0 +1,229 @@
+package com.intellij.psi;
+
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileTypes.MockLanguageFileType;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.psi.impl.source.PsiExpressionCodeFragmentImpl;
+import com.intellij.psi.impl.source.SourceTreeToPsiMap;
+import com.intellij.psi.text.BlockSupport;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.psi.xml.XmlText;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.util.IncorrectOperationException;
+import org.intellij.lang.annotations.Language;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JavaReparseTest extends AbstractReparseTestCase {
+
+ public void testInsertLBrace() throws Exception {
+ setFileType(StdFileTypes.JAVA);
+ final String text2 = "}}}";
+ final String text1 = "class Foo{ void method(){{";
+ prepareFile(text1, text2);
+ insert("{");
+ }
+
+ public void testJavaDoc() throws Exception {
+ setFileType(StdFileTypes.JAVA);
+ String text2 = "void method() {}}";
+ final String text1 = "class Foo { /** ";
+ prepareFile(text1, text2);
+ insert("*/");
+ }
+
+ public void testSCR5665() throws Exception {
+ setFileType(StdFileTypes.JAVA);
+ final String text2 = " \"and then insert it again\"}\n" +
+ " };\n" +
+ "}";
+ final String text1 = "class RedTest {\n" +
+ " String[][] test = {\n" +
+ " {\"remove the comma >\",";
+ prepareFile(text1, text2);
+ remove(1);
+ insert(",");
+ PsiFile file1 = myDummyFile;
+ prepareFile(text1, text2);
+ assertEquals(DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(file1), false),
+ DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(myDummyFile), false));
+ }
+
+
+ @NotNull
+ @Override
+ protected PsiFile createDummyFile(@NotNull String fileName, @NotNull String text) throws IncorrectOperationException {
+ if (getTestName(true).equals("codeFragment")) return new PsiExpressionCodeFragmentImpl(getProject(), true, "fragment.java", text, null,
+ null);
+ return super.createDummyFile(fileName, text);
+ }
+
+ public void testCodeFragment() throws Exception {
+ setFileType(StdFileTypes.JAVA);
+ prepareFile("a", "a");
+ insert("xxx xxx xxx xxx xxx xxx xxx");
+ }
+
+ public void testReparseAfterReformatReplacesWhitespaceNodesOnly() throws Exception {
+ @NonNls final String text =
+ "class RedTest { \n\n\n\n\n\n\n\n " +
+ "String [ ] [ ] test = { { \n\n\n\n\n { \"\"} \n\n\n\n\n }; " +
+ "String [ ] [ ] test = { { \n\n\n\n\n { \"\"} \n\n\n\n\n }; " +
+ " \n\n\n\n\n\n\n\n } ";
+
+ final PsiFile file = myFixture.addFileToProject("aaa.java", text);
+ final int[] added = {0};
+ final int[] removed = {0};
+ final int[] replacedWhite = {0};
+ final int[] replacedNWhite = {0};
+ final int[] moved = {0};
+
+ file.getManager().addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
+ @Override
+ public void childAdded(@NotNull PsiTreeChangeEvent event) {
+ PsiElement oldElement = event.getChild();
+ if (oldElement instanceof PsiWhiteSpace) replacedWhite[0]++; else added[0]++;
+ }
+
+ @Override
+ public void childRemoved(@NotNull PsiTreeChangeEvent event) {
+ PsiElement oldElement = event.getOldChild();
+ if (oldElement instanceof PsiWhiteSpace) replacedWhite[0]++; else removed[0]++;
+ }
+
+ @Override
+ public void childReplaced(@NotNull PsiTreeChangeEvent event) {
+ PsiElement oldElement = event.getOldChild();
+ PsiElement newElement = event.getNewChild();
+
+ if (oldElement instanceof PsiWhiteSpace) {
+ replacedWhite[0]++;
+ }
+ else {
+ replacedNWhite[0]++;
+ }
+ if (newElement instanceof PsiWhiteSpace) {
+ replacedWhite[0]++;
+ }
+ else {
+ replacedNWhite[0]++;
+ }
+ }
+
+ @Override
+ public void childMoved(@NotNull PsiTreeChangeEvent event) {
+ moved[0]++;
+ }
+ }, getProject());
+
+ WriteCommandAction.runWriteCommandAction(getProject(), () -> {
+ CodeStyleManager.getInstance(getProject()).reformatText(file, 0, file.getTextLength());
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ });
+
+ assertEquals(0, added[0]);
+ assertEquals(0, removed[0]);
+ assertEquals(0, moved[0]);
+ assertEquals(0, replacedNWhite[0]);
+ assertTrue(0 != replacedWhite[0]);
+ }
+
+ public void testInsertXMLSubTagProducesAddEvents() throws Exception {
+ @NonNls @Language("XML")
+ final String text = "\n" +
+ " \n" +
+ " TODO\n" +
+ " \n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "";
+
+ final PsiFile file = myFixture.addFileToProject("aaa.xml", text);
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+
+ final List added = new ArrayList<>();
+ final List removed = new ArrayList<>();
+ final List replaced = new ArrayList<>();
+ final List moved = new ArrayList<>();
+ file.getManager().addPsiTreeChangeListener(new PsiTreeChangeAdapter(){
+ @Override
+ public void childAdded(@NotNull PsiTreeChangeEvent event) {
+ added.add(event.getChild());
+ }
+
+ @Override
+ public void childRemoved(@NotNull PsiTreeChangeEvent event) {
+ removed.add(event.getElement());
+ }
+
+ @Override
+ public void childReplaced(@NotNull PsiTreeChangeEvent event) {
+ replaced.add(event.getOldChild());
+ }
+
+ @Override
+ public void childMoved(@NotNull PsiTreeChangeEvent event) {
+ moved.add(event.getElement());
+ }
+ }, getTestRootDisposable());
+
+ WriteCommandAction.runWriteCommandAction(getProject(), () -> {
+ Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file);
+ int offset = document.getText().indexOf("\n\n") + "\n\n".length();
+ document.insertString(offset, "");
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ });
+
+ assertEquals(2, added.size());
+ assertTrue(added.get(0) instanceof XmlTag);
+ assertEquals("", added.get(0).getText());
+ assertTrue(added.get(1) instanceof XmlText);
+ assertEquals("\n", added.get(1).getText());
+ assertEmpty(removed);
+ assertEmpty(moved);
+ assertEmpty(replaced);
+ }
+
+ public void testPlainTextSubstitution() {
+ LightVirtualFile vFile = new LightVirtualFile("a.xxx", MockLanguageFileType.INSTANCE, "aaa");
+ PsiFile file = myDummyFile = PsiManager.getInstance(getProject()).findFile(vFile);
+ assertNotNull(file);
+
+ assertEquals(com.intellij.lang.Language.ANY, file.getViewProvider().getBaseLanguage());
+ assertEquals(PlainTextLanguage.INSTANCE, file.getLanguage());
+ assertEquals(file, file.getViewProvider().getPsi(file.getViewProvider().getBaseLanguage()));
+
+ doReparse("b", 0);
+ assertTrue("baaa", file.isValid());
+ assertEquals("baaa", file.getText());
+ assertEquals("baaa", file.getFirstChild().getText());
+ }
+
+ public void testOverlappingCommonPrefixAndSuffix() {
+ setFileType(StdFileTypes.JAVA);
+ String toRemove = "} {foobar";
+ prepareFile("class Foo { {goo} {foobar" + toRemove, " foobar} }");
+ remove(toRemove.length());
+ }
+
+ public void testDocComment() {
+ String text = "/** .../ */";
+ final int offset = text.indexOf("...");
+ myDummyFile = createDummyFile(getName() + ".java", text);
+ String treeBefore = DebugUtil.psiTreeToString(myDummyFile, true);
+ WriteCommandAction.runWriteCommandAction(getProject(), () -> {
+ BlockSupport.getInstance(getProject()).reparseRange(myDummyFile, offset, offset + 3, "*");
+ BlockSupport.getInstance(getProject()).reparseRange(myDummyFile, offset, offset + 1, "...");
+ });
+ String treeAfter = DebugUtil.psiTreeToString(myDummyFile, true);
+ assertEquals(treeBefore, treeAfter);
+ }
+}
diff --git a/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java b/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java
index 50242f214809..66568bc4d2bb 100644
--- a/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java
+++ b/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java
@@ -4,17 +4,18 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.psi.impl.DebugUtil;
-import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.text.BlockSupport;
-import com.intellij.testFramework.PsiTestCase;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
/**
* @author maxim
*/
-public abstract class AbstractReparseTestCase extends PsiTestCase {
+public abstract class AbstractReparseTestCase extends LightCodeInsightFixtureTestCase {
protected FileType myFileType;
protected PsiFile myDummyFile;
private int myInsertOffset;
@@ -35,20 +36,11 @@ public abstract class AbstractReparseTestCase extends PsiTestCase {
String oldText = myDummyFile.getText();
String expectedNewText = oldText.substring(0, myInsertOffset) + s + oldText.substring(myInsertOffset);
- try {
- doReparseAndCheck(s, expectedNewText, 0);
- }
- catch (IncorrectOperationException e) {
- LOG.error(e);
- }
+ doReparseAndCheck(s, expectedNewText, 0);
myInsertOffset += s.length();
}), "asd", null);
}
- protected void moveEditPointLeft(int count) {
- myInsertOffset -= count;
- }
-
protected void moveEditPointRight(int count) {
myInsertOffset += count;
}
@@ -67,29 +59,24 @@ public abstract class AbstractReparseTestCase extends PsiTestCase {
private void doReparseAndCheck(final String s, final String expectedNewText, final int length) throws IncorrectOperationException {
doReparse(s, length);
- String foundStructure = DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(myDummyFile), false);
+ String foundStructure = DebugUtil.treeToString(myDummyFile.getNode(), false);
final PsiFile psiFile = createDummyFile(getName() + "." + myFileType.getDefaultExtension(), expectedNewText);
- String expectedStructure = DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(psiFile), false);
- if (!expectedStructure.equals(foundStructure)) {
- System.out.println("expected: ");
- System.out.println(expectedStructure);
- System.out.println("found: ");
- System.out.println(foundStructure);
- assertEquals(expectedStructure, foundStructure);
- }
+ String expectedStructure = DebugUtil.treeToString(psiFile.getNode(), false);
+ assertEquals(expectedStructure, foundStructure);
assertEquals("Reparse tree should be equal to the document", expectedNewText, myDummyFile.getText());
}
+ @NotNull
+ protected PsiFile createDummyFile(@NotNull String fileName, @NotNull String text) throws IncorrectOperationException {
+ FileType type = FileTypeRegistry.getInstance().getFileTypeByFileName(fileName);
+ return PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, type, text);
+ }
+
protected void doReparse(final String s, final int length) {
CommandProcessor.getInstance().executeCommand(getProject(), () -> ApplicationManager.getApplication().runWriteAction(() -> {
- BlockSupport blockSupport = ServiceManager.getService(myProject, BlockSupport.class);
- try {
- blockSupport.reparseRange(myDummyFile, myInsertOffset - length, myInsertOffset, s);
- }
- catch (IncorrectOperationException e) {
- LOG.error(e);
- }
+ BlockSupport blockSupport = ServiceManager.getService(getProject(), BlockSupport.class);
+ blockSupport.reparseRange(myDummyFile, myInsertOffset - length, myInsertOffset, s);
}), "asd", null);
}
diff --git a/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java b/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java
index dbde3480e435..3a149247c6d4 100644
--- a/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java
+++ b/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java
@@ -16,7 +16,7 @@
package com.intellij.codeInsight;
-import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.psi.AbstractReparseTestCase;
@@ -27,13 +27,11 @@ import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.source.xml.XmlFileImpl;
import com.intellij.psi.xml.XmlFile;
import com.intellij.testFramework.ParsingTestCase;
-import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.IncorrectOperationException;
import java.io.File;
-@PlatformTestCase.WrapInCommand
public class XmlReparseTest extends AbstractReparseTestCase {
@Override
protected void setUp() throws Exception {
@@ -144,7 +142,7 @@ public class XmlReparseTest extends AbstractReparseTestCase {
}
private static final String marker = "";
public void testXmlDeclDtd() throws Exception {
- PsiFile file = createFile("x.xml", "\n" +
" \n" +
"]>\n" +
@@ -160,10 +158,10 @@ public class XmlReparseTest extends AbstractReparseTestCase {
ParsingTestCase.doCheckResult(myFullDataPath, file, true, "testXmlDeclDtd", false, false);
}
- private static void removeGarbage(Document document) {
+ private void removeGarbage(Document document) {
int i = document.getText().indexOf(marker);
if (i==-1) return;
- ApplicationManager.getApplication().runWriteAction(() -> document.replaceString(i, i + marker.length(), ""));
+ WriteCommandAction.runWriteCommandAction(getProject(), () -> document.replaceString(i, i + marker.length(), ""));
removeGarbage(document);
}
@@ -172,4 +170,16 @@ public class XmlReparseTest extends AbstractReparseTestCase {
protected String getTestDataPath() {
return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/xml/tests/testData/";
}
+
+ public void testXml() throws Exception{
+ setFileType(StdFileTypes.XML);
+ String text2 = "";
+ final String text1 = "/n";
+ prepareFile(text1, text2);
+ insert("<");
+ PsiElement element = myDummyFile.findElementAt(10);
+ assert element != null;
+ assertNotNull(element.getTextRange());
+ }
+
}