Thread context through link policy and symbolic enum expansion
Use machine event type and CodebaseContext for trusted valueOf widen checks and resolveLinkResolution, and apply context-aware enum type matching when expanding symbolic polymorphic placeholders. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,12 +20,19 @@ public final class CallChainLinkPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldFailClosedOnAmbiguousCallGraphWiden(TriggerPoint trigger) {
|
public static boolean shouldFailClosedOnAmbiguousCallGraphWiden(TriggerPoint trigger) {
|
||||||
return shouldFailClosedOnAmbiguousCallGraphWiden(trigger, null);
|
return shouldFailClosedOnAmbiguousCallGraphWiden(trigger, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldFailClosedOnAmbiguousCallGraphWiden(
|
public static boolean shouldFailClosedOnAmbiguousCallGraphWiden(
|
||||||
TriggerPoint trigger,
|
TriggerPoint trigger,
|
||||||
String machineEventTypeFqn) {
|
String machineEventTypeFqn) {
|
||||||
|
return shouldFailClosedOnAmbiguousCallGraphWiden(trigger, machineEventTypeFqn, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldFailClosedOnAmbiguousCallGraphWiden(
|
||||||
|
TriggerPoint trigger,
|
||||||
|
String machineEventTypeFqn,
|
||||||
|
CodebaseContext context) {
|
||||||
if (trigger == null || trigger.isExternal() || !trigger.isAmbiguous()) {
|
if (trigger == null || trigger.isExternal() || !trigger.isAmbiguous()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -39,7 +46,7 @@ public final class CallChainLinkPolicy {
|
|||||||
}
|
}
|
||||||
if (event != null && event.contains(".valueOf(")) {
|
if (event != null && event.contains(".valueOf(")) {
|
||||||
return MachineEnumCanonicalizer.isDynamicTriggerExpression(event)
|
return MachineEnumCanonicalizer.isDynamicTriggerExpression(event)
|
||||||
&& !isTrustedEnumPolymorphicWiden(trigger, machineEventTypeFqn);
|
&& !isTrustedEnumPolymorphicWiden(trigger, machineEventTypeFqn, context);
|
||||||
}
|
}
|
||||||
return MachineEnumCanonicalizer.isDynamicTriggerExpression(event)
|
return MachineEnumCanonicalizer.isDynamicTriggerExpression(event)
|
||||||
&& event != null;
|
&& event != null;
|
||||||
@@ -51,10 +58,17 @@ public final class CallChainLinkPolicy {
|
|||||||
* cross-package or unqualified widens.
|
* cross-package or unqualified widens.
|
||||||
*/
|
*/
|
||||||
static boolean isTrustedEnumPolymorphicWiden(TriggerPoint trigger) {
|
static boolean isTrustedEnumPolymorphicWiden(TriggerPoint trigger) {
|
||||||
return isTrustedEnumPolymorphicWiden(trigger, null);
|
return isTrustedEnumPolymorphicWiden(trigger, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isTrustedEnumPolymorphicWiden(TriggerPoint trigger, String machineEventTypeFqn) {
|
static boolean isTrustedEnumPolymorphicWiden(TriggerPoint trigger, String machineEventTypeFqn) {
|
||||||
|
return isTrustedEnumPolymorphicWiden(trigger, machineEventTypeFqn, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isTrustedEnumPolymorphicWiden(
|
||||||
|
TriggerPoint trigger,
|
||||||
|
String machineEventTypeFqn,
|
||||||
|
CodebaseContext context) {
|
||||||
if (trigger == null) {
|
if (trigger == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -75,7 +89,7 @@ public final class CallChainLinkPolicy {
|
|||||||
}
|
}
|
||||||
String enumType = pe.substring(0, pe.lastIndexOf('.'));
|
String enumType = pe.substring(0, pe.lastIndexOf('.'));
|
||||||
if (!enumType.contains(".")
|
if (!enumType.contains(".")
|
||||||
|| !MachineEnumCanonicalizer.enumTypesMatch(eventTypeFqn, enumType)) {
|
|| !MachineEnumCanonicalizer.enumTypesMatch(eventTypeFqn, enumType, context)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,12 +100,29 @@ public final class CallChainLinkPolicy {
|
|||||||
TriggerPoint trigger,
|
TriggerPoint trigger,
|
||||||
List<MatchedTransition> matched,
|
List<MatchedTransition> matched,
|
||||||
boolean ambiguousSource) {
|
boolean ambiguousSource) {
|
||||||
|
return resolveLinkResolution(trigger, matched, ambiguousSource, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkResolution resolveLinkResolution(
|
||||||
|
TriggerPoint trigger,
|
||||||
|
List<MatchedTransition> matched,
|
||||||
|
boolean ambiguousSource,
|
||||||
|
String machineEventTypeFqn) {
|
||||||
|
return resolveLinkResolution(trigger, matched, ambiguousSource, machineEventTypeFqn, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkResolution resolveLinkResolution(
|
||||||
|
TriggerPoint trigger,
|
||||||
|
List<MatchedTransition> matched,
|
||||||
|
boolean ambiguousSource,
|
||||||
|
String machineEventTypeFqn,
|
||||||
|
CodebaseContext context) {
|
||||||
if (trigger != null && trigger.isExternal()) {
|
if (trigger != null && trigger.isExternal()) {
|
||||||
return LinkResolution.UNRESOLVED_EXTERNAL;
|
return LinkResolution.UNRESOLVED_EXTERNAL;
|
||||||
}
|
}
|
||||||
if (ambiguousSource
|
if (ambiguousSource
|
||||||
|| (trigger != null && trigger.isAmbiguous())
|
|| (trigger != null && trigger.isAmbiguous())
|
||||||
|| shouldFailClosedOnAmbiguousCallGraphWiden(trigger)) {
|
|| shouldFailClosedOnAmbiguousCallGraphWiden(trigger, machineEventTypeFqn, context)) {
|
||||||
return LinkResolution.AMBIGUOUS_WIDEN;
|
return LinkResolution.AMBIGUOUS_WIDEN;
|
||||||
}
|
}
|
||||||
if (matched != null && !matched.isEmpty()) {
|
if (matched != null && !matched.isEmpty()) {
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
|||||||
|
|
||||||
String triggerSource = tp.getSourceState() != null ? simplifySourceState(tp.getSourceState()) : null;
|
String triggerSource = tp.getSourceState() != null ? simplifySourceState(tp.getSourceState()) : null;
|
||||||
if (CallChainLinkPolicy.shouldFailClosedOnAmbiguousCallGraphWiden(
|
if (CallChainLinkPolicy.shouldFailClosedOnAmbiguousCallGraphWiden(
|
||||||
tp, machineTypes != null ? machineTypes.eventTypeFqn() : null)) {
|
tp,
|
||||||
|
machineTypes != null ? machineTypes.eventTypeFqn() : null,
|
||||||
|
context)) {
|
||||||
updatedChains.add(chain.toBuilder()
|
updatedChains.add(chain.toBuilder()
|
||||||
.triggerPoint(tp)
|
.triggerPoint(tp)
|
||||||
.matchedTransitions(null)
|
.matchedTransitions(null)
|
||||||
@@ -155,7 +157,12 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
|||||||
tp = tp.toBuilder().ambiguous(true).build();
|
tp = tp.toBuilder().ambiguous(true).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkResolution linkResolution = CallChainLinkPolicy.resolveLinkResolution(tp, matched, ambiguousSource);
|
LinkResolution linkResolution = CallChainLinkPolicy.resolveLinkResolution(
|
||||||
|
tp,
|
||||||
|
matched,
|
||||||
|
ambiguousSource,
|
||||||
|
machineTypes != null ? machineTypes.eventTypeFqn() : null,
|
||||||
|
context);
|
||||||
|
|
||||||
if (!matched.isEmpty()) {
|
if (!matched.isEmpty()) {
|
||||||
CallChain newChain = chain.toBuilder()
|
CallChain newChain = chain.toBuilder()
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public final class MachineEnumCanonicalizer {
|
|||||||
if (context != null && context.isAmbiguousSimpleName(symbolicType)) {
|
if (context != null && context.isAmbiguousSimpleName(symbolicType)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!enumTypesMatch(machineEventTypeFqn, symbolicType)) {
|
if (!enumTypesMatch(machineEventTypeFqn, symbolicType, context)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (transitionEvents.size() == 1) {
|
if (transitionEvents.size() == 1) {
|
||||||
|
|||||||
@@ -74,6 +74,23 @@ class CallChainLinkPolicyTest {
|
|||||||
trigger, "com.example.OrderEvent")).isFalse();
|
trigger, "com.example.OrderEvent")).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveLinkWhenTrustedWidenPassesUsingMachineEventType() {
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder()
|
||||||
|
.ambiguous(false)
|
||||||
|
.event("OrderEvent.valueOf(eventStr)")
|
||||||
|
.polymorphicEvents(List.of("com.example.OrderEvent.PAY", "com.example.OrderEvent.SHIP"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(CallChainLinkPolicy.resolveLinkResolution(
|
||||||
|
trigger,
|
||||||
|
List.of(),
|
||||||
|
false,
|
||||||
|
"com.example.OrderEvent")).isEqualTo(LinkResolution.NO_MATCH);
|
||||||
|
assertThat(CallChainLinkPolicy.shouldFailClosedOnAmbiguousCallGraphWiden(
|
||||||
|
trigger, "com.example.OrderEvent")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldNotTrustImportStylePolymorphicWidenWithoutPackage() {
|
void shouldNotTrustImportStylePolymorphicWidenWithoutPackage() {
|
||||||
TriggerPoint trigger = TriggerPoint.builder()
|
TriggerPoint trigger = TriggerPoint.builder()
|
||||||
|
|||||||
Reference in New Issue
Block a user