Fix abstract getter widening and nested reactive flatMap resolution.
Ensure abstract-type getter resolution merges subclass field values and trace indexed accessors on the requesting type, and extract terminal payloads from chained flatMap sendEvent calls. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -43,6 +43,8 @@ class AccessorPipelineBugFixTest {
|
||||
variableTracer = new VariableTracer(context, constantResolver);
|
||||
constantExtractor.setVariableTracer(variableTracer);
|
||||
constantExtractor.setConstructorAnalyzer(constructorAnalyzer);
|
||||
constructorAnalyzer.setVariableTracer(variableTracer);
|
||||
constructorAnalyzer.setConstantExtractor(constantExtractor);
|
||||
accessorResolver = new AccessorResolver(context, constantExtractor, constructorAnalyzer, constantResolver);
|
||||
constantExtractor.setAccessorResolver(accessorResolver);
|
||||
}
|
||||
@@ -118,6 +120,37 @@ class AccessorPipelineBugFixTest {
|
||||
|
||||
assertThat(resolved).containsExactlyInAnyOrder("Code.A", "Code.B");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWidenToImplsEvenWhenAbstractFieldHasInlineInitializer() throws IOException {
|
||||
writeJava("com/example/Code.java", """
|
||||
package com.example;
|
||||
public enum Code { PAY, SHIP }
|
||||
""");
|
||||
writeJava("com/example/BaseEvent.java", """
|
||||
package com.example;
|
||||
public abstract class BaseEvent {
|
||||
protected Code code = Code.PAY;
|
||||
public Code getCode() { return code; }
|
||||
}
|
||||
""");
|
||||
writeJava("com/example/DefaultEvent.java", """
|
||||
package com.example;
|
||||
public class DefaultEvent extends BaseEvent {}
|
||||
""");
|
||||
writeJava("com/example/ShipEvent.java", """
|
||||
package com.example;
|
||||
public class ShipEvent extends BaseEvent {
|
||||
public ShipEvent() { this.code = Code.SHIP; }
|
||||
}
|
||||
""");
|
||||
scanWorkspace();
|
||||
|
||||
List<String> resolved = constantExtractor.resolveMethodReturnConstant(
|
||||
"com.example.BaseEvent", "getCode", 0, new HashSet<>(), null);
|
||||
|
||||
assertThat(resolved).containsExactlyInAnyOrder("Code.PAY", "Code.SHIP");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -1037,6 +1037,42 @@ class HeuristicCallGraphEngineCoreTest {
|
||||
org.assertj.core.api.Assertions.assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).containsExactlyInAnyOrder("REACTIVE_EVENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveEventFromNestedReactiveFlatMap(@TempDir Path tempDir) throws IOException {
|
||||
String source = """
|
||||
package com.example;
|
||||
public class OrderController {
|
||||
private StateMachine stateMachine;
|
||||
public void handleReactive() {
|
||||
Mono.just("IGNORED")
|
||||
.flatMap(x -> Mono.just("NESTED_REACTIVE_EVENT"))
|
||||
.flatMap(stateMachine::sendEvent);
|
||||
}
|
||||
}
|
||||
|
||||
class StateMachine {
|
||||
public void sendEvent(String event) {}
|
||||
}
|
||||
|
||||
class Mono {
|
||||
public static Mono just(Object obj) { return new Mono(); }
|
||||
public Mono flatMap(Object mapper) { return this; }
|
||||
}
|
||||
""";
|
||||
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.scan(tempDir);
|
||||
HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);
|
||||
|
||||
EntryPoint entryPoint = EntryPoint.builder().className("com.example.OrderController").methodName("handleReactive").build();
|
||||
TriggerPoint trigger = TriggerPoint.builder().className("com.example.StateMachine").methodName("sendEvent").event("event").build();
|
||||
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||
|
||||
org.assertj.core.api.Assertions.assertThat(chains).hasSize(1);
|
||||
org.assertj.core.api.Assertions.assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents())
|
||||
.containsExactlyInAnyOrder("NESTED_REACTIVE_EVENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExtractEventFromSwitchExpressionAndParentheses(@TempDir Path tempDir) throws IOException {
|
||||
String source = """
|
||||
|
||||
Reference in New Issue
Block a user