heuristics updated

This commit is contained in:
2026-06-24 22:03:57 +02:00
parent b35effd05c
commit 75fd45d983
4 changed files with 268 additions and 2 deletions

View File

@@ -14,6 +14,14 @@ public class ConstantResolver {
return resolveInternal(expr, context, new HashSet<>());
}
public String evaluateSwitchWithParams(org.eclipse.jdt.core.dom.SwitchExpression se, java.util.Map<String, String> paramValues, CodebaseContext context) {
return evaluateSwitchExpression(se, paramValues, context, new HashSet<>());
}
public String evaluateSwitchWithParams(org.eclipse.jdt.core.dom.SwitchStatement ss, java.util.Map<String, String> paramValues, CodebaseContext context) {
return evaluateSwitchStatement(ss, paramValues, context, new HashSet<>());
}
private String resolveInternal(Expression expr, CodebaseContext context, Set<String> visited) {
if (expr == null) return null;

View File

@@ -78,7 +78,8 @@ import java.util.*;
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);
Map<String, String> parameterValues = buildParameterValuesMap(caller, target, callGraph, path, i);
String tracedVar = traceLocalVariable(target, currentParamName, parameterValues);
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
// Extract method calls like .getType() from the traced variable
String[] extractedTraced = extractMethodSuffix(tracedVar, methodSuffix);
@@ -1511,6 +1512,149 @@ import java.util.*;
return null;
}
protected String traceLocalVariable(String methodFqn, String varName, java.util.Map<String, String> parameterValues) {
String result = traceLocalVariable(methodFqn, varName);
if (result != null && parameterValues != null && !parameterValues.isEmpty()) {
TypeDeclaration td = context.getTypeDeclaration(methodFqn.substring(0, methodFqn.lastIndexOf('.')));
if (td != null) {
String methodName = methodFqn.substring(methodFqn.lastIndexOf('.') + 1);
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
if (md != null && md.getBody() != null) {
final org.eclipse.jdt.core.dom.ASTNode[] switchNode = new org.eclipse.jdt.core.dom.ASTNode[1];
md.getBody().accept(new ASTVisitor() {
@Override
public boolean visit(VariableDeclarationFragment node) {
if (node.getName().getIdentifier().equals(varName) && node.getInitializer() != null) {
Expression init = node.getInitializer();
if (init.getNodeType() == ASTNode.SWITCH_EXPRESSION) {
switchNode[0] = init;
return false;
}
if (init.getNodeType() == ASTNode.SWITCH_STATEMENT) {
switchNode[0] = init;
return false;
}
}
return super.visit(node);
}
@Override
public boolean visit(Assignment node) {
if (node.getLeftHandSide() instanceof SimpleName asn && asn.getIdentifier().equals(varName)) {
Expression rhs = node.getRightHandSide();
if (rhs.getNodeType() == ASTNode.SWITCH_EXPRESSION) {
switchNode[0] = rhs;
return false;
}
if (rhs.getNodeType() == ASTNode.SWITCH_STATEMENT) {
switchNode[0] = rhs;
return false;
}
}
return super.visit(node);
}
});
if (switchNode[0] != null) {
if (switchNode[0] instanceof SwitchExpression se) {
String evaluated = constantResolver.evaluateSwitchWithParams(se, parameterValues, context);
if (evaluated != null) return evaluated;
} else if (switchNode[0] instanceof SwitchStatement ss) {
String evaluated = constantResolver.evaluateSwitchWithParams(ss, parameterValues, context);
if (evaluated != null) return evaluated;
}
}
}
}
}
return result;
}
protected java.util.Map<String, String> buildParameterValuesMap(String caller, String target, Map<String, List<CallEdge>> callGraph, List<String> path, int pathIndex) {
java.util.Map<String, String> paramValues = new java.util.HashMap<>();
List<CallEdge> edges = callGraph.get(caller);
if (edges == null) {
return paramValues;
}
for (CallEdge edge : edges) {
if (edge.getTargetMethod().equals(target) || isHeuristicMatch(edge.getTargetMethod(), target)) {
List<String> args = edge.getArguments();
if (args == null || args.isEmpty()) break;
int lastDot = target.lastIndexOf('.');
if (lastDot < 0) break;
String className = target.substring(0, lastDot);
String methodName = target.substring(lastDot + 1);
TypeDeclaration td = context.getTypeDeclaration(className);
if (td == null) break;
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
if (md == null) break;
List<String> paramNames = new java.util.ArrayList<>();
for (Object paramObj : md.parameters()) {
org.eclipse.jdt.core.dom.SingleVariableDeclaration param = (org.eclipse.jdt.core.dom.SingleVariableDeclaration) paramObj;
paramNames.add(param.getName().getIdentifier());
}
int minSize = java.lang.Math.min(paramNames.size(), args.size());
for (int j = 0; j < minSize; j++) {
String argValue = args.get(j);
String resolvedArgValue = resolveArgumentValue(argValue, caller, path, pathIndex, callGraph);
paramValues.put(paramNames.get(j), resolvedArgValue);
}
break;
}
}
return paramValues;
}
protected String resolveArgumentValue(String argValue, String callerMethod, List<String> path, int pathIndex, Map<String, List<CallEdge>> callGraph) {
if (argValue == null) return null;
if (argValue.contains(".") || argValue.startsWith("new ") || argValue.matches(".*[0-9].*")) {
return argValue;
}
int callerIndex = path.indexOf(callerMethod);
if (callerIndex <= 0) return argValue;
String prevCaller = path.get(callerIndex - 1);
List<CallEdge> prevEdges = callGraph.get(prevCaller);
if (prevEdges == null) return argValue;
for (CallEdge edge : prevEdges) {
if (edge.getTargetMethod().equals(callerMethod) || isHeuristicMatch(edge.getTargetMethod(), callerMethod)) {
List<String> prevArgs = edge.getArguments();
if (prevArgs == null || prevArgs.isEmpty()) break;
int lastDot = callerMethod.lastIndexOf('.');
if (lastDot < 0) break;
String className = callerMethod.substring(0, lastDot);
String methodName = callerMethod.substring(lastDot + 1);
TypeDeclaration td = context.getTypeDeclaration(className);
if (td == null) break;
MethodDeclaration md = context.findMethodDeclaration(td, methodName, true);
if (md == null) break;
List<String> paramNames = new java.util.ArrayList<>();
for (Object paramObj : md.parameters()) {
org.eclipse.jdt.core.dom.SingleVariableDeclaration param = (org.eclipse.jdt.core.dom.SingleVariableDeclaration) paramObj;
paramNames.add(param.getName().getIdentifier());
}
int paramIdx = paramNames.indexOf(argValue);
if (paramIdx >= 0 && paramIdx < prevArgs.size()) {
String prevArg = prevArgs.get(paramIdx);
return resolveArgumentValue(prevArg, prevCaller, path, pathIndex, callGraph);
}
break;
}
}
return argValue;
}
protected org.eclipse.jdt.core.dom.Expression traceLocalSetter(String methodFqn, String varName, String getterName) {
if (methodFqn == null || !methodFqn.contains(".")) return null;
String className = methodFqn.substring(0, methodFqn.lastIndexOf('.'));

View File

@@ -562,7 +562,8 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
String caller = path.get(i - 1);
int paramIndex = getParameterIndex(target, currentParamName);
if (paramIndex < 0) {
String tracedVar = traceLocalVariable(target, currentParamName);
java.util.Map<String, String> parameterValues = buildParameterValuesMap(caller, target, callGraph, path, i);
String tracedVar = traceLocalVariable(target, currentParamName, parameterValues);
if (tracedVar != null && !tracedVar.equals(currentParamName)) {
String[] extractedTraced = extractMethodSuffix(tracedVar, methodSuffix);
tracedVar = extractedTraced[0];
@@ -646,6 +647,21 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
String entryMethod = path.get(0);
int entryParamIndex = getParameterIndex(entryMethod, currentParamName);
if (resolvedValue != null && resolvedValue.contains(".") && !resolvedValue.contains("(") && !resolvedValue.contains(" ")) {
TriggerPoint modifiedTp = TriggerPoint.builder()
.event(resolvedValue)
.className(tp.getClassName())
.methodName(tp.getMethodName())
.sourceFile(tp.getSourceFile())
.sourceModule(tp.getSourceModule())
.stateMachineId(tp.getStateMachineId())
.sourceState(tp.getSourceState())
.lineNumber(tp.getLineNumber())
.build();
return super.resolveTriggerPointParameters(modifiedTp, path, callGraph);
}
if (entryParamIndex < 0) {
if (methodSuffix.startsWith(".get") || methodSuffix.equals(".type") || methodSuffix.equals(".event") || methodSuffix.equals(".type()") || methodSuffix.equals(".event()")) {
String localMethodName = methodSuffix.substring(1).replace("()", "");
@@ -822,4 +838,5 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
});
return initExpr[0];
}
}