correct event firing when AST has no PSI (EA-111703 - IAE: PsiChangeHandler.$$$reportNull$$$)

This commit is contained in:
peter
2018-01-04 22:49:55 +01:00
parent b4b95184c2
commit fe06edef15
3 changed files with 44 additions and 7 deletions
@@ -22,6 +22,7 @@ import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.TreeElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ChangeInfoImpl implements ChangeInfo {
@@ -64,12 +65,10 @@ public class ChangeInfoImpl implements ChangeInfo {
}
void fireEvent(int parentStart, PsiFile file, CompositeElement parent) {
PsiTreeChangeEventImpl e = new PsiTreeChangeEventImpl(file.getManager());
e.setFile(file);
e.setOffset(myOffset + parentStart);
PsiTreeChangeEventImpl e = createEvent(file, myOffset + parentStart);
if (myOldChild == myNewChild && myNewChild != null) {
childrenChanged(e, myNewChild);
childrenChanged(e, myNewChild, myOldLength);
}
else if (myOldChild != null && myNewChild != null) {
childReplaced(e, myOldChild, myNewChild, parent);
@@ -82,6 +81,19 @@ public class ChangeInfoImpl implements ChangeInfo {
}
}
@NotNull
static PsiTreeChangeEventImpl createEvent(PsiFile file, int offset) {
PsiTreeChangeEventImpl e = new PsiTreeChangeEventImpl(file.getManager());
e.setFile(file);
e.setOffset(offset);
return e;
}
boolean hasNoPsi() {
return myOldChild != null && myOldChild.getPsi() == null ||
myNewChild != null && myNewChild.getPsi() == null;
}
private static void childAdded(PsiTreeChangeEventImpl e, TreeElement child, CompositeElement parent) {
e.setParent(parent.getPsi());
e.setChild(child.getPsi());
@@ -104,9 +116,9 @@ public class ChangeInfoImpl implements ChangeInfo {
getPsiManagerImpl(e).childReplaced(e);
}
private void childrenChanged(PsiTreeChangeEventImpl e, TreeElement parent) {
static void childrenChanged(PsiTreeChangeEventImpl e, TreeElement parent, int oldLength) {
e.setParent(parent.getPsi());
e.setOldLength(myOldLength);
e.setOldLength(oldLength);
getPsiManagerImpl(e).childrenChanged(e);
}
@@ -39,6 +39,7 @@ public class TreeChangeImpl implements TreeChange, Comparable<TreeChangeImpl> {
public TreeChangeImpl(@NotNull CompositeElement parent) {
myParent = parent;
assert myParent.getPsi() != null;
mySuperParents = JBIterable.generate(parent.getTreeParent(), TreeElement::getTreeParent).toList();
for (TreeElement child : getCurrentChildren()) {
myInitialChildren.add(child);
@@ -152,7 +153,13 @@ public class TreeChangeImpl implements TreeChange, Comparable<TreeChangeImpl> {
void fireEvents(PsiFile file) {
int start = myParent.getStartOffset();
for (ChangeInfoImpl change : getAllChanges().values()) {
Collection<ChangeInfoImpl> changes = getAllChanges().values();
if (ContainerUtil.exists(changes, c -> c.hasNoPsi())) {
ChangeInfoImpl.childrenChanged(ChangeInfoImpl.createEvent(file, start), myParent, myParent.getTextLength() - getLengthDelta());
return;
}
for (ChangeInfoImpl change : changes) {
change.fireEvent(start, file, myParent);
}
}
@@ -125,6 +125,17 @@ class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() {
assertEquals(root.text, file.viewProvider.document!!.text)
}
}
fun `test changes on AST without PSI`() {
val file = createEmptyFile()
WriteCommandAction.runWriteCommandAction(project) {
val root = file.node as FileElement
root.replaceChild(root.firstChildNode, leaf(leafTypes[0], "A"))
assertEquals("A", root.text)
assertEquals(root.text, file.viewProvider.document!!.text)
}
}
fun testPsiDocSynchronization() {
ImperativeCommand.checkScenarios { RandomAstChanges() }
@@ -198,6 +209,13 @@ class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() {
}
private fun leaf(type: IElementType, text: String): TreeElement {
if (text[0].isUpperCase()) {
// no PSI
return withDummyHolder(object : LeafElement(type, text) {
override fun toString() = text
})
}
return withDummyHolder(object : LeafPsiElement(type, text) {
override fun toString() = text
})