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 d819190..766bd61 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 @@ -2913,21 +2913,6 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine { if ((enumValues == null || enumValues.isEmpty()) && declaredType.contains(".")) { enumValues = context.getEnumValues(declaredType.substring(declaredType.lastIndexOf('.') + 1)); } - if ((enumValues == null || enumValues.isEmpty())) { - String simpleDeclared = declaredType.contains(".") - ? declaredType.substring(declaredType.lastIndexOf('.') + 1) - : declaredType; - for (Map.Entry> entry : context.getEnumValuesMap().entrySet()) { - String enumType = entry.getKey(); - String simpleType = enumType.contains(".") - ? enumType.substring(enumType.lastIndexOf('.') + 1) - : enumType; - if (simpleDeclared.equals(simpleType)) { - enumValues = entry.getValue(); - break; - } - } - } if (enumValues == null || enumValues.isEmpty()) { return List.of(); } diff --git a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/AmbiguousSimpleEnumLinkingTest.java b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/AmbiguousSimpleEnumLinkingTest.java index c8a5eee..5800b09 100644 --- a/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/AmbiguousSimpleEnumLinkingTest.java +++ b/state_machine_exporter/src/test/java/click/kamil/springstatemachineexporter/analysis/service/AmbiguousSimpleEnumLinkingTest.java @@ -93,5 +93,69 @@ class AmbiguousSimpleEnumLinkingTest { assertThat(linked.getMatchedTransitions()).isNullOrEmpty(); assertThat(linked.getLinkResolution()).isIn(LinkResolution.NO_MATCH, LinkResolution.AMBIGUOUS_WIDEN); } + + @Test + void shouldFailClosedWhenEnumExpansionHintUsesAmbiguousSimpleName(@TempDir Path tempDir) throws Exception { + Files.createDirectories(tempDir.resolve("a")); + Files.createDirectories(tempDir.resolve("b")); + Files.writeString(tempDir.resolve("a/OrderEvent.java"), + "package a; public enum OrderEvent { PAY, SHIP }"); + Files.writeString(tempDir.resolve("b/OrderEvent.java"), + "package b; public enum OrderEvent { CANCEL }"); + Files.writeString(tempDir.resolve("App.java"), """ + package com.example; + import a.OrderEvent; + public class OrderController { + Dispatcher dispatcher = new Dispatcher(); + public void transition(String eventStr) { + dispatcher.dispatch(eventStr); + } + } + class Dispatcher { + void dispatch(String eventStr) { + StateMachine sm = new StateMachine(); + sm.sendEvent(OrderEvent.valueOf(normalize(eventStr))); + } + String normalize(String value) { + return value.trim().toUpperCase(); + } + } + class StateMachine { void sendEvent(OrderEvent e) {} } + """); + + CodebaseContext context = new CodebaseContext(); + context.setResolveBindings(false); + context.scan(tempDir); + + HeuristicCallGraphEngine engine = new HeuristicCallGraphEngine(context); + EntryPoint entry = EntryPoint.builder() + .className("com.example.OrderController") + .methodName("transition") + .build(); + TriggerPoint trigger = TriggerPoint.builder() + .className("com.example.StateMachine") + .methodName("sendEvent") + .event("e") + .build(); + + CallChain chain = engine.findChains(List.of(entry), List.of(trigger)).get(0); + + Transition pay = new Transition(); + pay.setSourceStates(List.of(State.of("NEW", "NEW"))); + pay.setTargetStates(List.of(State.of("PAID", "PAID"))); + pay.setEvent(Event.of("PAY", "a.OrderEvent.PAY")); + + AnalysisResult result = AnalysisResult.builder() + .name("com.example.OrderStateMachineConfig") + .transitions(List.of(pay)) + .metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build()) + .build(); + + new TransitionLinkerEnricher().enrich(result, context, null); + + CallChain linked = result.getMetadata().getCallChains().get(0); + assertThat(linked.getMatchedTransitions()).isNullOrEmpty(); + assertThat(linked.getLinkResolution()).isIn(LinkResolution.NO_MATCH, LinkResolution.AMBIGUOUS_WIDEN); + } }