diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainEnricher.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainEnricher.java index cee74f7..22a914c 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainEnricher.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/enricher/CallChainEnricher.java @@ -1,5 +1,6 @@ package click.kamil.springstatemachineexporter.analysis.enricher; +import click.kamil.springstatemachineexporter.analysis.enricher.MachineScopeFilter; import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult; import click.kamil.springstatemachineexporter.analysis.model.CallChain; import click.kamil.springstatemachineexporter.analysis.model.CodebaseMetadata; @@ -26,10 +27,12 @@ public class CallChainEnricher implements AnalysisEnricher { List canonicalTriggers = intelligence.findTriggerPoints().stream() .map(trigger -> MachineEnumCanonicalizer.canonicalizeTriggerPoint(trigger, machineTypes)) .collect(Collectors.toList()); + List scopedTriggers = MachineScopeFilter.filterTriggersForMachine( + canonicalTriggers, result.getName(), context); List chains = intelligence.findCallChains( result.getMetadata().getEntryPoints(), - canonicalTriggers + scopedTriggers ); chains = chains.stream() .map(chain -> chain.getTriggerPoint() == null diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java index 51e69af..1f1fb70 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/AbstractCallGraphEngine.java @@ -104,6 +104,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine { polymorphicCallCache.clear(); context.clearAnalysisCaches(); pathFinder.clearAnalysisCaches(); + pathBindingEvaluator.clearAnalysisCaches(); parsedNodeCache.clear(); Map> callGraph = buildCallGraph(); List chains = new ArrayList<>(); diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java index b7b3cb8..b4c29db 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/ConstantExtractor.java @@ -305,19 +305,26 @@ public class ConstantExtractor { CompilationUnit contextCu, ResolutionBudget budget, boolean allowWidenToImplementations) { - log.debug("ConstantExtractor.resolveMethodReturnConstant CALLED: className={}, methodName={}", className, methodName); - log.debug("Entering resolveMethodReturnConstant with className={}, methodName={}, depth={}", className, methodName, depth); + final boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug("ConstantExtractor.resolveMethodReturnConstant CALLED: className={}, methodName={}", className, methodName); + log.debug("Entering resolveMethodReturnConstant with className={}, methodName={}, depth={}", className, methodName, depth); + } if (budget == null) { budget = ResolutionBudget.defaults(); } final ResolutionBudget activeBudget = budget; if (activeBudget.isMethodReturnExhausted(depth)) { - log.debug("Exiting resolveMethodReturnConstant early (depth limit) for {}.{}", className, methodName); + if (debug) { + log.debug("Exiting resolveMethodReturnConstant early (depth limit) for {}.{}", className, methodName); + } return Collections.emptyList(); } String fqn = className + "." + methodName; if (!visited.add(fqn)) { - log.debug("Exiting resolveMethodReturnConstant early (cycle detected) for fqn={}", fqn); + if (debug) { + log.debug("Exiting resolveMethodReturnConstant early (cycle detected) for fqn={}", fqn); + } return Collections.emptyList(); } @@ -483,8 +490,9 @@ public class ConstantExtractor { } } visited.remove(fqn); - log.debug("resolveMethodReturnConstant className={} methodName={} returns: {}", className, methodName, constants); - log.debug("resolveMethodReturnConstant for class={}, method={} resolved constants: {}", className, methodName, constants); + if (debug) { + log.debug("resolveMethodReturnConstant className={} methodName={} returns: {}", className, methodName, constants); + } return constants; } diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java index 3895673..dfc14e4 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/analysis/service/PathBindingEvaluator.java @@ -9,6 +9,7 @@ import org.eclipse.jdt.core.dom.*; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.StringJoiner; /** * Walks a call path forward, propagating known parameter / local bindings so switch-case @@ -20,6 +21,7 @@ public class PathBindingEvaluator { private final VariableTracer variableTracer; private final ConstantResolver constantResolver; private final TypeResolver typeResolver; + private final Map> traceBindingsCache = new HashMap<>(); public PathBindingEvaluator( CodebaseContext context, @@ -34,10 +36,26 @@ public class PathBindingEvaluator { /** Visible for tests: bindings accumulated while walking a path forward (ignores constraint rejection). */ Map traceBindings(List path, Map> callGraph, CallGraphPathFinder pathFinder) { - Map bindings = new HashMap<>(); if (path == null || path.size() < 2) { - return bindings; + return Map.of(); } + String cacheKey = pathCacheKey(path); + Map cached = traceBindingsCache.get(cacheKey); + if (cached != null) { + return new HashMap<>(cached); + } + Map bindings = computeTraceBindings(path, callGraph, pathFinder); + traceBindingsCache.put(cacheKey, Map.copyOf(bindings)); + return new HashMap<>(bindings); + } + + public void clearAnalysisCaches() { + traceBindingsCache.clear(); + } + + private Map computeTraceBindings( + List path, Map> callGraph, CallGraphPathFinder pathFinder) { + Map bindings = new HashMap<>(); for (int i = 0; i < path.size() - 1; i++) { String caller = path.get(i); String target = path.get(i + 1); @@ -50,6 +68,14 @@ public class PathBindingEvaluator { return bindings; } + private static String pathCacheKey(List path) { + StringJoiner joiner = new StringJoiner("\0"); + for (String hop : path) { + joiner.add(hop); + } + return joiner.toString(); + } + public boolean isPathCompatible( List path, Map> callGraph,