update number 4

This commit is contained in:
2026-07-05 15:11:09 +02:00
parent 3988864494
commit bcdbbffa13
3 changed files with 94 additions and 1 deletions

View File

@@ -194,6 +194,30 @@ 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 ")) {
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.")) {

View File

@@ -164,6 +164,10 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
List<String> allResolved = new ArrayList<>(); List<String> allResolved = new ArrayList<>();
if (node.getExpression() == null) {
return Collections.singletonList(baseCalled);
}
if (baseCalled.contains(".")) { if (baseCalled.contains(".")) {
String className = baseCalled.substring(0, baseCalled.lastIndexOf('.')); String className = baseCalled.substring(0, baseCalled.lastIndexOf('.'));
String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1); String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1);
@@ -177,7 +181,8 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
if (td != null) { if (td != null) {
isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract")); isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract"));
} }
if (!isAbstractOrInterface) { boolean isImplicitThis = node.getExpression() == null || node.getExpression() instanceof ThisExpression;
if (!isAbstractOrInterface || isImplicitThis) {
allResolved.add(baseCalled); allResolved.add(baseCalled);
} }
for (String impl : impls) { for (String impl : impls) {

View File

@@ -313,6 +313,70 @@ class HeuristicCallGraphEnginePolymorphicTest {
org.assertj.core.api.Assertions.assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).contains("POST_ACCEPTANCE_REJECTED"); org.assertj.core.api.Assertions.assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).contains("POST_ACCEPTANCE_REJECTED");
} }
@Test
void shouldResolvePolymorphicEventsThroughAssertSupportedMethod() 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) {
service.handleEvent(checkAndMapEvent(domainEvent.getType()));
}
private CustomEvents checkAndMapEvent(CustomEvents e) {
return e;
}
}
class HandlerService {
public void handleEvent(CustomEvents event) {}
}
interface Payload {
CustomEvents getType();
}
class AlphaPayload implements Payload {
public CustomEvents getType() { return CustomEvents.ALPHA; }
}
class BetaPayload implements Payload {
public CustomEvents getType() { return CustomEvents.BETA; }
}
enum CustomEvents { ALPHA, BETA }
""";
Path tempDir = Files.createTempDirectory("callgraph_test_poly_assert");
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);
CallChain chain = chains.get(0);
assertThat(chain.getTriggerPoint().getPolymorphicEvents())
.containsExactlyInAnyOrder("CustomEvents.ALPHA", "CustomEvents.BETA");
}
@Test @Test
void shouldResolveMappedTransitionEnumThroughAbstractBaseClassAndMultipleArgs() throws IOException { void shouldResolveMappedTransitionEnumThroughAbstractBaseClassAndMultipleArgs() throws IOException {
String source = """ String source = """