Skip to content

Commit 8387b44

Browse files
authored
Remove short-circuiting to ensure all classes are checked for cycles (#4598)
Resolves #4597.
1 parent 3c5b457 commit 8387b44

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
@@ -49,6 +49,8 @@
4949
import java.util.Optional;
5050
import java.util.Set;
5151
import java.util.concurrent.ConcurrentHashMap;
52+
import java.util.concurrent.atomic.AtomicBoolean;
53+
import java.util.function.Consumer;
5254
import java.util.function.Predicate;
5355
import java.util.regex.Matcher;
5456
import java.util.regex.Pattern;
@@ -1119,10 +1121,7 @@ public static List<Class<?>> findNestedClasses(Class<?> clazz, Predicate<Class<?
11191121
Preconditions.notNull(predicate, "Predicate must not be null");
11201122

11211123
Set<Class<?>> candidates = new LinkedHashSet<>();
1122-
visitNestedClasses(clazz, predicate, nestedClass -> {
1123-
candidates.add(nestedClass);
1124-
return true;
1125-
});
1124+
visitAllNestedClasses(clazz, predicate, candidates::add);
11261125
return List.copyOf(candidates);
11271126
}
11281127

@@ -1144,8 +1143,9 @@ public static boolean isNestedClassPresent(Class<?> clazz, Predicate<Class<?>> p
11441143
Preconditions.notNull(clazz, "Class must not be null");
11451144
Preconditions.notNull(predicate, "Predicate must not be null");
11461145

1147-
boolean visitorWasNotCalled = visitNestedClasses(clazz, predicate, __ -> false);
1148-
return !visitorWasNotCalled;
1146+
AtomicBoolean foundNestedClass = new AtomicBoolean(false);
1147+
visitAllNestedClasses(clazz, predicate, __ -> foundNestedClass.setPlain(true));
1148+
return foundNestedClass.getPlain();
11491149
}
11501150

11511151
/**
@@ -1156,10 +1156,15 @@ public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Cla
11561156
return findNestedClasses(clazz, predicate).stream();
11571157
}
11581158

1159-
private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> predicate,
1160-
Visitor<Class<?>> visitor) {
1159+
/**
1160+
* Visit <em>all</em> nested classes without support for short-circuiting
1161+
* in order to ensure all of them are checked for class cycles.
1162+
*/
1163+
private static void visitAllNestedClasses(Class<?> clazz, Predicate<Class<?>> predicate,
1164+
Consumer<Class<?>> consumer) {
1165+
11611166
if (!isSearchable(clazz)) {
1162-
return true;
1167+
return;
11631168
}
11641169

11651170
if (isInnerClass(clazz) && predicate.test(clazz)) {
@@ -1171,10 +1176,7 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
11711176
for (Class<?> nestedClass : clazz.getDeclaredClasses()) {
11721177
if (predicate.test(nestedClass)) {
11731178
detectInnerClassCycle(nestedClass);
1174-
boolean shouldContinue = visitor.accept(nestedClass);
1175-
if (!shouldContinue) {
1176-
return false;
1177-
}
1179+
consumer.accept(nestedClass);
11781180
}
11791181
}
11801182
}
@@ -1183,20 +1185,12 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
11831185
}
11841186

11851187
// Search class hierarchy
1186-
boolean shouldContinue = visitNestedClasses(clazz.getSuperclass(), predicate, visitor);
1187-
if (!shouldContinue) {
1188-
return false;
1189-
}
1188+
visitAllNestedClasses(clazz.getSuperclass(), predicate, consumer);
11901189

11911190
// Search interface hierarchy
11921191
for (Class<?> ifc : clazz.getInterfaces()) {
1193-
shouldContinue = visitNestedClasses(ifc, predicate, visitor);
1194-
if (!shouldContinue) {
1195-
return false;
1196-
}
1192+
visitAllNestedClasses(ifc, predicate, consumer);
11971193
}
1198-
1199-
return true;
12001194
}
12011195

12021196
/**
@@ -1936,14 +1930,4 @@ static Throwable getUnderlyingCause(Throwable t) {
19361930
return t;
19371931
}
19381932

1939-
private interface Visitor<T> {
1940-
1941-
/**
1942-
* @return {@code true} if the visitor should continue searching;
1943-
* {@code false} if the visitor should stop
1944-
*/
1945-
boolean accept(T value);
1946-
1947-
}
1948-
19491933
}

0 commit comments

Comments
 (0)