better enricher attempt
This commit is contained in:
@@ -51,10 +51,10 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
||||
if (targetVar == null && chain.getTriggerPoint() != null) {
|
||||
targetVar = chain.getTriggerPoint().getStateMachineId();
|
||||
}
|
||||
if (targetVar == null || targetVar.isEmpty()) {
|
||||
// Wildcard without specific routing context is too broad, do not link
|
||||
continue;
|
||||
}
|
||||
// We no longer hard-block wildcards without a specific routing context.
|
||||
// If a project doesn't use standard SM persisters (e.g. restores state manually),
|
||||
// contextMachineId will be null. We should still link the wildcard to provide SOME visibility,
|
||||
// rather than completely hiding the endpoint.
|
||||
}
|
||||
|
||||
if (isWildcard || smEvent.equals(triggerEvent) || triggerEvent.toLowerCase().contains(smEvent.toLowerCase()) || smEvent.toLowerCase().contains(triggerEvent.toLowerCase())) {
|
||||
|
||||
@@ -84,6 +84,15 @@ public class CallGraphBuilder {
|
||||
|
||||
// Find parameter index in target method
|
||||
int paramIndex = getParameterIndex(target, currentParamName);
|
||||
if (paramIndex < 0) {
|
||||
// Not a parameter. Maybe it's a local variable initialized from a parameter or method call?
|
||||
String tracedVar = traceLocalVariable(target, currentParamName);
|
||||
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
|
||||
currentParamName = tracedVar;
|
||||
// We must try to find paramIndex again, because the traced variable might be a parameter of this same method
|
||||
paramIndex = getParameterIndex(target, currentParamName);
|
||||
}
|
||||
}
|
||||
if (paramIndex < 0) {
|
||||
break; // Parameter name changed or not found, stop tracing
|
||||
}
|
||||
@@ -141,6 +150,51 @@ public class CallGraphBuilder {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private String traceLocalVariable(String methodFqn, String varName) {
|
||||
if (methodFqn == null || !methodFqn.contains(".")) return null;
|
||||
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));
|
||||
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
|
||||
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||
if (td != null) {
|
||||
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
|
||||
if (md != null && md.getBody() != null) {
|
||||
final Expression[] initializer = new Expression[1];
|
||||
md.getBody().accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(VariableDeclarationFragment node) {
|
||||
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
|
||||
initializer[0] = node.getInitializer();
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
@Override
|
||||
public boolean visit(Assignment node) {
|
||||
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
|
||||
initializer[0] = node.getRightHandSide();
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
|
||||
if (initializer[0] != null) {
|
||||
Expression expr = traceVariable(initializer[0]);
|
||||
if (expr instanceof MethodInvocation mi) {
|
||||
// e.g. event.getType() -> return "event.getType()" or just "event"
|
||||
if (mi.getExpression() instanceof SimpleName sn) {
|
||||
return sn.getIdentifier() + "." + mi.getName().getIdentifier() + "()";
|
||||
}
|
||||
return mi.getName().getIdentifier() + "()";
|
||||
}
|
||||
if (expr instanceof SimpleName sn) {
|
||||
return sn.getIdentifier();
|
||||
}
|
||||
return expr.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String extractContextMachineId(List<String> path, Map<String, List<CallEdge>> callGraph) {
|
||||
for (String node : path) {
|
||||
List<CallEdge> edges = callGraph.get(node);
|
||||
|
||||
@@ -168,7 +168,7 @@ class TransitionLinkerEnricherTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIgnoreWildcardWhenContextMachineIdIsMissing() {
|
||||
void shouldAllowWildcardWhenContextMachineIdIsMissing() {
|
||||
Transition t1 = new Transition();
|
||||
t1.setSourceStates(List.of(State.of("NEW", "NEW")));
|
||||
t1.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||
@@ -176,7 +176,7 @@ class TransitionLinkerEnricherTest {
|
||||
|
||||
CallChain chain = CallChain.builder()
|
||||
.triggerPoint(TriggerPoint.builder().event("event").build())
|
||||
// Intentionally NO contextMachineId or stateMachineId
|
||||
// NO contextMachineId or stateMachineId
|
||||
.build();
|
||||
|
||||
AnalysisResult result = AnalysisResult.builder()
|
||||
@@ -188,6 +188,6 @@ class TransitionLinkerEnricherTest {
|
||||
enricher.enrich(result, null, null);
|
||||
|
||||
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
|
||||
assertThat(updatedChain.getMatchedTransitions()).isNullOrEmpty();
|
||||
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,4 +165,58 @@ class CallGraphBuilderTest {
|
||||
CallChain chain = chains.get(0);
|
||||
assertThat(chain.getTriggerPoint().getEvent()).isEqualTo("OrderEvents.CREATE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveTriggerPointLocalVariableAcrossChain() throws IOException {
|
||||
String source = """
|
||||
package com.example;
|
||||
public class OrderController {
|
||||
private OrderService service;
|
||||
public void processOrderEvent(MyOrderEvent domainEvent) {
|
||||
doProcessOrderEvent(domainEvent);
|
||||
}
|
||||
|
||||
private void doProcessOrderEvent(MyOrderEvent domainEvent) {
|
||||
OrderEvents eventType = domainEvent.getType();
|
||||
service.updateOrderState(eventType);
|
||||
}
|
||||
}
|
||||
|
||||
class OrderService {
|
||||
public void updateOrderState(OrderEvents event) {
|
||||
// sendEvent
|
||||
}
|
||||
}
|
||||
|
||||
class MyOrderEvent {
|
||||
public OrderEvents getType() { return OrderEvents.PAY; }
|
||||
}
|
||||
|
||||
enum OrderEvents { CREATE, PAY }
|
||||
""";
|
||||
Path tempDir = Files.createTempDirectory("callgraph_test2");
|
||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
|
||||
CallGraphBuilder builder = new CallGraphBuilder(context);
|
||||
|
||||
EntryPoint entryPoint = EntryPoint.builder()
|
||||
.className("com.example.OrderController")
|
||||
.methodName("processOrderEvent")
|
||||
.build();
|
||||
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.className("com.example.OrderService")
|
||||
.methodName("updateOrderState")
|
||||
.event("event")
|
||||
.build();
|
||||
|
||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||
|
||||
assertThat(chains).hasSize(1);
|
||||
CallChain chain = chains.get(0);
|
||||
assertThat(chain.getTriggerPoint().getEvent()).isEqualTo("domainEvent.getType()");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user