2 Commits

Author SHA1 Message Date
9bea5c4687 7 2026-07-06 18:25:48 +02:00
475084aed4 7 2026-07-06 18:17:37 +02:00
9 changed files with 76 additions and 50 deletions

View File

@@ -6,11 +6,22 @@ import java.util.List;
public class HeuristicEventMatchingEngine implements EventMatchingEngine { public class HeuristicEventMatchingEngine implements EventMatchingEngine {
private final java.util.Map<java.util.Map.Entry<Event, TriggerPoint>, Boolean> matchesCache = new java.util.HashMap<>();
@Override @Override
public boolean matches(Event stateMachineEvent, TriggerPoint triggerPoint) { public boolean matches(Event stateMachineEvent, TriggerPoint triggerPoint) {
if (stateMachineEvent == null || triggerPoint == null || triggerPoint.getEvent() == null) { if (stateMachineEvent == null || triggerPoint == null || triggerPoint.getEvent() == null) {
return false; return false;
} }
java.util.Map.Entry<Event, TriggerPoint> cacheKey = new java.util.AbstractMap.SimpleImmutableEntry<>(stateMachineEvent, triggerPoint);
if (matchesCache.containsKey(cacheKey)) return matchesCache.get(cacheKey);
boolean result = calculateMatches(stateMachineEvent, triggerPoint);
matchesCache.put(cacheKey, result);
return result;
}
private boolean calculateMatches(Event stateMachineEvent, TriggerPoint triggerPoint) {
String rawTriggerEvent = triggerPoint.getEvent(); String rawTriggerEvent = triggerPoint.getEvent();
String smEventRaw = stateMachineEvent.fullIdentifier() != null ? stateMachineEvent.fullIdentifier() : stateMachineEvent.rawName(); String smEventRaw = stateMachineEvent.fullIdentifier() != null ? stateMachineEvent.fullIdentifier() : stateMachineEvent.rawName();

View File

@@ -21,6 +21,21 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
protected final VariableTracer variableTracer; protected final VariableTracer variableTracer;
protected final ConstantExtractor constantExtractor; protected final ConstantExtractor constantExtractor;
protected final ConstructorAnalyzer constructorAnalyzer; protected final ConstructorAnalyzer constructorAnalyzer;
private final Map<String, ASTNode> parsedNodeCache = new HashMap<>();
private ASTNode parseExpressionString(String expr) {
if (expr == null) return null;
return parsedNodeCache.computeIfAbsent(expr, e -> {
ASTParser parser = ASTParser.newParser(AST.JLS17);
parser.setKind(ASTParser.K_EXPRESSION);
parser.setSource(e.toCharArray());
try {
return parser.createAST(null);
} catch (Exception ex) {
return null;
}
});
}
@FunctionalInterface @FunctionalInterface
protected interface RhsResolver { protected interface RhsResolver {
@@ -268,7 +283,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); log.debug("Early return 1: setterEvents = {}", setterEvents);
return TriggerPoint.builder() return TriggerPoint.builder()
.event(tp.getEvent()) .event(tp.getEvent())
.className(tp.getClassName()) .className(tp.getClassName())
@@ -293,7 +308,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
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); log.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,7 +338,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
} }
} }
System.out.println("DEBUG resolvedValue before ENUM_SET check: " + resolvedValue + " for path: " + path); log.debug("resolvedValue before ENUM_SET check: {} for path: {}", resolvedValue, path);
List<String> polymorphicEvents = new ArrayList<>(); List<String> polymorphicEvents = new ArrayList<>();
if (resolvedValue.startsWith("ENUM_SET:")) { if (resolvedValue.startsWith("ENUM_SET:")) {
@@ -348,10 +363,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
.build(); .build();
} }
ASTParser exprParser = ASTParser.newParser(AST.JLS17); ASTNode exprNode = parseExpressionString(resolvedValue);
exprParser.setKind(ASTParser.K_EXPRESSION);
exprParser.setSource(resolvedValue.toCharArray());
ASTNode exprNode = exprParser.createAST(null);
String varName = null; String varName = null;
String methodName = null; String methodName = null;
@@ -552,10 +564,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
if (extractedFinalTraced[0] != null) { if (extractedFinalTraced[0] != null) {
resolvedValue = extractedFinalTraced[0] + extractedFinalTraced[1]; resolvedValue = extractedFinalTraced[0] + extractedFinalTraced[1];
if (extractedFinalTraced[0].contains("new ") && extractedFinalTraced[0].contains("{")) { if (extractedFinalTraced[0].contains("new ") && extractedFinalTraced[0].contains("{")) {
ASTParser p = ASTParser.newParser(AST.JLS17); ASTNode newNode = parseExpressionString(resolvedValue);
p.setKind(ASTParser.K_EXPRESSION);
p.setSource(resolvedValue.toCharArray());
ASTNode newNode = p.createAST(null);
if (newNode instanceof Expression) { if (newNode instanceof Expression) {
List<Expression> traced = variableTracer.traceVariableAll((Expression) newNode); List<Expression> traced = variableTracer.traceVariableAll((Expression) newNode);
for (Expression ex : traced) { for (Expression ex : traced) {
@@ -581,10 +590,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
if (polymorphicEvents.isEmpty() && variableTracer != null) { if (polymorphicEvents.isEmpty() && variableTracer != null) {
String initializer = variableTracer.traceLocalVariable(methodFqn, varName); String initializer = variableTracer.traceLocalVariable(methodFqn, varName);
if (initializer != null && !initializer.equals(varName)) { if (initializer != null && !initializer.equals(varName)) {
ASTParser mapParser = ASTParser.newParser(AST.JLS17); ASTNode mapNode = parseExpressionString(initializer);
mapParser.setKind(ASTParser.K_EXPRESSION);
mapParser.setSource(initializer.toCharArray());
ASTNode mapNode = mapParser.createAST(null);
if (mapNode instanceof Expression) { if (mapNode instanceof Expression) {
List<Expression> mapTraced = variableTracer.traceVariableAll((Expression) mapNode); List<Expression> mapTraced = variableTracer.traceVariableAll((Expression) mapNode);
for (Expression t : mapTraced) { for (Expression t : mapTraced) {
@@ -625,7 +631,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
} }
} }
System.out.println("DEBUG declaredType before getEnumValues: " + declaredType + " for exprNode: " + exprNode + " in " + entryMethod); log.debug("declaredType before getEnumValues: {} for exprNode: {} in {}", declaredType, exprNode, 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()) {
@@ -935,10 +941,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
} }
protected List<String> evaluateGetterOnReceiver(String resolvedValue, String methodSuffix, String entryMethod, List<String> path, Map<String, List<CallEdge>> callGraph) { protected List<String> evaluateGetterOnReceiver(String resolvedValue, String methodSuffix, String entryMethod, List<String> path, Map<String, List<CallEdge>> callGraph) {
ASTParser exprParser = ASTParser.newParser(AST.JLS17); ASTNode exprNode = parseExpressionString(resolvedValue);
exprParser.setKind(ASTParser.K_EXPRESSION);
exprParser.setSource(resolvedValue.toCharArray());
ASTNode exprNode = exprParser.createAST(null);
if (exprNode instanceof SuperMethodInvocation smi) { if (exprNode instanceof SuperMethodInvocation smi) {
String getterName = smi.getName().getIdentifier(); String getterName = smi.getName().getIdentifier();
@@ -1499,10 +1502,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
if (arg == null) return null; if (arg == null) return null;
String current = arg; String current = arg;
while (current.contains("(") && !current.startsWith("new ")) { 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); org.eclipse.jdt.core.dom.ASTNode argNode = parseExpressionString(current);
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()) { if (argNode instanceof org.eclipse.jdt.core.dom.MethodInvocation miArg && !miArg.arguments().isEmpty()) {
boolean shouldUnpack = false; boolean shouldUnpack = false;
org.eclipse.jdt.core.dom.Expression recv = miArg.getExpression(); org.eclipse.jdt.core.dom.Expression recv = miArg.getExpression();

View File

@@ -11,6 +11,9 @@ public class CallGraphPathFinder {
private final CodebaseContext context; private final CodebaseContext context;
private final Map<java.util.Map.Entry<String, String>, Boolean> heuristicCache = new HashMap<>(); private final Map<java.util.Map.Entry<String, String>, Boolean> heuristicCache = new HashMap<>();
private final Map<java.util.Map.Entry<String, String>, List<List<String>>> memoCache = new HashMap<>();
private final Map<java.util.Map.Entry<String, String>, Boolean> unreachableCache = new HashMap<>();
public CallGraphPathFinder(CodebaseContext context) { public CallGraphPathFinder(CodebaseContext context) {
this.context = context; this.context = context;
} }
@@ -50,16 +53,17 @@ public class CallGraphPathFinder {
} }
public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) { public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited) {
return findAllPaths(start, target, graph, visited, new HashSet<>(), new boolean[]{false}, new HashMap<>()); return findAllPaths(start, target, graph, visited, new boolean[]{false});
} }
public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited, Set<String> unreachable, boolean[] parentHitCycle, Map<String, List<List<String>>> memo) { public List<List<String>> findAllPaths(String start, String target, Map<String, List<CallEdge>> graph, Set<String> visited, boolean[] parentHitCycle) {
List<List<String>> result = new ArrayList<>(); List<List<String>> result = new ArrayList<>();
if (unreachable.contains(start)) { java.util.Map.Entry<String, String> cacheKey = new java.util.AbstractMap.SimpleImmutableEntry<>(start, target);
if (unreachableCache.containsKey(cacheKey)) {
return result; return result;
} }
if (memo.containsKey(start)) { if (memoCache.containsKey(cacheKey)) {
List<List<String>> cached = memo.get(start); List<List<String>> cached = memoCache.get(cacheKey);
for (List<String> path : cached) { for (List<String> path : cached) {
boolean hasCycle = false; boolean hasCycle = false;
for (String node : path) { for (String node : path) {
@@ -95,7 +99,7 @@ public class CallGraphPathFinder {
List<String> path = new ArrayList<>(List.of(start, target)); List<String> path = new ArrayList<>(List.of(start, target));
result.add(path); result.add(path);
} else { } else {
List<List<String>> subPaths = findAllPaths(neighbor, target, graph, visited, unreachable, localHitCycle, memo); List<List<String>> subPaths = findAllPaths(neighbor, target, graph, visited, localHitCycle);
for (List<String> subPath : subPaths) { for (List<String> subPath : subPaths) {
List<String> path = new ArrayList<>(); List<String> path = new ArrayList<>();
path.add(start); path.add(start);
@@ -119,7 +123,7 @@ public class CallGraphPathFinder {
if (superclass != null) { if (superclass != null) {
String superMethod = superclass + "." + methodName; String superMethod = superclass + "." + methodName;
if (graph.containsKey(superMethod)) { if (graph.containsKey(superMethod)) {
List<List<String>> superPaths = findAllPaths(superMethod, target, graph, visited, unreachable, localHitCycle, memo); List<List<String>> superPaths = findAllPaths(superMethod, target, graph, visited, localHitCycle);
for (List<String> superPath : superPaths) { for (List<String> superPath : superPaths) {
List<String> path = new ArrayList<>(); List<String> path = new ArrayList<>();
path.add(start); path.add(start);
@@ -143,7 +147,7 @@ public class CallGraphPathFinder {
for (String impl : impls) { for (String impl : impls) {
String implMethod = impl + "." + methodName; String implMethod = impl + "." + methodName;
if (graph.containsKey(implMethod)) { if (graph.containsKey(implMethod)) {
List<List<String>> implPaths = findAllPaths(implMethod, target, graph, visited, unreachable, localHitCycle, memo); List<List<String>> implPaths = findAllPaths(implMethod, target, graph, visited, localHitCycle);
for (List<String> implPath : implPaths) { for (List<String> implPath : implPaths) {
List<String> path = new ArrayList<>(); List<String> path = new ArrayList<>();
path.add(start); path.add(start);
@@ -159,13 +163,13 @@ public class CallGraphPathFinder {
if (localHitCycle[0]) { if (localHitCycle[0]) {
parentHitCycle[0] = true; parentHitCycle[0] = true;
} else if (result.isEmpty()) { } else if (result.isEmpty()) {
unreachable.add(start); unreachableCache.put(cacheKey, true);
} else { } else {
List<List<String>> toCache = new ArrayList<>(); List<List<String>> toCache = new ArrayList<>();
for (List<String> path : result) { for (List<String> path : result) {
toCache.add(new ArrayList<>(path)); toCache.add(new ArrayList<>(path));
} }
memo.put(start, toCache); memoCache.put(cacheKey, toCache);
} }
return result; return result;

View File

@@ -89,7 +89,8 @@ 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();
System.out.println("Processing mi: " + mi); if (methodName.equals("get") || methodName.equals("getOrDefault")) { log.trace("Processing mi: {}", mi);
if (methodName.equals("get") || methodName.equals("getOrDefault")) {
if (mi.getExpression() != null) { if (mi.getExpression() != null) {
if (variableTracer != null) { if (variableTracer != null) {
List<Expression> traced = variableTracer.traceVariableAll(mi.getExpression()); List<Expression> traced = variableTracer.traceVariableAll(mi.getExpression());
@@ -281,7 +282,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("ConstantExtractor.resolveMethodReturnConstant CALLED: className={}, methodName={}", className, 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);
@@ -392,7 +393,7 @@ public class ConstantExtractor {
} }
} }
visited.remove(fqn); visited.remove(fqn);
System.out.println("DEBUG resolveMethodReturnConstant className=" + className + " methodName=" + methodName + " returns: " + constants); log.debug("resolveMethodReturnConstant className={} methodName={} returns: {}", className, methodName, 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;
} }

View File

@@ -5,6 +5,9 @@ import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.eclipse.jdt.core.dom.*; import org.eclipse.jdt.core.dom.*;
import java.util.*; import java.util.*;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ConstructorAnalyzer { public class ConstructorAnalyzer {
private final CodebaseContext context; private final CodebaseContext context;
private final ConstantResolver constantResolver; private final ConstantResolver constantResolver;
@@ -591,11 +594,11 @@ public class ConstructorAnalyzer {
try { try {
Map<String, String> fieldValues = buildFieldValuesFromCIC(td, cic, context, this::evaluateMethodCallInConstructor); Map<String, String> fieldValues = buildFieldValuesFromCIC(td, cic, context, this::evaluateMethodCallInConstructor);
System.out.println("RESOLVE_GETTER: td=" + context.getFqn(td) + ", fieldValues=" + fieldValues); log.debug("RESOLVE_GETTER: td={}, fieldValues={}", context.getFqn(td), fieldValues);
if (fieldValues.isEmpty()) return Collections.emptyList(); if (fieldValues.isEmpty()) return Collections.emptyList();
String result = constantResolver.evaluateMethodBodyWithLocals(getter, fieldValues, context, visited); String result = constantResolver.evaluateMethodBodyWithLocals(getter, fieldValues, context, visited);
System.out.println("RESOLVE_GETTER: result=" + result); log.debug("RESOLVE_GETTER: result={}", result);
return result != null ? List.of(result) : Collections.emptyList(); return result != null ? List.of(result) : Collections.emptyList();
} finally { } finally {
visited.remove(getterKey); visited.remove(getterKey);

View File

@@ -185,16 +185,16 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
nameBinding = fa.resolveFieldBinding(); nameBinding = fa.resolveFieldBinding();
} }
if (nameBinding instanceof IVariableBinding varBinding) { if (nameBinding instanceof IVariableBinding varBinding) {
System.out.println("CALLGRAPH RESOLVING BEAN FOR BINDING: " + varBinding.getName() + " calling " + methodName); log.debug("CALLGRAPH RESOLVING BEAN FOR BINDING: {} calling {}", varBinding.getName(), methodName);
String concreteFqn = injectionAnalyzer.resolveInjectedBeanFqn(varBinding); String concreteFqn = injectionAnalyzer.resolveInjectedBeanFqn(varBinding);
if (concreteFqn != null) { if (concreteFqn != null) {
System.out.println(" -> RESOLVED CONCRETE FQN: " + concreteFqn); log.debug(" -> RESOLVED CONCRETE FQN: {}", concreteFqn);
return concreteFqn + "." + methodName; return concreteFqn + "." + methodName;
} else { } else {
System.out.println(" -> RESOLVE FAILED, RETURNED NULL"); log.debug(" -> RESOLVE FAILED, RETURNED NULL");
} }
} else { } else {
System.out.println("CALLGRAPH NAME BINDING IS NOT VARIABLE: " + nameBinding + " calling " + methodName); log.debug("CALLGRAPH NAME BINDING IS NOT VARIABLE: {} calling {}", nameBinding, methodName);
} }
} }

View File

@@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SpringDependencyResolver { public class SpringDependencyResolver {
private final SpringBeanRegistry registry; private final SpringBeanRegistry registry;
@@ -21,16 +24,16 @@ public class SpringDependencyResolver {
*/ */
public List<SpringBean> resolve(String requiredTypeFqn, String qualifier, String injectionName) { public List<SpringBean> resolve(String requiredTypeFqn, String qualifier, String injectionName) {
if (requiredTypeFqn == null) return new ArrayList<>(); if (requiredTypeFqn == null) return new ArrayList<>();
log.debug("RESOLVING {} qual={} injectionName={}", requiredTypeFqn, qualifier, injectionName);
// 1. Filter by Type (Exact FQN or Assignable Type) // 1. Filter by Type (Exact FQN or Assignable Type)
System.out.println("RESOLVING " + requiredTypeFqn + " qual=" + qualifier + " injectionName=" + injectionName);
List<SpringBean> candidates = registry.getBeans().stream() List<SpringBean> candidates = registry.getBeans().stream()
.filter(bean -> requiredTypeFqn.equals(bean.getTypeFqn()) || bean.getAssignableTypes().contains(requiredTypeFqn)) .filter(bean -> requiredTypeFqn.equals(bean.getTypeFqn()) || bean.getAssignableTypes().contains(requiredTypeFqn))
.collect(Collectors.toList()); .collect(Collectors.toList());
System.out.println("CANDIDATES AFTER TYPE: " + candidates.stream().map(c -> c.getTypeFqn() + " (primary=" + c.isPrimary() + " names=" + c.getBeanNames() + " qual=" + c.getQualifiers() + ")").collect(Collectors.toList())); log.debug("CANDIDATES AFTER TYPE: {}", candidates.stream().map(c -> c.getTypeFqn() + " (primary=" + c.isPrimary() + " names=" + c.getBeanNames() + " qual=" + c.getQualifiers() + ")").collect(Collectors.toList()));
if (candidates.isEmpty() || candidates.size() == 1) { if (candidates.isEmpty() || candidates.size() == 1) {
System.out.println("RETURNING: " + candidates.size()); log.debug("RETURNING: {}", candidates.size());
return candidates; return candidates;
} }
@@ -81,7 +84,7 @@ public class SpringDependencyResolver {
} }
// Return whatever candidates remain (could be ambiguous) // Return whatever candidates remain (could be ambiguous)
System.out.println("RETURNING: " + candidates.size()); log.debug("RETURNING: {}", candidates.size());
return candidates; return candidates;
} }
} }

View File

@@ -378,7 +378,7 @@ public class CodebaseContext {
String fqn = simpleNameToFqn.get(cleanName); String fqn = simpleNameToFqn.get(cleanName);
if (fqn != null) values = enumValues.get(fqn); if (fqn != null) values = enumValues.get(fqn);
} }
System.out.println("DEBUG getEnumValues called for: " + fqnOrSimpleName + " resolved to " + cleanName + ". Returns: " + values); log.debug("getEnumValues called for: {} resolved to {}. Returns: {}", fqnOrSimpleName, cleanName, values);
return values; return values;
} }

View File

@@ -3,6 +3,9 @@ package click.kamil.springstatemachineexporter.ast.common;
import org.eclipse.jdt.core.dom.*; import org.eclipse.jdt.core.dom.*;
import java.util.*; import java.util.*;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class JdtDataFlowModel implements DataFlowModel { public class JdtDataFlowModel implements DataFlowModel {
private final CodebaseContext context; private final CodebaseContext context;
private final Map<MethodDeclaration, ControlFlowGraph> cfgCache = new HashMap<>(); private final Map<MethodDeclaration, ControlFlowGraph> cfgCache = new HashMap<>();
@@ -436,7 +439,8 @@ public class JdtDataFlowModel implements DataFlowModel {
currentParamValues.put(paramVb, resolvedArg); currentParamValues.put(paramVb, resolvedArg);
} }
} }
System.out.println("EVAL_CTOR: cd=" + cd.getName() + ", currentParamValues=" + currentParamValues);
log.debug("EVAL_CTOR: cd={}, currentParamValues={}", cd.getName(), currentParamValues);
List<?> statements = cd.getBody().statements(); List<?> statements = cd.getBody().statements();
if (!statements.isEmpty()) { if (!statements.isEmpty()) {