diff --git a/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java b/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java index 613f3d546616..826fb631855a 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java +++ b/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java @@ -30,6 +30,7 @@ import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import javax.swing.*; @@ -44,25 +45,25 @@ import java.util.Set; * User: cdr */ public class LeakHunter { - private static final Map> allFields = new THashMap>(); - private static List getAllFields(Class aClass) { - List cached = allFields.get(aClass); + private static final Map allFields = new THashMap(); + private static Field[] getAllFields(@NotNull Class aClass) { + Field[] cached = allFields.get(aClass); if (cached == null) { Field[] declaredFields = aClass.getDeclaredFields(); - cached =new ArrayList(declaredFields.length + 5); + List fields = new ArrayList(declaredFields.length + 5); for (Field declaredField : declaredFields) { declaredField.setAccessible(true); - cached.add(declaredField); + fields.add(declaredField); } Class superclass = aClass.getSuperclass(); if (superclass != null) { for (Field sup : getAllFields(superclass)) { - if (!cached.contains(sup)) { - cached.add(sup); + if (!fields.contains(sup)) { + fields.add(sup); } } } - ((ArrayList)cached).trimToSize(); + cached = fields.toArray(new Field[fields.size()]); allFields.put(aClass, cached); } return cached; @@ -75,7 +76,7 @@ public class LeakHunter { private final Field field; private final BackLink backLink; - private BackLink(Class aClass, Object value, Field field, BackLink backLink) { + private BackLink(@NotNull Class aClass, @NotNull Object value, Field field, BackLink backLink) { this.aClass = aClass; this.value = value; this.field = field; @@ -84,15 +85,14 @@ public class LeakHunter { } private static final Stack toVisit = new Stack(); - private static void walkObjects(Processor leakProcessor, Class lookFor) { + private static void walkObjects(@NotNull Class lookFor, @NotNull Processor leakProcessor) { while (true) { if (toVisit.isEmpty()) return; BackLink backLink = toVisit.pop(); Object root = backLink.value; if (!visited.add(root)) continue; Class rootClass = backLink.aClass; - List fields = getAllFields(rootClass); - for (Field field : fields) { + for (Field field : getAllFields(rootClass)) { String fieldName = field.getName(); if (root instanceof Reference && "referent".equals(fieldName)) continue; // do not follow weak/soft refs Object value; @@ -138,7 +138,7 @@ public class LeakHunter { } private static final Key IS_NOT_A_LEAK = Key.create("IS_NOT_A_LEAK"); - public static void markAsNotALeak(UserDataHolder object) { + public static void markAsNotALeak(@NotNull UserDataHolder object) { object.putUserData(IS_NOT_A_LEAK, Boolean.TRUE); } private static boolean isReallyLeak(Field field, String fieldName, Object value, Class valueClass) { @@ -167,7 +167,7 @@ public class LeakHunter { private static final Key REPORTED_LEAKED = Key.create("REPORTED_LEAKED"); @TestOnly - public static void checkProjectLeak(Object root) throws Exception { + public static void checkProjectLeak(@NotNull Object root) throws Exception { checkLeak(root, ProjectImpl.class); } @TestOnly @@ -175,7 +175,7 @@ public class LeakHunter { checkLeak(root, suspectClass, null); } @TestOnly - public static void checkLeak(@NotNull Object root, @NotNull Class suspectClass, final Processor isReallyLeak) throws AssertionError { + public static void checkLeak(@NotNull Object root, @NotNull Class suspectClass, @Nullable final Processor isReallyLeak) throws AssertionError { if (SwingUtilities.isEventDispatchThread()) { UIUtil.dispatchAllInvocationEvents(); } @@ -187,7 +187,7 @@ public class LeakHunter { visited.clear(); toVisit.push(new BackLink(root.getClass(), root, null,null)); try { - walkObjects(new Processor() { + walkObjects(suspectClass, new Processor() { @Override public boolean process(BackLink backLink) { UserDataHolder leaked = (UserDataHolder)backLink.value; @@ -212,7 +212,7 @@ public class LeakHunter { } return true; } - }, suspectClass); + }); } finally { visited.clear();