heuristic code
This commit is contained in:
@@ -9,6 +9,7 @@ import java.util.*;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class CallGraphPathFinder {
|
public class CallGraphPathFinder {
|
||||||
private final CodebaseContext context;
|
private final CodebaseContext context;
|
||||||
|
private final Map<String, Boolean> heuristicCache = new HashMap<>();
|
||||||
|
|
||||||
public CallGraphPathFinder(CodebaseContext context) {
|
public CallGraphPathFinder(CodebaseContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -49,15 +50,25 @@ public class CallGraphPathFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) {
|
public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) {
|
||||||
|
return findAllPaths(start, target, graph, visited, new HashSet<>(), new boolean[]{false});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited, Set<String> unreachable, boolean[] parentHitCycle) {
|
||||||
List<List<String>> result = new ArrayList<>();
|
List<List<String>> result = new ArrayList<>();
|
||||||
|
if (unreachable.contains(start)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
if (start.equals(target)) {
|
if (start.equals(target)) {
|
||||||
result.add(new ArrayList<>(List.of(start)));
|
result.add(new ArrayList<>(List.of(start)));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (!visited.add(start)) {
|
if (!visited.add(start)) {
|
||||||
|
parentHitCycle[0] = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean[] localHitCycle = new boolean[]{false};
|
||||||
|
|
||||||
List<CallEdge> neighbors = graph.get(start);
|
List<CallEdge> neighbors = graph.get(start);
|
||||||
if (neighbors != null) {
|
if (neighbors != null) {
|
||||||
for (CallEdge edge : neighbors) {
|
for (CallEdge edge : neighbors) {
|
||||||
@@ -67,7 +78,7 @@ public class CallGraphPathFinder {
|
|||||||
List<String> path = new ArrayList<>(List.of(start, target));
|
List<String> path = new ArrayList<>(List.of(start, target));
|
||||||
result.add(path);
|
result.add(path);
|
||||||
} else {
|
} else {
|
||||||
List<List<String>> subPaths = findAllPaths(neighbor, target, graph, visited);
|
List<List<String>> subPaths = findAllPaths(neighbor, target, graph, visited, unreachable, localHitCycle);
|
||||||
for (List<String> subPath : subPaths) {
|
for (List<String> subPath : subPaths) {
|
||||||
List<String> path = new ArrayList<>();
|
List<String> path = new ArrayList<>();
|
||||||
path.add(start);
|
path.add(start);
|
||||||
@@ -91,7 +102,7 @@ public class CallGraphPathFinder {
|
|||||||
if (superclass != null) {
|
if (superclass != null) {
|
||||||
String superMethod = superclass + "." + methodName;
|
String superMethod = superclass + "." + methodName;
|
||||||
if (graph.containsKey(superMethod)) {
|
if (graph.containsKey(superMethod)) {
|
||||||
List<List<String>> superPaths = findAllPaths(superMethod, target, graph, visited);
|
List<List<String>> superPaths = findAllPaths(superMethod, target, graph, visited, unreachable, localHitCycle);
|
||||||
for (List<String> superPath : superPaths) {
|
for (List<String> superPath : superPaths) {
|
||||||
List<String> path = new ArrayList<>();
|
List<String> path = new ArrayList<>();
|
||||||
path.add(start);
|
path.add(start);
|
||||||
@@ -115,7 +126,7 @@ public class CallGraphPathFinder {
|
|||||||
for (String impl : impls) {
|
for (String impl : impls) {
|
||||||
String implMethod = impl + "." + methodName;
|
String implMethod = impl + "." + methodName;
|
||||||
if (graph.containsKey(implMethod)) {
|
if (graph.containsKey(implMethod)) {
|
||||||
List<List<String>> implPaths = findAllPaths(implMethod, target, graph, visited);
|
List<List<String>> implPaths = findAllPaths(implMethod, target, graph, visited, unreachable, localHitCycle);
|
||||||
for (List<String> implPath : implPaths) {
|
for (List<String> implPath : implPaths) {
|
||||||
List<String> path = new ArrayList<>();
|
List<String> path = new ArrayList<>();
|
||||||
path.add(start);
|
path.add(start);
|
||||||
@@ -127,6 +138,13 @@ public class CallGraphPathFinder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
visited.remove(start);
|
visited.remove(start);
|
||||||
|
|
||||||
|
if (localHitCycle[0]) {
|
||||||
|
parentHitCycle[0] = true;
|
||||||
|
} else if (result.isEmpty()) {
|
||||||
|
unreachable.add(start);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +169,18 @@ public class CallGraphPathFinder {
|
|||||||
if (neighbor == null || target == null) return false;
|
if (neighbor == null || target == null) return false;
|
||||||
if (neighbor.equals(target)) return true;
|
if (neighbor.equals(target)) return true;
|
||||||
|
|
||||||
|
String cacheKey = neighbor + "|" + target;
|
||||||
|
Boolean cached = heuristicCache.get(cacheKey);
|
||||||
|
if (cached != null) return cached;
|
||||||
|
|
||||||
|
boolean result = calculateHeuristicMatch(neighbor, target);
|
||||||
|
heuristicCache.put(cacheKey, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean calculateHeuristicMatch(String neighbor, String target) {
|
||||||
|
if (neighbor.equals(target)) return true;
|
||||||
|
|
||||||
if (isFullyQualifiedMethod(neighbor) && isFullyQualifiedMethod(target)) {
|
if (isFullyQualifiedMethod(neighbor) && isFullyQualifiedMethod(target)) {
|
||||||
int lastDotNeighbor = neighbor.lastIndexOf('.');
|
int lastDotNeighbor = neighbor.lastIndexOf('.');
|
||||||
int lastDotTarget = target.lastIndexOf('.');
|
int lastDotTarget = target.lastIndexOf('.');
|
||||||
|
|||||||
Reference in New Issue
Block a user