fix attempt 1
This commit is contained in:
3
TODO.md
3
TODO.md
@@ -1,10 +1,9 @@
|
|||||||
1.extract from all possible formats (ask chatgpt)
|
1.extract from all possible formats (ask chatgpt)
|
||||||
|
|
||||||
[DONE] json
|
|
||||||
[TODO] xml, maybe yaml
|
[TODO] xml, maybe yaml
|
||||||
|
|
||||||
2. [PLAN] Support external dependencies (JARs/compiled classes):
|
2. [PLAN] Support external dependencies (JARs/compiled classes):
|
||||||
- Enable binding resolution in ASTParser (`setResolveBindings(true)`).
|
- Enable binding resolution in ASTParser (`setResolveBindings(true)`).
|
||||||
- Configure ASTParser with project classpath (including JARs).
|
- Configure ASTParser with project classpath (including JARs).
|
||||||
- Refactor `CodebaseContext` to handle resolved bindings, not just local AST nodes.
|
- Refactor `CodebaseContext` to handle resolved bindings, not just local AST nodes.
|
||||||
- Implement tests using external libraries as base classes.
|
- Implement tests using external libraries as base classes.
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
|
|||||||
|
|
||||||
boolean isWildcard = triggerEvent.equals("event") || triggerEvent.equals("e") ||
|
boolean isWildcard = triggerEvent.equals("event") || triggerEvent.equals("e") ||
|
||||||
triggerEvent.equals("msg") || triggerEvent.equals("message") ||
|
triggerEvent.equals("msg") || triggerEvent.equals("message") ||
|
||||||
triggerEvent.equals("payload") || triggerEvent.matches(".*\\.get[A-Z].*\\(\\)");
|
triggerEvent.equals("payload") || triggerEvent.matches(".*\\.getType\\(\\)");
|
||||||
|
|
||||||
if (isWildcard) {
|
if (isWildcard) {
|
||||||
String targetVar = chain.getContextMachineId();
|
String targetVar = chain.getContextMachineId();
|
||||||
|
|||||||
@@ -541,9 +541,11 @@ public class CallGraphBuilder {
|
|||||||
expr = tracedExpr; // Only accept trace if it resolves to a pure constant/primitive/constructor
|
expr = tracedExpr; // Only accept trace if it resolves to a pure constant/primitive/constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr instanceof ClassInstanceCreation cic) {
|
if (expr instanceof ClassInstanceCreation cic && !cic.arguments().isEmpty()) {
|
||||||
if (!cic.arguments().isEmpty()) {
|
Expression firstArg = (Expression) cic.arguments().get(0);
|
||||||
expr = (Expression) cic.arguments().get(0);
|
String resolved = constantResolver.resolve(firstArg, context);
|
||||||
|
if (resolved != null) {
|
||||||
|
expr = firstArg; // Only unwrap if it's actually a constant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,30 @@ class TransitionLinkerEnricherTest {
|
|||||||
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
|
assertThat(updatedChain.getMatchedTransitions()).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotMatchArbitraryGetXMethodWildcard() {
|
||||||
|
Transition t1 = new Transition();
|
||||||
|
t1.setSourceStates(List.of(State.of("NEW", "NEW")));
|
||||||
|
t1.setTargetStates(List.of(State.of("PAID", "PAID")));
|
||||||
|
t1.setEvent(Event.of("PAY", "PAY"));
|
||||||
|
|
||||||
|
CallChain chain = CallChain.builder()
|
||||||
|
.triggerPoint(TriggerPoint.builder().event("richEvent.getId()").build())
|
||||||
|
.contextMachineId("testMachine")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
AnalysisResult result = AnalysisResult.builder()
|
||||||
|
.name("testMachine")
|
||||||
|
.transitions(List.of(t1))
|
||||||
|
.metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
enricher.enrich(result, null, null);
|
||||||
|
|
||||||
|
CallChain updatedChain = result.getMetadata().getCallChains().get(0);
|
||||||
|
assertThat(updatedChain.getMatchedTransitions()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldAllowWildcardWhenContextMachineIdIsMissing() {
|
void shouldAllowWildcardWhenContextMachineIdIsMissing() {
|
||||||
Transition t1 = new Transition();
|
Transition t1 = new Transition();
|
||||||
|
|||||||
@@ -954,4 +954,131 @@ class CallGraphBuilderTest {
|
|||||||
// It returns the array access expression as a string.
|
// It returns the array access expression as a string.
|
||||||
assertThat(chain.getTriggerPoint().getEvent()).isEqualTo("events[0]");
|
assertThat(chain.getTriggerPoint().getEvent()).isEqualTo("events[0]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldProperlyUnwrapDeeplyNestedWrapperCallsForFix1() throws IOException {
|
||||||
|
String source = """
|
||||||
|
package com.example;
|
||||||
|
public class OrderController {
|
||||||
|
private OrderService service;
|
||||||
|
public void processOrderEvent(MyEvent event) {
|
||||||
|
OrderEvents eventType = wrap1(wrap2(wrap3(event.getType())));
|
||||||
|
service.updateOrderState(eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderEvents wrap1(OrderEvents e) { return e; }
|
||||||
|
private OrderEvents wrap2(OrderEvents e) { return e; }
|
||||||
|
private OrderEvents wrap3(OrderEvents e) { return e; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class OrderService {
|
||||||
|
public void updateOrderState(OrderEvents event) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyEvent {
|
||||||
|
public OrderEvents getType() { return OrderEvents.CREATE; }
|
||||||
|
}
|
||||||
|
enum OrderEvents { CREATE }
|
||||||
|
""";
|
||||||
|
Path tempDir = Files.createTempDirectory("callgraph_nested_wrap");
|
||||||
|
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
CallGraphBuilder builder = new CallGraphBuilder(context);
|
||||||
|
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder().className("com.example.OrderController").methodName("processOrderEvent").build();
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder().className("com.example.OrderService").methodName("updateOrderState").event("event").build();
|
||||||
|
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||||
|
assertThat(chains).hasSize(1);
|
||||||
|
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).containsExactlyInAnyOrder("OrderEvents.CREATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotExtractClassInstanceCreationEvenWithComplexArgsForFix2() throws IOException {
|
||||||
|
String source = """
|
||||||
|
package com.example;
|
||||||
|
public class OrderController {
|
||||||
|
private OrderService service;
|
||||||
|
public void createOrder(String oID) {
|
||||||
|
service.processOrderEvent(new OrderCancelledEvent(new OrderId(oID)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class OrderService {
|
||||||
|
public void processOrderEvent(OrderCancelledEvent event) { }
|
||||||
|
}
|
||||||
|
class OrderCancelledEvent {
|
||||||
|
public OrderCancelledEvent(OrderId id) {}
|
||||||
|
}
|
||||||
|
class OrderId {
|
||||||
|
public OrderId(String id) {}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Path tempDir = Files.createTempDirectory("callgraph_complex_cic");
|
||||||
|
Files.writeString(tempDir.resolve("OrderConfig.java"), source);
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
CallGraphBuilder builder = new CallGraphBuilder(context);
|
||||||
|
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder().className("com.example.OrderController").methodName("createOrder").build();
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder().className("com.example.OrderService").methodName("processOrderEvent").event("event").build();
|
||||||
|
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||||
|
assertThat(chains).hasSize(1);
|
||||||
|
assertThat(chains.get(0).getTriggerPoint().getEvent()).isEqualTo("new OrderCancelledEvent(new OrderId(oID))");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveMethodReturnConstantFromMultiplePackagesForFix3() throws IOException {
|
||||||
|
String source1 = """
|
||||||
|
package com.example.api;
|
||||||
|
public interface RichEvent {
|
||||||
|
String getType();
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
String source2 = """
|
||||||
|
package com.example.impl.a;
|
||||||
|
import com.example.api.RichEvent;
|
||||||
|
public class EventA implements RichEvent {
|
||||||
|
public String getType() { return "EVENT_A"; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
String source3 = """
|
||||||
|
package com.example.impl.b;
|
||||||
|
import com.example.api.RichEvent;
|
||||||
|
public class EventB implements RichEvent {
|
||||||
|
public String getType() { return "EVENT_B"; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
String source4 = """
|
||||||
|
package com.example.controller;
|
||||||
|
import com.example.api.RichEvent;
|
||||||
|
public class EventController {
|
||||||
|
private com.example.service.EventService service;
|
||||||
|
public void handleEvent(RichEvent event) {
|
||||||
|
service.process(event.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
String source5 = """
|
||||||
|
package com.example.service;
|
||||||
|
public class EventService {
|
||||||
|
public void process(String type) {}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Path tempDir = Files.createTempDirectory("callgraph_multi_pkg");
|
||||||
|
Files.writeString(tempDir.resolve("RichEvent.java"), source1);
|
||||||
|
Files.writeString(tempDir.resolve("EventA.java"), source2);
|
||||||
|
Files.writeString(tempDir.resolve("EventB.java"), source3);
|
||||||
|
Files.writeString(tempDir.resolve("EventController.java"), source4);
|
||||||
|
Files.writeString(tempDir.resolve("EventService.java"), source5);
|
||||||
|
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
CallGraphBuilder builder = new CallGraphBuilder(context);
|
||||||
|
|
||||||
|
EntryPoint entryPoint = EntryPoint.builder().className("com.example.controller.EventController").methodName("handleEvent").build();
|
||||||
|
TriggerPoint trigger = TriggerPoint.builder().className("com.example.service.EventService").methodName("process").event("type").build();
|
||||||
|
List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));
|
||||||
|
assertThat(chains).hasSize(1);
|
||||||
|
assertThat(chains.get(0).getTriggerPoint().getPolymorphicEvents()).containsExactlyInAnyOrder("EVENT_A", "EVENT_B");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user