Stop inferring machine transitions onto ambiguous triggers
Do not backfill polymorphic events from configured transitions when a trigger is ambiguous without enum-member constraints, and block symbolic inference when the symbolic type simple name is ambiguous across packages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -258,7 +258,7 @@ public final class MachineEnumCanonicalizer {
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
if (shouldInferPolymorphicEvents(expanded, machineTransitions)) {
|
||||
if (shouldInferPolymorphicEvents(expanded, machineTransitions, context)) {
|
||||
List<String> machineEvents = inferPolymorphicCandidates(
|
||||
expanded.getConstraint(),
|
||||
machineTypes.eventTypeFqn(),
|
||||
@@ -292,11 +292,15 @@ public final class MachineEnumCanonicalizer {
|
||||
|
||||
private static boolean shouldInferPolymorphicEvents(
|
||||
TriggerPoint trigger,
|
||||
List<Transition> machineTransitions) {
|
||||
List<Transition> machineTransitions,
|
||||
CodebaseContext context) {
|
||||
if (trigger == null || machineTransitions == null || machineTransitions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (hasOnlySymbolicPolymorphicEvents(trigger.getPolymorphicEvents())) {
|
||||
if (context != null && hasAmbiguousSymbolicPolymorphicType(trigger.getPolymorphicEvents(), context)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
List<String> polyEvents = trigger.getPolymorphicEvents();
|
||||
@@ -306,12 +310,32 @@ public final class MachineEnumCanonicalizer {
|
||||
if (EnumMemberPredicateEvaluator.hasEnumMemberPredicates(trigger.getConstraint())) {
|
||||
return true;
|
||||
}
|
||||
if (trigger.isExternal() || trigger.isAmbiguous()) {
|
||||
if (trigger.isExternal()) {
|
||||
return true;
|
||||
}
|
||||
if (trigger.isAmbiguous()) {
|
||||
return false;
|
||||
}
|
||||
return classifyTriggerEvent(trigger.getEvent()) == TriggerEventKind.DYNAMIC_EXPRESSION;
|
||||
}
|
||||
|
||||
private static boolean hasAmbiguousSymbolicPolymorphicType(
|
||||
List<String> polymorphicEvents,
|
||||
CodebaseContext context) {
|
||||
if (polymorphicEvents == null) {
|
||||
return false;
|
||||
}
|
||||
for (String pe : polymorphicEvents) {
|
||||
if (pe != null && pe.startsWith("<SYMBOLIC: ") && pe.endsWith(".*>")) {
|
||||
String symbolicType = pe.substring("<SYMBOLIC: ".length(), pe.length() - 3).trim();
|
||||
if (context.isAmbiguousSimpleName(symbolicType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasOnlySymbolicPolymorphicEvents(List<String> polymorphicEvents) {
|
||||
if (polymorphicEvents == null || polymorphicEvents.isEmpty()) {
|
||||
return false;
|
||||
|
||||
@@ -231,6 +231,38 @@ class MachineEnumCanonicalizerTest {
|
||||
assertThat(expanded).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotInferMachineTransitionsForAmbiguousTriggerWithoutConstraint(@TempDir Path tempDir)
|
||||
throws IOException {
|
||||
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 }");
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
|
||||
TriggerPoint trigger = TriggerPoint.builder()
|
||||
.event("OrderEvent.valueOf(eventStr)")
|
||||
.ambiguous(true)
|
||||
.polymorphicEvents(List.of())
|
||||
.build();
|
||||
StateMachineTypeResolver.MachineTypes types =
|
||||
new StateMachineTypeResolver.MachineTypes(null, "a.OrderEvent");
|
||||
|
||||
Transition pay = new Transition();
|
||||
pay.setEvent(Event.of("PAY", "a.OrderEvent.PAY"));
|
||||
pay.setSourceStates(List.of(State.of("NEW", "NEW")));
|
||||
pay.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||
|
||||
TriggerPoint enriched = MachineEnumCanonicalizer.ensureCallChainPolymorphicEvents(
|
||||
trigger, types, context, List.of(pay), true);
|
||||
|
||||
assertThat(enriched.getPolymorphicEvents()).isNullOrEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldValidateRawNameConsistencyForCanonicalHelpers() {
|
||||
assertThat(MachineEnumCanonicalizer.isRawNameConsistentWithFullIdentifier(
|
||||
|
||||
Reference in New Issue
Block a user