1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.util;
4 import com.intellij.openapi.Disposable;
5 import com.intellij.openapi.util.objectTree.ThrowableInterner;
6 import com.intellij.util.SmartList;
7 import org.jetbrains.annotations.NonNls;
8 import org.jetbrains.annotations.NotNull;
9 import org.jetbrains.annotations.Nullable;
10 import org.jetbrains.annotations.TestOnly;
12 import java.util.List;
14 final class ObjectNode {
15 private final ObjectTree myTree;
17 ObjectNode myParent; // guarded by myTree.treeLock
18 private final Disposable myObject;
20 private List<ObjectNode> myChildren; // guarded by myTree.treeLock
21 private Throwable myTrace;
23 ObjectNode(@NotNull ObjectTree tree,
24 @Nullable ObjectNode parentNode,
25 @NotNull Disposable object) {
27 myParent = parentNode;
30 myTrace = parentNode == null && Disposer.isDebugMode() ? ThrowableInterner.intern(new Throwable()) : null;
33 void addChild(@NotNull ObjectNode child) {
34 List<ObjectNode> children = myChildren;
35 if (children == null) {
36 myChildren = new SmartList<>(child);
41 child.myParent = this;
44 void removeChild(@NotNull ObjectNode child) {
45 List<ObjectNode> children = myChildren;
46 if (children != null) {
47 // optimisation: iterate backwards
48 for (int i = children.size() - 1; i >= 0; i--) {
49 ObjectNode node = children.get(i);
50 if (node.equals(child)) {
56 child.myParent = null;
59 ObjectNode getParent() {
60 synchronized (myTree.treeLock) {
65 void getAndRemoveRecursively(@NotNull List<? super Disposable> result) {
66 if (myChildren != null) {
67 for (int i = myChildren.size() - 1; i >= 0; i--) {
68 ObjectNode childNode = myChildren.get(i);
69 childNode.getAndRemoveRecursively(result);
72 myTree.removeObjectFromTree(this);
73 // already disposed. may happen when someone does `register(obj, ()->Disposer.dispose(t));` abomination
74 if (myTree.rememberDisposedTrace(myObject) == null) {
80 void getAndRemoveChildrenRecursively(@NotNull List<? super Disposable> result) {
81 if (myChildren != null) {
82 for (int i = myChildren.size() - 1; i >= 0; i--) {
83 ObjectNode childNode = myChildren.get(i);
84 childNode.getAndRemoveRecursively(result);
90 Disposable getObject() {
96 public String toString() {
97 return "Node: " + myObject;
100 Throwable getTrace() {
109 void assertNoReferencesKept(@NotNull Disposable aDisposable) {
110 assert getObject() != aDisposable;
111 if (myChildren != null) {
112 for (ObjectNode node: myChildren) {
113 node.assertNoReferencesKept(aDisposable);
118 <D extends Disposable> D findChildEqualTo(@NotNull D object) {
119 List<ObjectNode> children = myChildren;
120 if (children != null) {
121 for (ObjectNode node : children) {
122 Disposable nodeObject = node.getObject();
123 if (nodeObject.equals(object)) {
124 //noinspection unchecked
125 return (D)nodeObject;