Fail closed on cross-package enum switch constraints
Switch-arm equality now requires compatible enum types when both sides are package-qualified, while still accepting import-style vs FQN pairs like DomainCommand.ORDER_PAY. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -169,7 +169,6 @@ public final class BooleanConstraintEvaluator {
|
||||
if (cleanValue.startsWith("\"") && cleanValue.endsWith("\"")) {
|
||||
cleanValue = cleanValue.substring(1, cleanValue.length() - 1);
|
||||
}
|
||||
String suffix = cleanValue.contains(".") ? cleanValue.substring(cleanValue.lastIndexOf('.') + 1) : cleanValue;
|
||||
|
||||
Pattern eqPattern = Pattern.compile(
|
||||
"(?i)" + Pattern.quote(varName) + "\\s*==\\s*([\\w.\"']+)");
|
||||
@@ -177,10 +176,7 @@ public final class BooleanConstraintEvaluator {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
String rhs = matcher.group(1).replace("\"", "").replace("'", "");
|
||||
boolean matches = cleanValue.equals(rhs)
|
||||
|| cleanValue.endsWith("." + rhs)
|
||||
|| suffix.equalsIgnoreCase(rhs)
|
||||
|| cleanValue.equalsIgnoreCase(rhs);
|
||||
boolean matches = constraintValuesMatch(cleanValue, rhs);
|
||||
matcher.appendReplacement(sb, matches ? "true" : "false");
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
@@ -191,6 +187,72 @@ public final class BooleanConstraintEvaluator {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean constraintValuesMatch(String boundValue, String rhs) {
|
||||
if (boundValue == null || rhs == null) {
|
||||
return false;
|
||||
}
|
||||
String bound = stripOuterQuotes(boundValue);
|
||||
String rhsClean = stripOuterQuotes(rhs);
|
||||
if (bound.equals(rhsClean) || bound.equalsIgnoreCase(rhsClean)) {
|
||||
return true;
|
||||
}
|
||||
if (bound.endsWith("." + rhsClean) || rhsClean.endsWith("." + bound)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String boundConstant = enumConstantName(bound);
|
||||
String rhsConstant = enumConstantName(rhsClean);
|
||||
if (!boundConstant.equalsIgnoreCase(rhsConstant)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String boundType = enumTypePart(bound);
|
||||
String rhsType = enumTypePart(rhsClean);
|
||||
if (boundType == null || rhsType == null) {
|
||||
return true;
|
||||
}
|
||||
if (boundType.equals(rhsType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String boundSimple = simpleTypeName(boundType);
|
||||
String rhsSimple = simpleTypeName(rhsType);
|
||||
if (!boundSimple.equals(rhsSimple)) {
|
||||
return false;
|
||||
}
|
||||
boolean boundImportStyle = !boundType.contains(".");
|
||||
boolean rhsImportStyle = !rhsType.contains(".");
|
||||
return boundImportStyle || rhsImportStyle;
|
||||
}
|
||||
|
||||
private static String stripOuterQuotes(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value.length() >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String enumConstantName(String ref) {
|
||||
int dot = ref.lastIndexOf('.');
|
||||
return dot >= 0 ? ref.substring(dot + 1) : ref;
|
||||
}
|
||||
|
||||
private static String enumTypePart(String ref) {
|
||||
int dot = ref.lastIndexOf('.');
|
||||
if (dot <= 0) {
|
||||
return null;
|
||||
}
|
||||
return ref.substring(0, dot);
|
||||
}
|
||||
|
||||
private static String simpleTypeName(String typePart) {
|
||||
int dot = typePart.lastIndexOf('.');
|
||||
return dot >= 0 ? typePart.substring(dot + 1) : typePart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true}/{@code false} when both sides are compile-time string literals; otherwise {@code null}.
|
||||
*/
|
||||
|
||||
@@ -29,6 +29,20 @@ class BooleanConstraintEvaluatorBindingsTest {
|
||||
Map.of("commandKey", "order.pay"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectCrossPackageQualifiedEnumSwitchConstraint() {
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(
|
||||
"command == a.OrderEvent.PAY",
|
||||
Map.of("command", "b.OrderEvent.PAY"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAcceptPackageQualifiedRhsAgainstImportStyleBinding() {
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(
|
||||
"command == com.example.DomainCommand.ORDER_PAY",
|
||||
Map.of("command", "DomainCommand.ORDER_PAY"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectConstraintWhenBindingIsMissing() {
|
||||
assertThat(BooleanConstraintEvaluator.isCompatibleWithBindings(
|
||||
|
||||
Reference in New Issue
Block a user