Prune call-graph paths using switch constraints during search.
Propagate path bindings while exploring CallEdge constraints in CallGraphPathFinder so impossible dispatch arms are skipped before chain assembly, with inheritance fallback preserved for polymorphic resolution. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -78,4 +78,40 @@ class CallGraphPathFinderTest {
|
||||
"com.acme.End.finish"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPruneBranchesDuringSearchWhenConstraintsPresent() {
|
||||
Map<String, List<CallEdge>> graph = new HashMap<>();
|
||||
graph.put("com.acme.Start.run", List.of(
|
||||
new CallEdge("com.acme.BranchA.step", List.of(), null, "command == \"PAY\""),
|
||||
new CallEdge("com.acme.BranchB.step", List.of(), null, "command == \"SHIP\"")
|
||||
));
|
||||
graph.put("com.acme.BranchA.step", List.of(
|
||||
new CallEdge("com.acme.End.finish", List.of())
|
||||
));
|
||||
graph.put("com.acme.BranchB.step", List.of(
|
||||
new CallEdge("com.acme.End.finish", List.of())
|
||||
));
|
||||
|
||||
CallGraphPathFinder pathFinder = new CallGraphPathFinder(new CodebaseContext());
|
||||
PathBindingEvaluator evaluator = new PathBindingEvaluator(
|
||||
new CodebaseContext(), null, null, null);
|
||||
|
||||
List<List<String>> unconstrained = pathFinder.findAllPaths(
|
||||
"com.acme.Start.run", "com.acme.End.finish", graph, new HashSet<>());
|
||||
assertThat(unconstrained).hasSize(2);
|
||||
|
||||
List<List<String>> payOnly = pathFinder.findAllPaths(
|
||||
"com.acme.Start.run",
|
||||
"com.acme.End.finish",
|
||||
graph,
|
||||
new HashSet<>(),
|
||||
evaluator,
|
||||
Map.of("command", "PAY"));
|
||||
assertThat(payOnly).hasSize(1);
|
||||
assertThat(payOnly.get(0)).containsExactly(
|
||||
"com.acme.Start.run",
|
||||
"com.acme.BranchA.step",
|
||||
"com.acme.End.finish");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ class PathBindingEvaluatorTest {
|
||||
Map<String, List<CallEdge>> graph = engine.buildCallGraph();
|
||||
|
||||
CallGraphPathFinder pathFinder = new CallGraphPathFinder(context);
|
||||
PathBindingEvaluator evaluator = new PathBindingEvaluator(
|
||||
context, engine.variableTracer, context.getConstantResolver(), engine.typeResolver);
|
||||
|
||||
List<List<String>> rawPaths = pathFinder.findAllPaths(
|
||||
"com.example.ApiController.pay",
|
||||
"com.example.CentralDispatcher.fire",
|
||||
@@ -72,8 +75,15 @@ class PathBindingEvaluatorTest {
|
||||
new java.util.HashSet<>());
|
||||
assertThat(rawPaths).hasSize(2);
|
||||
|
||||
PathBindingEvaluator evaluator = new PathBindingEvaluator(
|
||||
context, engine.variableTracer, context.getConstantResolver(), engine.typeResolver);
|
||||
List<List<String>> constrainedPaths = pathFinder.findAllPaths(
|
||||
"com.example.ApiController.pay",
|
||||
"com.example.CentralDispatcher.fire",
|
||||
graph,
|
||||
new java.util.HashSet<>(),
|
||||
evaluator,
|
||||
Map.of());
|
||||
assertThat(constrainedPaths).hasSize(1);
|
||||
assertThat(constrainedPaths.get(0)).contains("com.example.CentralDispatcher.orderPay");
|
||||
|
||||
List<CallEdge> dispatchEdges = graph.get("com.example.CentralDispatcher.dispatch");
|
||||
assertThat(dispatchEdges.stream().map(CallEdge::getConstraint).filter(c -> c != null && !c.isBlank()))
|
||||
|
||||
Reference in New Issue
Block a user