apparently perfomance fix that doesn't bring regreesions, NOT SURE

This commit is contained in:
2026-07-05 16:29:30 +02:00
parent 27005da678
commit 78c0f3e705
6 changed files with 124 additions and 166 deletions

View File

@@ -53,6 +53,18 @@ public class StrictFqnMatchingEngine implements EventMatchingEngine {
}
}
if (rawTriggerEvent != null && rawTriggerEvent.contains(".valueOf(")) {
String enumClass = rawTriggerEvent.substring(0, rawTriggerEvent.indexOf(".valueOf("));
if (enumClass.contains(" ")) {
enumClass = enumClass.substring(enumClass.lastIndexOf(" ") + 1);
}
String smClass = smEventRaw.contains(".") ? smEventRaw.substring(0, smEventRaw.lastIndexOf('.')) : smEventRaw;
if (enumClass.equals(smClass) || enumClass.endsWith("." + smClass) || smClass.endsWith("." + enumClass)) {
return true;
}
return false;
}
if (polyEvents.isEmpty() && isWildcardVariable(rawTriggerEvent)) {
return true;
}

View File

@@ -51,11 +51,29 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
for (EntryPoint ep : entryPoints) {
String startMethod = ep.getClassName() + "." + ep.getMethodName();
List<String> startMethods = new ArrayList<>();
startMethods.add(startMethod);
TypeDeclaration td = context.getTypeDeclaration(ep.getClassName());
boolean isAbstractOrInterface = false;
if (td != null) {
isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract"));
}
if (isAbstractOrInterface) {
List<String> impls = context.getImplementations(ep.getClassName());
for (String impl : impls) {
startMethods.add(impl + "." + ep.getMethodName());
}
}
boolean foundAny = false;
for (TriggerPoint tp : triggers) {
String targetMethod = tp.getClassName() + "." + tp.getMethodName();
List<List<String>> paths = pathFinder.findAllPaths(startMethod, targetMethod, callGraph, new HashSet<>());
Set<List<String>> uniquePaths = new LinkedHashSet<>(paths);
List<List<String>> allPaths = new ArrayList<>();
for (String sMethod : startMethods) {
allPaths.addAll(pathFinder.findAllPaths(sMethod, targetMethod, callGraph, new HashSet<>()));
}
Set<List<String>> uniquePaths = new LinkedHashSet<>(allPaths);
for (List<String> path : uniquePaths) {
foundAny = true;
TriggerPoint resolvedTp = resolveTriggerPointParameters(tp, path, callGraph);
@@ -1411,24 +1429,28 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1);
TypeDeclaration td = context.getTypeDeclaration(className);
if (isFunctionalInterface(className, td)) {
allResolved.add(baseCalled);
List<String> impls = context.getImplementations(className);
boolean shouldExpand = true;
if (impls.isEmpty()) {
shouldExpand = false;
} else {
List<String> impls = context.getImplementations(className);
if (impls.isEmpty()) {
allResolved.add(baseCalled);
} else {
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);
}
if (td == null && impls.size() > 3) {
shouldExpand = false;
}
if (impls.size() > 20) {
shouldExpand = false;
}
boolean isImplicitThis = node.getExpression() instanceof ThisExpression;
if (td != null && !td.isInterface() && !Modifier.isAbstract(td.getModifiers()) && isImplicitThis) {
shouldExpand = false;
}
}
allResolved.add(baseCalled);
if (shouldExpand) {
for (String impl : impls) {
allResolved.add(impl + "." + methodName);
}
}
} else {
@@ -1438,52 +1460,6 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
return allResolved;
}
private boolean isFunctionalInterface(String className, TypeDeclaration td) {
if (className == null) return false;
if (className.equals("java.lang.Runnable") || className.equals("Runnable")) return true;
if (className.equals("java.util.concurrent.Callable") || className.equals("Callable")) return true;
if (className.startsWith("java.util.function.")) return true;
if (td != null && td.isInterface()) {
if (td.modifiers() != null) {
for (Object mod : td.modifiers()) {
if (mod instanceof Annotation ann) {
String name = ann.getTypeName().toString();
if (name.equals("FunctionalInterface") || name.endsWith(".FunctionalInterface")) {
return true;
}
}
}
}
int abstractMethodCount = 0;
for (MethodDeclaration md : td.getMethods()) {
if (md.getBody() == null) {
String name = md.getName().getIdentifier();
if (name.equals("equals") && md.parameters().size() == 1) continue;
if (name.equals("hashCode") && md.parameters().isEmpty()) continue;
if (name.equals("toString") && md.parameters().isEmpty()) continue;
boolean isStaticOrDefault = false;
if (md.modifiers() != null) {
for (Object mod : md.modifiers()) {
if (mod instanceof Modifier m) {
if (m.isStatic() || m.isDefault()) {
isStaticOrDefault = true;
break;
}
}
}
}
if (!isStaticOrDefault) {
abstractMethodCount++;
}
}
}
return abstractMethodCount == 1;
}
return false;
}
private String unwrapConverterMethods(String arg) {
if (arg == null) return null;
String current = arg;

View File

@@ -77,54 +77,7 @@ public class CallGraphPathFinder {
}
}
// Handle inheritance fallback for concrete class methods not in the graph
if (result.isEmpty() && start.contains(".")) {
String className = start.substring(0, start.lastIndexOf('.'));
String methodName = start.substring(start.lastIndexOf('.') + 1);
if (className.contains("<")) {
className = className.substring(0, className.indexOf('<'));
}
TypeDeclaration td = context.getTypeDeclaration(className);
if (td != null) {
String superclass = context.getSuperclassFqn(td);
if (superclass != null) {
String superMethod = superclass + "." + methodName;
if (graph.containsKey(superMethod)) {
List<List<String>> superPaths = findAllPaths(superMethod, target, graph, visited);
for (List<String> superPath : superPaths) {
List<String> path = new ArrayList<>();
path.add(start);
path.addAll(superPath);
result.add(path);
}
}
}
}
}
// Handle implementation fallback for interfaces/superclasses (interface -> concrete class)
if (result.isEmpty() && start.contains(".")) {
String className = start.substring(0, start.lastIndexOf('.'));
String methodName = start.substring(start.lastIndexOf('.') + 1);
if (className.contains("<")) {
className = className.substring(0, className.indexOf('<'));
}
List<String> impls = context.getImplementations(className);
if (impls != null) {
for (String impl : impls) {
String implMethod = impl + "." + methodName;
if (graph.containsKey(implMethod)) {
List<List<String>> implPaths = findAllPaths(implMethod, target, graph, visited);
for (List<String> implPath : implPaths) {
List<String> path = new ArrayList<>();
path.add(start);
path.addAll(implPath);
result.add(path);
}
}
}
}
}
visited.remove(start);
return result;

View File

@@ -165,7 +165,7 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
if (receiver instanceof MethodInvocation miReceiver) {
String returnType = resolveMethodInvocationReturnType(miReceiver);
if (returnType != null) {
return returnType + "." + methodName;
return resolveToDeclaringMethod(returnType, methodName);
}
}
@@ -189,7 +189,7 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
String concreteFqn = injectionAnalyzer.resolveInjectedBeanFqn(varBinding);
if (concreteFqn != null) {
System.out.println(" -> RESOLVED CONCRETE FQN: " + concreteFqn);
return concreteFqn + "." + methodName;
return resolveToDeclaringMethod(concreteFqn, methodName);
} else {
System.out.println(" -> RESOLVE FAILED, RETURNED NULL");
}
@@ -223,7 +223,7 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
}
if (typeName != null && !typeName.isEmpty()) {
return typeName + "." + methodName;
return resolveToDeclaringMethod(typeName, methodName);
}
}
@@ -237,7 +237,7 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
if (receiver instanceof SimpleName sn) {
String fallbackTypeFqn = resolveReceiverTypeFallback(sn);
if (fallbackTypeFqn != null) {
return fallbackTypeFqn + "." + methodName;
return resolveToDeclaringMethod(fallbackTypeFqn, methodName);
}
String receiverName = sn.getIdentifier();
return receiverName + "." + methodName;
@@ -246,6 +246,21 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
return null;
}
private String resolveToDeclaringMethod(String typeName, String methodName) {
if (typeName == null || typeName.isEmpty()) return null;
TypeDeclaration td = context.getTypeDeclaration(typeName);
if (td != null) {
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
if (md != null) {
TypeDeclaration declaringTd = findEnclosingType(md);
if (declaringTd != null) {
return context.getFqn(declaringTd) + "." + methodName;
}
}
}
return typeName + "." + methodName;
}
private String resolveReceiverTypeFallback(SimpleName receiverNameNode) {
String varName = receiverNameNode.getIdentifier();