mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fix a case of incorrect events generated after complicated PSI changes
This commit is contained in:
@@ -22,4 +22,6 @@ public interface PomChangeSet {
|
||||
@NotNull
|
||||
PomModelAspect getAspect();
|
||||
void merge(@NotNull PomChangeSet blocked);
|
||||
|
||||
default void beforeNestedTransaction() {}
|
||||
}
|
||||
@@ -89,4 +89,12 @@ public class PomModelEvent extends EventObject {
|
||||
public PomModel getSource() {
|
||||
return (PomModel)super.getSource();
|
||||
}
|
||||
|
||||
public void beforeNestedTransaction() {
|
||||
if (myChangeSets != null) {
|
||||
for (PomChangeSet changeSet : myChangeSets.values()) {
|
||||
changeSet.beforeNestedTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,12 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel {
|
||||
List<Throwable> throwables = new ArrayList<>(0);
|
||||
final PomModelAspect aspect = transaction.getTransactionAspect();
|
||||
startTransaction(transaction);
|
||||
|
||||
Pair<PomModelAspect,PomTransaction> block = getBlockingTransaction(aspect, transaction);
|
||||
if (block != null) {
|
||||
block.getSecond().getAccumulatedEvent().beforeNestedTransaction();
|
||||
}
|
||||
|
||||
try{
|
||||
DebugUtil.startPsiModification(null);
|
||||
Stack<Pair<PomModelAspect, PomTransaction>> blockedAspects = myBlockedAspects.get();
|
||||
@@ -167,10 +173,8 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel {
|
||||
finally{
|
||||
blockedAspects.pop();
|
||||
}
|
||||
final Pair<PomModelAspect,PomTransaction> block = getBlockingTransaction(aspect, transaction);
|
||||
if(block != null){
|
||||
final PomModelEvent currentEvent = block.getSecond().getAccumulatedEvent();
|
||||
currentEvent.merge(event);
|
||||
block.getSecond().getAccumulatedEvent().merge(event);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +152,15 @@ public class TreeChangeEventImpl implements TreeChangeEvent{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeNestedTransaction() {
|
||||
// compute changes and remember them, to prevent lazy computation to happen in another transaction
|
||||
// when more changes might have occurred but shouldn't count in this transaction
|
||||
for (TreeChangeImpl change : myChangedElements.values()) {
|
||||
change.getAffectedChildren();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ArrayList<>(myChangedElements.values()).toString();
|
||||
}
|
||||
|
||||
@@ -26,17 +26,39 @@ class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
WriteCommandAction.runWriteCommandAction(project) {
|
||||
// prepare
|
||||
val root = createEmptyFile().node
|
||||
root.replaceChild(root.firstChildNode, createComposite(compositeTypes[0], listOf(createLeaf(leafTypes[0], "d"))))
|
||||
root.replaceChild(root.firstChildNode, composite(compositeTypes[0], leaf(leafTypes[0], "d")))
|
||||
|
||||
// actual composite change
|
||||
ChangeUtil.prepareAndRunChangeAction(ChangeUtil.ChangeAction {
|
||||
root.firstChildNode.removeChild(root.firstChildNode.firstChildNode) // remove "d" leaf
|
||||
root.replaceChild(root.firstChildNode, createComposite(compositeTypes[0], listOf())) // replace now empty composite with another one
|
||||
root.replaceChild(root.firstChildNode, composite(compositeTypes[0])) // replace now empty composite with another one
|
||||
}, root as FileElement)
|
||||
assertEquals("", root.text)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test no excessive change merging between transactions if the second one has also a change higher in the tree`() {
|
||||
val file = createEmptyFile()
|
||||
WriteCommandAction.runWriteCommandAction(project) {
|
||||
//prepare
|
||||
val root = file.node as FileElement
|
||||
root.addChild(composite(compositeTypes[0], leaf(leafTypes[0], "a")), root.firstChildNode)
|
||||
|
||||
ChangeUtil.prepareAndRunChangeAction(ChangeUtil.ChangeAction {
|
||||
// change in root child
|
||||
root.firstChildNode.replaceChild(root.firstChildNode.firstChildNode, leaf(leafTypes[0], "b"))
|
||||
ChangeUtil.prepareAndRunChangeAction(ChangeUtil.ChangeAction {
|
||||
// change in root
|
||||
root.removeChild(root.lastChildNode)
|
||||
// change in the same root child as above
|
||||
root.firstChildNode.addChild(leaf(leafTypes[0], "c"), null)
|
||||
}, root)
|
||||
}, root)
|
||||
assertEquals("bc", root.text)
|
||||
assertEquals(root.text, file.viewProvider.document!!.text)
|
||||
}
|
||||
}
|
||||
|
||||
fun testPsiDocSynchronization() {
|
||||
PropertyChecker.forAll(commands).shouldHold { cmd ->
|
||||
runCommand(cmd)
|
||||
@@ -122,10 +144,10 @@ class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
private val compositeTypes = IntStreamEx.range(1, 5).mapToObj { i -> IElementType("Composite" + i, null) }.toList()
|
||||
|
||||
private val leaves = Generator.zipWith(Generator.sampledFrom(leafTypes), Generator.asciiLetters()) { type, c ->
|
||||
createLeaf(type, c.toString())
|
||||
leaf(type, c.toString())
|
||||
}
|
||||
|
||||
private fun createLeaf(type: IElementType, text: String): TreeElement {
|
||||
private fun leaf(type: IElementType, text: String): TreeElement {
|
||||
return withDummyHolder(object : LeafPsiElement(type, text) {
|
||||
override fun toString() = text
|
||||
})
|
||||
@@ -133,11 +155,11 @@ class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
|
||||
private val composites : Generator<TreeElement> = Generator.sampledFrom(compositeTypes).flatMap { type ->
|
||||
Generator.listsOf(IntDistribution.uniform(0, 5), nodes).map { children ->
|
||||
createComposite(type, children)
|
||||
composite(type, *children.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createComposite(type: IElementType, children: List<TreeElement>): TreeElement {
|
||||
private fun composite(type: IElementType, vararg children: TreeElement): TreeElement {
|
||||
val composite = withDummyHolder(object : CompositePsiElement(type) {
|
||||
override fun toString() = getChildren(null).asList().toString()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user