better tests
This commit is contained in:
@@ -352,7 +352,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
resolvedValue = cic.toString() + "." + methodName + "()";
|
resolvedValue = cic.toString() + "." + methodName + "()";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!polymorphicEvents.isEmpty()) {
|
System.out.println("Returning early with events: " + polymorphicEvents + " for " + resolvedValue); if (!polymorphicEvents.isEmpty()) {
|
||||||
return TriggerPoint.builder()
|
return TriggerPoint.builder()
|
||||||
.event(resolvedValue)
|
.event(resolvedValue)
|
||||||
.className(tp.getClassName())
|
.className(tp.getClassName())
|
||||||
@@ -438,6 +438,21 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
if (values != null && !values.isEmpty()) {
|
if (values != null && !values.isEmpty()) {
|
||||||
polymorphicEvents.addAll(values);
|
polymorphicEvents.addAll(values);
|
||||||
}
|
}
|
||||||
|
if (polymorphicEvents.isEmpty() && variableTracer != null) {
|
||||||
|
String initializer = variableTracer.traceLocalVariable(methodFqn, varName);
|
||||||
|
if (initializer != null && !initializer.equals(varName)) {
|
||||||
|
ASTParser mapParser = ASTParser.newParser(AST.JLS17);
|
||||||
|
mapParser.setKind(ASTParser.K_EXPRESSION);
|
||||||
|
mapParser.setSource(initializer.toCharArray());
|
||||||
|
ASTNode mapNode = mapParser.createAST(null);
|
||||||
|
if (mapNode instanceof Expression) {
|
||||||
|
List<Expression> mapTraced = variableTracer.traceVariableAll((Expression) mapNode);
|
||||||
|
for (Expression t : mapTraced) {
|
||||||
|
constantExtractor.extractConstantsFromExpression(t, polymorphicEvents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
sourceMethod = methodFqn;
|
sourceMethod = methodFqn;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,11 +72,20 @@ public class ConstantExtractor {
|
|||||||
} else if (expr instanceof MethodInvocation mi) {
|
} else if (expr instanceof MethodInvocation mi) {
|
||||||
String methodName = mi.getName().getIdentifier();
|
String methodName = mi.getName().getIdentifier();
|
||||||
|
|
||||||
if (methodName.equals("get") && mi.arguments().size() == 1 && mi.getExpression() != null) {
|
System.out.println("Processing mi: " + mi); if (methodName.equals("get") || methodName.equals("getOrDefault")) {
|
||||||
|
if (mi.getExpression() != null) {
|
||||||
|
if (variableTracer != null) {
|
||||||
|
List<Expression> traced = variableTracer.traceVariableAll(mi.getExpression());
|
||||||
|
for (Expression t : traced) {
|
||||||
|
extractConstantsFromExpression(t, constants);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
extractConstantsFromExpression(mi.getExpression(), constants);
|
extractConstantsFromExpression(mi.getExpression(), constants);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((methodName.equals("of") || methodName.equals("asList")) && mi.getExpression() instanceof SimpleName) {
|
if (methodName.equals("of") || methodName.equals("ofEntries") || methodName.equals("asList") || methodName.equals("entry")) {
|
||||||
for (Object argObj : mi.arguments()) {
|
for (Object argObj : mi.arguments()) {
|
||||||
extractConstantsFromExpression((Expression) argObj, constants);
|
extractConstantsFromExpression((Expression) argObj, constants);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,19 +341,7 @@ public class VariableTracer {
|
|||||||
Expression traced = traceVariable(expr);
|
Expression traced = traceVariable(expr);
|
||||||
if (traced instanceof MethodInvocation mi) {
|
if (traced instanceof MethodInvocation mi) {
|
||||||
Expression innerMost = unwrapMethodInvocation(mi, 0);
|
Expression innerMost = unwrapMethodInvocation(mi, 0);
|
||||||
if (innerMost instanceof MethodInvocation innerMi) {
|
|
||||||
if (innerMi.getExpression() instanceof SimpleName sn) {
|
|
||||||
stringified.add(sn.getIdentifier() + "." + innerMi.getName().getIdentifier() + "()");
|
|
||||||
} else {
|
|
||||||
stringified.add(innerMi.getName().getIdentifier() + "()");
|
|
||||||
}
|
|
||||||
} else if (innerMost instanceof SimpleName sn) {
|
|
||||||
stringified.add(sn.getIdentifier());
|
|
||||||
} else {
|
|
||||||
stringified.add(innerMost.toString());
|
stringified.add(innerMost.toString());
|
||||||
}
|
|
||||||
} else if (traced instanceof SimpleName sn) {
|
|
||||||
stringified.add(sn.getIdentifier());
|
|
||||||
} else if (traced instanceof ArrayInitializer) {
|
} else if (traced instanceof ArrayInitializer) {
|
||||||
stringified.add("new Object[]" + traced.toString());
|
stringified.add("new Object[]" + traced.toString());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.analysis.service;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||||
|
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||||
|
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class NewBugTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveMapLookup() throws IOException {
|
||||||
|
String source = """
|
||||||
|
package com.example;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Controller {
|
||||||
|
private StateMachine machine;
|
||||||
|
private static final Map<InputEnum, TransitionEnum> MAP = Map.of(
|
||||||
|
InputEnum.IN_A, TransitionEnum.STATE_X,
|
||||||
|
InputEnum.IN_B, TransitionEnum.STATE_Y
|
||||||
|
);
|
||||||
|
|
||||||
|
public void process(InputEnum input) {
|
||||||
|
TransitionEnum trans = MAP.get(input);
|
||||||
|
machine.fire(trans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StateMachine {
|
||||||
|
public void fire(TransitionEnum event) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum InputEnum { IN_A, IN_B }
|
||||||
|
enum TransitionEnum { STATE_X, STATE_Y }
|
||||||
|
""";
|
||||||
|
|
||||||
|
Path tempDir = Files.createTempDirectory("callgraph_test_map");
|
||||||
|
Files.writeString(tempDir.resolve("Config.java"), source);
|
||||||
|
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
|
||||||
|
HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context);
|
||||||
|
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder()
|
||||||
|
.className("com.example.Controller")
|
||||||
|
.methodName("process")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder()
|
||||||
|
.className("com.example.StateMachine")
|
||||||
|
.methodName("fire")
|
||||||
|
.event("event")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<CallChain> chains = engine.findChains(List.of(entryPoint), List.of(trigger));
|
||||||
|
assertThat(chains).hasSize(1);
|
||||||
|
System.out.println("Poly events: " + chains.get(0).getTriggerPoint().getPolymorphicEvents());
|
||||||
|
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).contains("TransitionEnum.STATE_X", "TransitionEnum.STATE_Y");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user