mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[jvm-lang] add ability to traverse super classes
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.lang.jvm.util;
|
||||
|
||||
import com.intellij.lang.jvm.JvmClass;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.intellij.lang.jvm.util.JvmUtil.resolveClass;
|
||||
import static com.intellij.lang.jvm.util.JvmUtil.resolveClasses;
|
||||
|
||||
public class JvmHierarchyUtil {
|
||||
|
||||
private JvmHierarchyUtil() {}
|
||||
|
||||
/**
|
||||
* Traverses class tree in BFS order applying the function to each superclass.
|
||||
* <p/>
|
||||
* Notes:
|
||||
* <ul>
|
||||
* <li><i>supers</i> term includes both classes and interfaces</li>
|
||||
* <li>the function will also be applied to the start class</li>
|
||||
* <li>if the function returns non-null result for any class then traversal is stopped and result is returned</li>
|
||||
* <li>the function is applied to each class at most once</li>
|
||||
* <li>unresolvable supertypes are skipped</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param start class to start traversal from
|
||||
* @param <R> type of the result
|
||||
* @return first non-null result or null
|
||||
*/
|
||||
public static <R> R traverseSupers(@NotNull JvmClass start, @NotNull Function<? super JvmClass, R> f) {
|
||||
// TODO implement method returning Stream<JvmClass>
|
||||
final Queue<JvmClass> queue = new ArrayDeque<>();
|
||||
queue.offer(start);
|
||||
|
||||
final Set<JvmClass> visited = new THashSet<>();
|
||||
while (!queue.isEmpty()) {
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
JvmClass current = queue.remove();
|
||||
if (!visited.add(current)) continue;
|
||||
|
||||
R result = f.apply(current);
|
||||
if (result != null) return result;
|
||||
|
||||
queueSupers(queue, current);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void queueSupers(@NotNull Queue<JvmClass> queue, @NotNull JvmClass current) {
|
||||
JvmClass superClass = resolveClass(current.getSuperClassType());
|
||||
if (superClass != null) {
|
||||
queue.offer(superClass);
|
||||
}
|
||||
for (JvmClass anInterface : resolveClasses(current.getInterfaceTypes())) {
|
||||
queue.offer(anInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.lang.jvm.util;
|
||||
|
||||
import com.intellij.lang.jvm.JvmClass;
|
||||
import com.intellij.lang.jvm.JvmTypeDeclaration;
|
||||
import com.intellij.lang.jvm.types.JvmReferenceType;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.util.containers.ContainerUtil.mapNotNull;
|
||||
|
||||
class JvmUtil {
|
||||
|
||||
private JvmUtil() {}
|
||||
|
||||
@NotNull
|
||||
static Iterable<JvmClass> resolveClasses(@NotNull JvmReferenceType[] types) {
|
||||
return mapNotNull(types, JvmUtil::resolveClass);
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
static JvmClass resolveClass(@Nullable JvmReferenceType type) {
|
||||
if (type == null) return null;
|
||||
JvmTypeDeclaration resolved = type.resolve();
|
||||
return resolved instanceof JvmClass ? (JvmClass)resolved : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user