From 20453a1c42ddbb63933c99bb2e489e18280b1ac7 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 6 Dec 2018 17:23:06 +0300 Subject: [PATCH] avoid double dispose in case of `Disposer.register(d, ()->Disposer.dispose(t))` abomination --- .../intellij/openapi/util/objectTree/ObjectNode.java | 3 ++- .../intellij/openapi/util/objectTree/DisposerTest.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java index bd3843b2f926..af7660bd80f4 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java @@ -107,6 +107,7 @@ final class ObjectNode { ObjectTree.executeActionWithRecursiveGuard(this, myTree.getNodesInExecution(), new ObjectTreeAction>() { @Override public void execute(@NotNull ObjectNode each) { + if (myTree.getDisposalInfo(myObject) != null) return; // already disposed. may happen when someone does `register(obj, ()->Disposer.dispose(t));` abomination try { action.beforeTreeExecution(myObject); } @@ -167,7 +168,7 @@ final class ObjectNode { } } - private void removeFromObjectTree() { + void removeFromObjectTree() { synchronized (myTree.treeLock) { myTree.putNode(myObject, null); if (myParent == null) { diff --git a/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java b/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java index 129c0112d64e..caf35b02d32c 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java @@ -94,6 +94,16 @@ public class DisposerTest extends TestCase { assertEquals(Arrays.asList(myFolder2, myLeaf1, myFolder1, myRoot), myDisposedObjects); } + public void testDisposalOrderNestedDispose() { + Disposer.register(myRoot, myFolder2); + //noinspection SSBasedInspection + Disposer.register(myRoot, () -> Disposer.dispose(myFolder2)); + + Disposer.dispose(myRoot); + + assertEquals(Arrays.asList(myFolder2, myRoot), myDisposedObjects); + } + public void testDirectCallOfDisposable() { SelDisposable selfDisposable = new SelDisposable("selfDisposable"); Disposer.register(myRoot, selfDisposable);