test1
This commit is contained in:
@@ -54,6 +54,30 @@ public class ConstantResolver {
|
|||||||
return resolveManual(sn, context, visited);
|
return resolveManual(sn, context, visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expr instanceof MethodInvocation mi) {
|
||||||
|
IMethodBinding mb = mi.resolveMethodBinding();
|
||||||
|
if (mb != null) {
|
||||||
|
ITypeBinding returnType = mb.getReturnType();
|
||||||
|
if (returnType != null) {
|
||||||
|
java.util.List<String> values = context.getEnumValues(returnType.getQualifiedName());
|
||||||
|
if (values != null && !values.isEmpty()) {
|
||||||
|
return "ENUM_SET:" + String.join(",", values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TypeDeclaration td = findEnclosingType(mi);
|
||||||
|
if (td != null) {
|
||||||
|
MethodDeclaration md = context.findMethodDeclaration(td, mi.getName().getIdentifier(), true);
|
||||||
|
if (md != null && md.getReturnType2() != null) {
|
||||||
|
java.util.List<String> values = context.getEnumValues(md.getReturnType2().toString());
|
||||||
|
if (values != null && !values.isEmpty()) {
|
||||||
|
return "ENUM_SET:" + String.join(",", values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,14 @@ public class GenericEventDetector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processSendEvent(MethodInvocation node, CompilationUnit cu, List<TriggerPoint> triggers) {
|
private void processSendEvent(MethodInvocation node, CompilationUnit cu, List<TriggerPoint> triggers) {
|
||||||
TriggerPoint trigger = buildTriggerPoint(node, cu, null);
|
List<TriggerPoint> builtTriggers = buildTriggerPoints(node, cu, null);
|
||||||
if (trigger != null) {
|
if (builtTriggers != null) {
|
||||||
|
for (TriggerPoint trigger : builtTriggers) {
|
||||||
log.debug("Successfully built trigger point: {}", trigger.getEvent());
|
log.debug("Successfully built trigger point: {}", trigger.getEvent());
|
||||||
triggers.add(trigger);
|
triggers.add(trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void processHints(MethodInvocation node, CompilationUnit cu, List<TriggerPoint> triggers) {
|
private void processHints(MethodInvocation node, CompilationUnit cu, List<TriggerPoint> triggers) {
|
||||||
if (hints == null || hints.isEmpty()) return;
|
if (hints == null || hints.isEmpty()) return;
|
||||||
@@ -62,14 +64,16 @@ public class GenericEventDetector {
|
|||||||
|
|
||||||
for (LibraryHint hint : hints) {
|
for (LibraryHint hint : hints) {
|
||||||
if (calledMethod.equals(hint.getMethodFqn()) || isHintMatch(calledMethod, hint.getMethodFqn())) {
|
if (calledMethod.equals(hint.getMethodFqn()) || isHintMatch(calledMethod, hint.getMethodFqn())) {
|
||||||
TriggerPoint trigger = buildTriggerPoint(node, cu, hint.getEvent());
|
List<TriggerPoint> builtTriggers = buildTriggerPoints(node, cu, hint.getEvent());
|
||||||
if (trigger != null) {
|
if (builtTriggers != null) {
|
||||||
|
for (TriggerPoint trigger : builtTriggers) {
|
||||||
log.debug("Successfully built synthetic trigger point from hint: {}", trigger.getEvent());
|
log.debug("Successfully built synthetic trigger point from hint: {}", trigger.getEvent());
|
||||||
triggers.add(trigger);
|
triggers.add(trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isHintMatch(String called, String hintFqn) {
|
private boolean isHintMatch(String called, String hintFqn) {
|
||||||
return hintFqn.endsWith("." + called);
|
return hintFqn.endsWith("." + called);
|
||||||
@@ -102,12 +106,12 @@ public class GenericEventDetector {
|
|||||||
return receiver.toString() + "." + methodName;
|
return receiver.toString() + "." + methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TriggerPoint buildTriggerPoint(MethodInvocation node, CompilationUnit cu, String forcedEvent) {
|
private List<TriggerPoint> buildTriggerPoints(MethodInvocation node, CompilationUnit cu, String forcedEvent) {
|
||||||
String eventValue = null;
|
String eventValue = null;
|
||||||
if (forcedEvent != null) {
|
if (forcedEvent != null) {
|
||||||
eventValue = context.resolveString(forcedEvent);
|
eventValue = context.resolveString(forcedEvent);
|
||||||
} else {
|
} else {
|
||||||
if (node.arguments().isEmpty()) return null;
|
if (node.arguments().isEmpty()) return Collections.emptyList();
|
||||||
Expression eventExpr = (Expression) node.arguments().get(0);
|
Expression eventExpr = (Expression) node.arguments().get(0);
|
||||||
|
|
||||||
// Try MessageBuilder extraction first
|
// Try MessageBuilder extraction first
|
||||||
@@ -123,18 +127,37 @@ public class GenericEventDetector {
|
|||||||
MethodDeclaration method = findEnclosingMethod(node);
|
MethodDeclaration method = findEnclosingMethod(node);
|
||||||
TypeDeclaration type = findEnclosingType(node);
|
TypeDeclaration type = findEnclosingType(node);
|
||||||
|
|
||||||
if (type == null) return null;
|
if (type == null) return Collections.emptyList();
|
||||||
|
|
||||||
String sourceState = extractSourceState(node);
|
String sourceState = extractSourceState(node);
|
||||||
|
|
||||||
return TriggerPoint.builder()
|
List<TriggerPoint> results = new ArrayList<>();
|
||||||
|
if (eventValue != null && eventValue.startsWith("ENUM_SET:")) {
|
||||||
|
String[] parts = eventValue.substring(9).split(",");
|
||||||
|
for (String part : parts) {
|
||||||
|
if (!part.trim().isEmpty()) {
|
||||||
|
results.add(TriggerPoint.builder()
|
||||||
|
.event(part.trim())
|
||||||
|
.sourceState(sourceState)
|
||||||
|
.className(context.getFqn(type))
|
||||||
|
.methodName(method != null ? method.getName().getIdentifier() : "initializer")
|
||||||
|
.sourceFile(context.getRelativePath(context.getFqn(type)))
|
||||||
|
.lineNumber(cu.getLineNumber(node.getStartPosition()))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results.add(TriggerPoint.builder()
|
||||||
.event(eventValue)
|
.event(eventValue)
|
||||||
.sourceState(sourceState)
|
.sourceState(sourceState)
|
||||||
.className(context.getFqn(type))
|
.className(context.getFqn(type))
|
||||||
.methodName(method != null ? method.getName().getIdentifier() : "initializer")
|
.methodName(method != null ? method.getName().getIdentifier() : "initializer")
|
||||||
.sourceFile(context.getRelativePath(context.getFqn(type)))
|
.sourceFile(context.getRelativePath(context.getFqn(type)))
|
||||||
.lineNumber(cu.getLineNumber(node.getStartPosition()))
|
.lineNumber(cu.getLineNumber(node.getStartPosition()))
|
||||||
.build();
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String extractSourceState(ASTNode node) {
|
private String extractSourceState(ASTNode node) {
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ public class CodebaseContext {
|
|||||||
private final List<CompilationUnit> allCus = new ArrayList<>();
|
private final List<CompilationUnit> allCus = new ArrayList<>();
|
||||||
|
|
||||||
private final Map<String, List<String>> interfaceToImpls = new HashMap<>();
|
private final Map<String, List<String>> interfaceToImpls = new HashMap<>();
|
||||||
|
private final Map<String, List<String>> enumValues = new HashMap<>();
|
||||||
|
|
||||||
public void scan(Set<Path> rootDirs, Set<String> customIgnorePatterns) throws IOException {
|
public void scan(Set<Path> rootDirs, Set<String> customIgnorePatterns) throws IOException {
|
||||||
this.allProperties = propertyResolver.resolveAllProperties(rootDirs);
|
this.allProperties = propertyResolver.resolveAllProperties(rootDirs);
|
||||||
@@ -188,6 +189,8 @@ public class CodebaseContext {
|
|||||||
for (Object type : cu.types()) {
|
for (Object type : cu.types()) {
|
||||||
if (type instanceof TypeDeclaration td) {
|
if (type instanceof TypeDeclaration td) {
|
||||||
indexType(td, packageName, javaFile);
|
indexType(td, packageName, javaFile);
|
||||||
|
} else if (type instanceof EnumDeclaration ed) {
|
||||||
|
indexEnum(ed, packageName, javaFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,6 +251,35 @@ public class CodebaseContext {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void indexEnum(EnumDeclaration ed, String parentFqn, Path javaFile) {
|
||||||
|
String simpleName = ed.getName().getIdentifier();
|
||||||
|
String fqn = parentFqn.isEmpty() ? simpleName : parentFqn + "." + simpleName;
|
||||||
|
|
||||||
|
classes.put(fqn, (CompilationUnit) ed.getRoot());
|
||||||
|
classPaths.put(fqn, javaFile);
|
||||||
|
|
||||||
|
List<String> values = new ArrayList<>();
|
||||||
|
for (Object o : ed.enumConstants()) {
|
||||||
|
if (o instanceof EnumConstantDeclaration ecd) {
|
||||||
|
values.add(fqn + "." + ecd.getName().getIdentifier());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumValues.put(fqn, values);
|
||||||
|
if (!simpleNameToFqn.containsKey(simpleName)) {
|
||||||
|
simpleNameToFqn.put(simpleName, fqn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getEnumValues(String fqnOrSimpleName) {
|
||||||
|
if (fqnOrSimpleName == null) return null;
|
||||||
|
List<String> values = enumValues.get(fqnOrSimpleName);
|
||||||
|
if (values != null) return values;
|
||||||
|
String fqn = simpleNameToFqn.get(fqnOrSimpleName);
|
||||||
|
if (fqn != null) return enumValues.get(fqn);
|
||||||
|
// Also try stripping array or generic types if any (e.g. MyEnum[])
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public State resolveState(Expression expr, CompilationUnit cu) {
|
public State resolveState(Expression expr, CompilationUnit cu) {
|
||||||
if (expr == null)
|
if (expr == null)
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -44,4 +44,42 @@ public class GenericEventDetectorTest {
|
|||||||
assertThat(triggers.get(0).getEvent()).isEqualTo("myEvent");
|
assertThat(triggers.get(0).getEvent()).isEqualTo("myEvent");
|
||||||
assertThat(triggers.get(0).getMethodName()).isEqualTo("a");
|
assertThat(triggers.get(0).getMethodName()).isEqualTo("a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEnumGetterUnionExtraction(@TempDir Path tempDir) throws IOException {
|
||||||
|
Path dir = tempDir.resolve("com/example");
|
||||||
|
Files.createDirectories(dir);
|
||||||
|
Files.writeString(dir.resolve("MyEnum.java"),
|
||||||
|
"package com.example;\n" +
|
||||||
|
"public enum MyEnum {\n" +
|
||||||
|
" STATE_A, STATE_B;\n" +
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
Files.writeString(dir.resolve("MyService.java"),
|
||||||
|
"package com.example;\n" +
|
||||||
|
"import org.springframework.statemachine.StateMachine;\n" +
|
||||||
|
"public class MyService {\n" +
|
||||||
|
" private StateMachine<String, String> stateMachine;\n" +
|
||||||
|
" public MyEnum getEvent() { return MyEnum.STATE_A; }\n" + // Pretend it returns the enum
|
||||||
|
" public void trigger() {\n" +
|
||||||
|
" stateMachine.sendEvent(this.getEvent());\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
CodebaseContext context = new CodebaseContext();
|
||||||
|
context.scan(tempDir);
|
||||||
|
|
||||||
|
GenericEventDetector detector = new GenericEventDetector(context, new ConstantResolver(), List.of());
|
||||||
|
|
||||||
|
CompilationUnit serviceCu = context.getCompilationUnits().stream()
|
||||||
|
.filter(cu -> cu.getJavaElement() == null || cu.getJavaElement().getElementName().contains("MyService"))
|
||||||
|
.findFirst().orElseThrow();
|
||||||
|
|
||||||
|
List<TriggerPoint> triggers = detector.detect(serviceCu);
|
||||||
|
|
||||||
|
System.out.println("TRIGGERS: " + triggers);
|
||||||
|
assertThat(triggers).hasSize(2);
|
||||||
|
assertThat(triggers).anyMatch(t -> t.getEvent().equals("com.example.MyEnum.STATE_A"));
|
||||||
|
assertThat(triggers).anyMatch(t -> t.getEvent().equals("com.example.MyEnum.STATE_B"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user