Skip to content

Commit 5f0e4e6

Browse files
committed
Remove short-circuiting to ensure all classes are checked for cycles (#4598)
Resolves #4597. (cherry picked from commit 8387b44)
1 parent 36bb005 commit 5f0e4e6

File tree

1 file changed

+17
-33
lines changed

1 file changed

+17
-33
lines changed

junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
import java.util.Optional;
5353
import java.util.Set;
5454
import java.util.concurrent.ConcurrentHashMap;
55+
import java.util.concurrent.atomic.AtomicBoolean;
56+
import java.util.function.Consumer;
5557
import java.util.function.Predicate;
5658
import java.util.regex.Matcher;
5759
import java.util.regex.Pattern;
@@ -1236,10 +1238,7 @@ public static List<Class<?>> findNestedClasses(Class<?> clazz, Predicate<Class<?
12361238
Preconditions.notNull(predicate, "Predicate must not be null");
12371239

12381240
Set<Class<?>> candidates = new LinkedHashSet<>();
1239-
visitNestedClasses(clazz, predicate, nestedClass -> {
1240-
candidates.add(nestedClass);
1241-
return true;
1242-
});
1241+
visitAllNestedClasses(clazz, predicate, candidates::add);
12431242
return Collections.unmodifiableList(new ArrayList<>(candidates));
12441243
}
12451244

@@ -1261,8 +1260,9 @@ public static boolean isNestedClassPresent(Class<?> clazz, Predicate<Class<?>> p
12611260
Preconditions.notNull(clazz, "Class must not be null");
12621261
Preconditions.notNull(predicate, "Predicate must not be null");
12631262

1264-
boolean visitorWasNotCalled = visitNestedClasses(clazz, predicate, __ -> false);
1265-
return !visitorWasNotCalled;
1263+
AtomicBoolean foundNestedClass = new AtomicBoolean(false);
1264+
visitAllNestedClasses(clazz, predicate, __ -> foundNestedClass.setPlain(true));
1265+
return foundNestedClass.getPlain();
12661266
}
12671267

12681268
/**
@@ -1273,10 +1273,15 @@ public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Cla
12731273
return findNestedClasses(clazz, predicate).stream();
12741274
}
12751275

1276-
private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> predicate,
1277-
Visitor<Class<?>> visitor) {
1276+
/**
1277+
* Visit <em>all</em> nested classes without support for short-circuiting
1278+
* in order to ensure all of them are checked for class cycles.
1279+
*/
1280+
private static void visitAllNestedClasses(Class<?> clazz, Predicate<Class<?>> predicate,
1281+
Consumer<Class<?>> consumer) {
1282+
12781283
if (!isSearchable(clazz)) {
1279-
return true;
1284+
return;
12801285
}
12811286

12821287
if (isInnerClass(clazz) && predicate.test(clazz)) {
@@ -1288,10 +1293,7 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
12881293
for (Class<?> nestedClass : clazz.getDeclaredClasses()) {
12891294
if (predicate.test(nestedClass)) {
12901295
detectInnerClassCycle(nestedClass);
1291-
boolean shouldContinue = visitor.accept(nestedClass);
1292-
if (!shouldContinue) {
1293-
return false;
1294-
}
1296+
consumer.accept(nestedClass);
12951297
}
12961298
}
12971299
}
@@ -1300,20 +1302,12 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
13001302
}
13011303

13021304
// Search class hierarchy
1303-
boolean shouldContinue = visitNestedClasses(clazz.getSuperclass(), predicate, visitor);
1304-
if (!shouldContinue) {
1305-
return false;
1306-
}
1305+
visitAllNestedClasses(clazz.getSuperclass(), predicate, consumer);
13071306

13081307
// Search interface hierarchy
13091308
for (Class<?> ifc : clazz.getInterfaces()) {
1310-
shouldContinue = visitNestedClasses(ifc, predicate, visitor);
1311-
if (!shouldContinue) {
1312-
return false;
1313-
}
1309+
visitAllNestedClasses(ifc, predicate, consumer);
13141310
}
1315-
1316-
return true;
13171311
}
13181312

13191313
/**
@@ -2119,14 +2113,4 @@ private static boolean getLegacySearchSemanticsFlag() {
21192113
return isTrue;
21202114
}
21212115

2122-
private interface Visitor<T> {
2123-
2124-
/**
2125-
* @return {@code true} if the visitor should continue searching;
2126-
* {@code false} if the visitor should stop
2127-
*/
2128-
boolean accept(T value);
2129-
2130-
}
2131-
21322116
}

0 commit comments

Comments
 (0)