update number 5
This commit is contained in:
@@ -53,6 +53,9 @@ public class TriggerPoint {
|
|||||||
this.eventTypeFqn = eventTypeFqn;
|
this.eventTypeFqn = eventTypeFqn;
|
||||||
this.event = qualifyEvent(event, eventTypeFqn);
|
this.event = qualifyEvent(event, eventTypeFqn);
|
||||||
if (polymorphicEvents != null) {
|
if (polymorphicEvents != null) {
|
||||||
|
if (polymorphicEvents.contains("CustomEvents.ALPHA")) {
|
||||||
|
new Exception("DEBUG TriggerPoint constructed with CustomEvents.ALPHA!").printStackTrace(System.out);
|
||||||
|
}
|
||||||
this.polymorphicEvents = polymorphicEvents.stream()
|
this.polymorphicEvents = polymorphicEvents.stream()
|
||||||
.map(pe -> qualifyEvent(pe, eventTypeFqn))
|
.map(pe -> qualifyEvent(pe, eventTypeFqn))
|
||||||
.collect(java.util.stream.Collectors.toList());
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|||||||
@@ -132,13 +132,7 @@ public class ConstantResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ITypeBinding returnType = mb.getReturnType();
|
|
||||||
if (returnType != null) {
|
|
||||||
java.util.List<String> values = context.getEnumValues(returnType.getQualifiedName());
|
|
||||||
if (values != null && !values.isEmpty()) {
|
|
||||||
return "ENUM_SET:" + String.join(",", values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
TypeDeclaration td = null;
|
TypeDeclaration td = null;
|
||||||
if (mi.getExpression() != null) {
|
if (mi.getExpression() != null) {
|
||||||
@@ -171,8 +165,7 @@ public class ConstantResolver {
|
|||||||
if (md != null) {
|
if (md != null) {
|
||||||
String evaluated = evaluateMethodOutput(mi, md, context, visited);
|
String evaluated = evaluateMethodOutput(mi, md, context, visited);
|
||||||
if (evaluated != null) return evaluated;
|
if (evaluated != null) return evaluated;
|
||||||
|
if (mi.getName().getIdentifier().startsWith("get") && md.getReturnType2() != null) {
|
||||||
if (md.getReturnType2() != null) {
|
|
||||||
java.util.List<String> values = context.getEnumValues(md.getReturnType2().toString());
|
java.util.List<String> values = context.getEnumValues(md.getReturnType2().toString());
|
||||||
if (values != null && !values.isEmpty()) {
|
if (values != null && !values.isEmpty()) {
|
||||||
return "ENUM_SET:" + String.join(",", values);
|
return "ENUM_SET:" + String.join(",", values);
|
||||||
@@ -182,7 +175,6 @@ public class ConstantResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
click.kamil.springstatemachineexporter.ast.common.JdtDataFlowModel.setCurrentPath(path);
|
click.kamil.springstatemachineexporter.ast.common.JdtDataFlowModel.setCurrentPath(path);
|
||||||
try {
|
try {
|
||||||
String event = tp.getEvent();
|
String event = tp.getEvent();
|
||||||
|
event = unwrapConverterMethods(event);
|
||||||
String currentParamName = event;
|
String currentParamName = event;
|
||||||
String resolvedValue = event;
|
String resolvedValue = event;
|
||||||
String methodSuffix = "";
|
String methodSuffix = "";
|
||||||
@@ -194,30 +195,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
if (paramIndex < edge.getArguments().size()) {
|
if (paramIndex < edge.getArguments().size()) {
|
||||||
String arg = edge.getArguments().get(paramIndex);
|
String arg = edge.getArguments().get(paramIndex);
|
||||||
if (arg != null) {
|
if (arg != null) {
|
||||||
if (arg.contains("(") && !arg.startsWith("new ")) {
|
arg = unwrapConverterMethods(arg);
|
||||||
org.eclipse.jdt.core.dom.ASTParser argParser = org.eclipse.jdt.core.dom.ASTParser.newParser(org.eclipse.jdt.core.dom.AST.JLS17);
|
|
||||||
argParser.setKind(org.eclipse.jdt.core.dom.ASTParser.K_EXPRESSION);
|
|
||||||
argParser.setSource(arg.toCharArray());
|
|
||||||
org.eclipse.jdt.core.dom.ASTNode argNode = argParser.createAST(null);
|
|
||||||
if (argNode instanceof org.eclipse.jdt.core.dom.MethodInvocation miArg && !miArg.arguments().isEmpty()) {
|
|
||||||
boolean shouldUnpack = false;
|
|
||||||
org.eclipse.jdt.core.dom.Expression recv = miArg.getExpression();
|
|
||||||
if (recv == null || recv instanceof org.eclipse.jdt.core.dom.ThisExpression) {
|
|
||||||
shouldUnpack = true;
|
|
||||||
} else if (recv instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
|
||||||
shouldUnpack = !Character.isLowerCase(sn.getIdentifier().charAt(0));
|
|
||||||
} else if (recv instanceof org.eclipse.jdt.core.dom.QualifiedName qn) {
|
|
||||||
shouldUnpack = !Character.isLowerCase(qn.getName().getIdentifier().charAt(0));
|
|
||||||
}
|
|
||||||
if (shouldUnpack) {
|
|
||||||
org.eclipse.jdt.core.dom.Expression innerArg = (org.eclipse.jdt.core.dom.Expression) miArg.arguments().get(0);
|
|
||||||
if (miArg.getName().getIdentifier().equals("valueOf") && miArg.arguments().size() == 2) {
|
|
||||||
innerArg = (org.eclipse.jdt.core.dom.Expression) miArg.arguments().get(1);
|
|
||||||
}
|
|
||||||
arg = innerArg.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String receiver = edge.getReceiver();
|
String receiver = edge.getReceiver();
|
||||||
String actualReceiver = null;
|
String actualReceiver = null;
|
||||||
if ("this".equals(arg) || arg.startsWith("this.") || "super".equals(arg) || arg.startsWith("super.")) {
|
if ("this".equals(arg) || arg.startsWith("this.") || "super".equals(arg) || arg.startsWith("super.")) {
|
||||||
@@ -270,6 +248,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
constantExtractor.extractConstantsFromExpression(tracedSetter, setterEvents);
|
constantExtractor.extractConstantsFromExpression(tracedSetter, setterEvents);
|
||||||
}
|
}
|
||||||
if (!setterEvents.isEmpty()) {
|
if (!setterEvents.isEmpty()) {
|
||||||
|
System.out.println("DEBUG Early return 1: setterEvents = " + setterEvents);
|
||||||
return TriggerPoint.builder()
|
return TriggerPoint.builder()
|
||||||
.event(tp.getEvent())
|
.event(tp.getEvent())
|
||||||
.className(tp.getClassName())
|
.className(tp.getClassName())
|
||||||
@@ -289,11 +268,12 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasGetterOnReceiver = methodSuffix.startsWith(".get") && currentParamName != null
|
boolean hasGetterOnReceiver = (methodSuffix.startsWith(".get") || methodSuffix.equals(".type") || methodSuffix.equals(".event") || methodSuffix.equals(".type()") || methodSuffix.equals(".event()")) && currentParamName != null
|
||||||
&& (currentParamName.contains("new ") || (!currentParamName.replaceFirst("^this\\.", "").contains(".") && !currentParamName.contains("(")));
|
&& (currentParamName.contains("new ") || (!currentParamName.replaceFirst("^this\\.", "").contains(".") && !currentParamName.contains("(")));
|
||||||
if (hasGetterOnReceiver) {
|
if (hasGetterOnReceiver) {
|
||||||
List<String> getterEvents = evaluateGetterOnReceiver(resolvedValue, methodSuffix, entryMethod, path, callGraph);
|
List<String> getterEvents = evaluateGetterOnReceiver(resolvedValue, methodSuffix, entryMethod, path, callGraph);
|
||||||
if (getterEvents != null && !getterEvents.isEmpty()) {
|
if (getterEvents != null && !getterEvents.isEmpty()) {
|
||||||
|
System.out.println("DEBUG Early return 2: getterEvents = " + getterEvents);
|
||||||
return TriggerPoint.builder()
|
return TriggerPoint.builder()
|
||||||
.event(tp.getEvent())
|
.event(tp.getEvent())
|
||||||
.className(tp.getClassName())
|
.className(tp.getClassName())
|
||||||
@@ -323,6 +303,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println("DEBUG resolvedValue before ENUM_SET check: " + resolvedValue + " for path: " + path);
|
||||||
List<String> polymorphicEvents = new ArrayList<>();
|
List<String> polymorphicEvents = new ArrayList<>();
|
||||||
|
|
||||||
if (resolvedValue.startsWith("ENUM_SET:")) {
|
if (resolvedValue.startsWith("ENUM_SET:")) {
|
||||||
@@ -594,6 +575,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println("DEBUG declaredType before getEnumValues: " + declaredType + " for exprNode: " + exprNode + " in " + entryMethod);
|
||||||
if (declaredType != null) {
|
if (declaredType != null) {
|
||||||
List<String> enumValues = context.getEnumValues(declaredType);
|
List<String> enumValues = context.getEnumValues(declaredType);
|
||||||
if (enumValues != null && !enumValues.isEmpty()) {
|
if (enumValues != null && !enumValues.isEmpty()) {
|
||||||
@@ -722,7 +704,6 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
|
|
||||||
polymorphicEvents = polymorphicEvents.stream().distinct().collect(java.util.stream.Collectors.toList());
|
polymorphicEvents = polymorphicEvents.stream().distinct().collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
System.out.println("JSON DEBUG: building final TriggerPoint. resolvedValue=" + resolvedValue + ", event=" + event);
|
|
||||||
if (!resolvedValue.equals(event) || !polymorphicEvents.isEmpty()) {
|
if (!resolvedValue.equals(event) || !polymorphicEvents.isEmpty()) {
|
||||||
return TriggerPoint.builder()
|
return TriggerPoint.builder()
|
||||||
.event(resolvedValue)
|
.event(resolvedValue)
|
||||||
@@ -1414,4 +1395,74 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
|||||||
|
|
||||||
protected abstract Map<String, List<CallEdge>> buildCallGraph();
|
protected abstract Map<String, List<CallEdge>> buildCallGraph();
|
||||||
protected abstract String resolveCalledMethod(MethodInvocation node);
|
protected abstract String resolveCalledMethod(MethodInvocation node);
|
||||||
|
|
||||||
|
protected List<String> resolveCalledMethodsPolymorphic(MethodInvocation node) {
|
||||||
|
String baseCalled = resolveCalledMethod(node);
|
||||||
|
if (baseCalled == null) return Collections.emptyList();
|
||||||
|
|
||||||
|
List<String> allResolved = new ArrayList<>();
|
||||||
|
|
||||||
|
if (node.getExpression() == null) {
|
||||||
|
return Collections.singletonList(baseCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseCalled.contains(".")) {
|
||||||
|
String className = baseCalled.substring(0, baseCalled.lastIndexOf('.'));
|
||||||
|
String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1);
|
||||||
|
|
||||||
|
List<String> impls = context.getImplementations(className);
|
||||||
|
if (impls.isEmpty()) {
|
||||||
|
allResolved.add(baseCalled);
|
||||||
|
} else {
|
||||||
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
|
boolean isAbstractOrInterface = false;
|
||||||
|
if (td != null) {
|
||||||
|
isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract"));
|
||||||
|
}
|
||||||
|
boolean isImplicitThis = node.getExpression() == null || node.getExpression() instanceof ThisExpression;
|
||||||
|
if (!isAbstractOrInterface || isImplicitThis) {
|
||||||
|
allResolved.add(baseCalled);
|
||||||
|
}
|
||||||
|
for (String impl : impls) {
|
||||||
|
allResolved.add(impl + "." + methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allResolved.add(baseCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allResolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String unwrapConverterMethods(String arg) {
|
||||||
|
if (arg == null) return null;
|
||||||
|
String current = arg;
|
||||||
|
while (current.contains("(") && !current.startsWith("new ")) {
|
||||||
|
org.eclipse.jdt.core.dom.ASTParser argParser = org.eclipse.jdt.core.dom.ASTParser.newParser(org.eclipse.jdt.core.dom.AST.JLS17);
|
||||||
|
argParser.setKind(org.eclipse.jdt.core.dom.ASTParser.K_EXPRESSION);
|
||||||
|
argParser.setSource(current.toCharArray());
|
||||||
|
org.eclipse.jdt.core.dom.ASTNode argNode = argParser.createAST(null);
|
||||||
|
if (argNode instanceof org.eclipse.jdt.core.dom.MethodInvocation miArg && !miArg.arguments().isEmpty()) {
|
||||||
|
boolean shouldUnpack = false;
|
||||||
|
org.eclipse.jdt.core.dom.Expression recv = miArg.getExpression();
|
||||||
|
if (recv == null || recv instanceof org.eclipse.jdt.core.dom.ThisExpression) {
|
||||||
|
shouldUnpack = true;
|
||||||
|
} else if (recv instanceof org.eclipse.jdt.core.dom.SimpleName sn) {
|
||||||
|
shouldUnpack = !Character.isLowerCase(sn.getIdentifier().charAt(0));
|
||||||
|
} else if (recv instanceof org.eclipse.jdt.core.dom.QualifiedName qn) {
|
||||||
|
shouldUnpack = !Character.isLowerCase(qn.getName().getIdentifier().charAt(0));
|
||||||
|
}
|
||||||
|
if (shouldUnpack) {
|
||||||
|
org.eclipse.jdt.core.dom.Expression innerArg = (org.eclipse.jdt.core.dom.Expression) miArg.arguments().get(0);
|
||||||
|
if (miArg.getName().getIdentifier().equals("valueOf") && miArg.arguments().size() == 2) {
|
||||||
|
innerArg = (org.eclipse.jdt.core.dom.Expression) miArg.arguments().get(1);
|
||||||
|
}
|
||||||
|
current = innerArg.toString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,14 @@ public class ConstantExtractor {
|
|||||||
if (constantResolver != null) {
|
if (constantResolver != null) {
|
||||||
String resolved = constantResolver.resolve(expr, context);
|
String resolved = constantResolver.resolve(expr, context);
|
||||||
if (resolved != null) {
|
if (resolved != null) {
|
||||||
|
if (resolved.startsWith("ENUM_SET:")) {
|
||||||
|
for (String eVal : resolved.substring(9).split(",")) {
|
||||||
|
String parsed = parseEnumSetElement(eVal);
|
||||||
|
if (!constants.contains(parsed)) constants.add(parsed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
constants.add(resolved);
|
constants.add(resolved);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,6 +281,7 @@ public class ConstantExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<String> resolveMethodReturnConstant(String className, String methodName, int depth, Set<String> visited, CompilationUnit contextCu) {
|
public List<String> resolveMethodReturnConstant(String className, String methodName, int depth, Set<String> visited, CompilationUnit contextCu) {
|
||||||
|
System.out.println("DEBUG ConstantExtractor.resolveMethodReturnConstant CALLED: className=" + className + ", methodName=" + methodName);
|
||||||
log.debug("Entering resolveMethodReturnConstant with className={}, methodName={}, depth={}", className, methodName, depth);
|
log.debug("Entering resolveMethodReturnConstant with className={}, methodName={}, depth={}", className, methodName, depth);
|
||||||
if (depth > 20) {
|
if (depth > 20) {
|
||||||
log.debug("Exiting resolveMethodReturnConstant early (depth limit) for {}.{}", className, methodName);
|
log.debug("Exiting resolveMethodReturnConstant early (depth limit) for {}.{}", className, methodName);
|
||||||
@@ -384,6 +392,7 @@ public class ConstantExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
visited.remove(fqn);
|
visited.remove(fqn);
|
||||||
|
System.out.println("DEBUG resolveMethodReturnConstant className=" + className + " methodName=" + methodName + " returns: " + constants);
|
||||||
log.debug("resolveMethodReturnConstant for class={}, method={} resolved constants: {}", className, methodName, constants);
|
log.debug("resolveMethodReturnConstant for class={}, method={} resolved constants: {}", className, methodName, constants);
|
||||||
return constants;
|
return constants;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,45 +160,6 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
|
|
||||||
return resolvedValue;
|
return resolvedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> resolveCalledMethodsPolymorphic(MethodInvocation node) {
|
|
||||||
String baseCalled = resolveCalledMethod(node);
|
|
||||||
if (baseCalled == null) return Collections.emptyList();
|
|
||||||
|
|
||||||
List<String> allResolved = new ArrayList<>();
|
|
||||||
|
|
||||||
if (node.getExpression() == null) {
|
|
||||||
return Collections.singletonList(baseCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseCalled.contains(".")) {
|
|
||||||
String className = baseCalled.substring(0, baseCalled.lastIndexOf('.'));
|
|
||||||
String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1);
|
|
||||||
|
|
||||||
List<String> impls = context.getImplementations(className);
|
|
||||||
if (impls.isEmpty()) {
|
|
||||||
allResolved.add(className + "." + methodName);
|
|
||||||
} else {
|
|
||||||
TypeDeclaration td = context.getTypeDeclaration(className);
|
|
||||||
boolean isAbstractOrInterface = false;
|
|
||||||
if (td != null) {
|
|
||||||
isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract"));
|
|
||||||
}
|
|
||||||
boolean isImplicitThis = node.getExpression() == null || node.getExpression() instanceof ThisExpression || node.getExpression() instanceof SuperMethodInvocation;
|
|
||||||
if (!isAbstractOrInterface || isImplicitThis) {
|
|
||||||
allResolved.add(className + "." + methodName);
|
|
||||||
}
|
|
||||||
for (String impl : impls) {
|
|
||||||
allResolved.add(impl + "." + methodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
allResolved.add(baseCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allResolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String findDefiningClass(String className, String methodName) {
|
private String findDefiningClass(String className, String methodName) {
|
||||||
TypeDeclaration td = context.getTypeDeclaration(className);
|
TypeDeclaration td = context.getTypeDeclaration(className);
|
||||||
if (td == null) return null;
|
if (td == null) return null;
|
||||||
|
|||||||
@@ -158,44 +158,6 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
|
|||||||
return super.resolveArgument(expr);
|
return super.resolveArgument(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> resolveCalledMethodsPolymorphic(MethodInvocation node) {
|
|
||||||
String baseCalled = resolveCalledMethod(node);
|
|
||||||
if (baseCalled == null) return Collections.emptyList();
|
|
||||||
|
|
||||||
List<String> allResolved = new ArrayList<>();
|
|
||||||
|
|
||||||
if (node.getExpression() == null) {
|
|
||||||
return Collections.singletonList(baseCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseCalled.contains(".")) {
|
|
||||||
String className = baseCalled.substring(0, baseCalled.lastIndexOf('.'));
|
|
||||||
String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1);
|
|
||||||
|
|
||||||
List<String> impls = context.getImplementations(className);
|
|
||||||
if (impls.isEmpty()) {
|
|
||||||
allResolved.add(baseCalled);
|
|
||||||
} else {
|
|
||||||
TypeDeclaration td = context.getTypeDeclaration(className);
|
|
||||||
boolean isAbstractOrInterface = false;
|
|
||||||
if (td != null) {
|
|
||||||
isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract"));
|
|
||||||
}
|
|
||||||
boolean isImplicitThis = node.getExpression() == null || node.getExpression() instanceof ThisExpression;
|
|
||||||
if (!isAbstractOrInterface || isImplicitThis) {
|
|
||||||
allResolved.add(baseCalled);
|
|
||||||
}
|
|
||||||
for (String impl : impls) {
|
|
||||||
allResolved.add(impl + "." + methodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
allResolved.add(baseCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allResolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String resolveCalledMethod(MethodInvocation node) {
|
protected String resolveCalledMethod(MethodInvocation node) {
|
||||||
Expression receiver = node.getExpression();
|
Expression receiver = node.getExpression();
|
||||||
String methodName = node.getName().getIdentifier();
|
String methodName = node.getName().getIdentifier();
|
||||||
|
|||||||
@@ -374,10 +374,12 @@ public class CodebaseContext {
|
|||||||
cleanName = cleanName.trim();
|
cleanName = cleanName.trim();
|
||||||
|
|
||||||
List<String> values = enumValues.get(cleanName);
|
List<String> values = enumValues.get(cleanName);
|
||||||
if (values != null) return values;
|
if (values == null) {
|
||||||
String fqn = simpleNameToFqn.get(cleanName);
|
String fqn = simpleNameToFqn.get(cleanName);
|
||||||
if (fqn != null) return enumValues.get(fqn);
|
if (fqn != null) values = enumValues.get(fqn);
|
||||||
return null;
|
}
|
||||||
|
System.out.println("DEBUG getEnumValues called for: " + fqnOrSimpleName + " resolved to " + cleanName + ". Returns: " + values);
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public State resolveState(Expression expr, CompilationUnit cu) {
|
public State resolveState(Expression expr, CompilationUnit cu) {
|
||||||
|
|||||||
@@ -377,6 +377,122 @@ class HeuristicCallGraphEnginePolymorphicTest {
|
|||||||
.containsExactlyInAnyOrder("CustomEvents.ALPHA", "CustomEvents.BETA");
|
.containsExactlyInAnyOrder("CustomEvents.ALPHA", "CustomEvents.BETA");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolvePolymorphicEventsThroughNestedConverters() throws IOException {
|
||||||
|
String source = """
|
||||||
|
package com.example;
|
||||||
|
public class Dispatcher {
|
||||||
|
private HandlerService service;
|
||||||
|
public void dispatchRequest(Payload domainEvent) {
|
||||||
|
doDispatch(domainEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doDispatch(Payload domainEvent) {
|
||||||
|
// NESTED CONVERTERS
|
||||||
|
service.handleEvent(verify(sanitize(domainEvent.type())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomEvents sanitize(CustomEvents e) { return e; }
|
||||||
|
private CustomEvents verify(CustomEvents e) { return e; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class HandlerService {
|
||||||
|
public void handleEvent(CustomEvents event) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
CustomEvents type();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AlphaPayload implements Payload {
|
||||||
|
public CustomEvents type() { return CustomEvents.ALPHA; }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CustomEvents { ALPHA, BETA }
|
||||||
|
""";
|
||||||
|
Path tempDir = Files.createTempDirectory("callgraph_test_poly_nested");
|
||||||
|
Files.writeString(tempDir.resolve("DispatcherConfig.java"), source);
|
||||||
|
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
||||||
|
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder()
|
||||||
|
.className("com.example.Dispatcher")
|
||||||
|
.methodName("dispatchRequest")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder()
|
||||||
|
.className("com.example.HandlerService")
|
||||||
|
.methodName("handleEvent")
|
||||||
|
.event("event")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||||
|
System.out.println("DEBUG context.getImplementations(Payload) = " + context.getImplementations("Payload"));
|
||||||
|
System.out.println("DEBUG context.getImplementations(com.example.Payload) = " + context.getImplementations("com.example.Payload"));
|
||||||
|
System.out.println("DEBUG getPolymorphicEvents() = " + chains.get(0).getTriggerPoint().getPolymorphicEvents());
|
||||||
|
assertThat(chains).hasSize(1);
|
||||||
|
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
||||||
|
.containsExactly("CustomEvents.ALPHA");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolvePolymorphicEventsWithCustomGetterSuffixes() throws IOException {
|
||||||
|
String source = """
|
||||||
|
package com.example;
|
||||||
|
public class Dispatcher {
|
||||||
|
private HandlerService service;
|
||||||
|
public void dispatchRequest(Payload domainEvent) {
|
||||||
|
doDispatch(domainEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doDispatch(Payload domainEvent) {
|
||||||
|
// Using .event() instead of .getEvent()
|
||||||
|
service.handleEvent(check(domainEvent.event()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomEvents check(CustomEvents e) { return e; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class HandlerService {
|
||||||
|
public void handleEvent(CustomEvents event) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
CustomEvents event();
|
||||||
|
}
|
||||||
|
|
||||||
|
class BetaPayload implements Payload {
|
||||||
|
public CustomEvents event() { return CustomEvents.BETA; }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CustomEvents { ALPHA, BETA }
|
||||||
|
""";
|
||||||
|
Path tempDir = Files.createTempDirectory("callgraph_test_poly_suffix");
|
||||||
|
Files.writeString(tempDir.resolve("DispatcherConfig.java"), source);
|
||||||
|
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
||||||
|
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder()
|
||||||
|
.className("com.example.Dispatcher")
|
||||||
|
.methodName("dispatchRequest")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder()
|
||||||
|
.className("com.example.HandlerService")
|
||||||
|
.methodName("handleEvent")
|
||||||
|
.event("event")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||||
|
assertThat(chains).hasSize(1);
|
||||||
|
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
||||||
|
.containsExactly("CustomEvents.BETA");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldResolveMappedTransitionEnumThroughAbstractBaseClassAndMultipleArgs() throws IOException {
|
void shouldResolveMappedTransitionEnumThroughAbstractBaseClassAndMultipleArgs() throws IOException {
|
||||||
String source = """
|
String source = """
|
||||||
|
|||||||
Reference in New Issue
Block a user