update number 2
This commit is contained in:
@@ -36,7 +36,7 @@ public class StrictFqnMatchingEngine implements EventMatchingEngine {
|
||||
List<String> polyEvents = triggerPoint.getPolymorphicEvents() != null ? triggerPoint.getPolymorphicEvents() : java.util.Collections.emptyList();
|
||||
|
||||
for (String pe : polyEvents) {
|
||||
if (pe.equals(smEventRaw)) {
|
||||
if (matchEventNames(pe, smEventRaw, triggerPoint.getEventTypeFqn())) {
|
||||
return true;
|
||||
}
|
||||
if (pe.startsWith("<SYMBOLIC: ") && pe.endsWith(".*>")) {
|
||||
@@ -57,7 +57,32 @@ public class StrictFqnMatchingEngine implements EventMatchingEngine {
|
||||
return true;
|
||||
}
|
||||
|
||||
return rawTriggerEvent.equals(smEventRaw);
|
||||
return matchEventNames(rawTriggerEvent, smEventRaw, triggerPoint.getEventTypeFqn());
|
||||
}
|
||||
|
||||
private boolean matchEventNames(String triggerEvent, String smEvent, String eventTypeFqn) {
|
||||
if (triggerEvent == null || smEvent == null) return false;
|
||||
if (triggerEvent.equals(smEvent)) return true;
|
||||
|
||||
String tConst = triggerEvent.contains(".") ? triggerEvent.substring(triggerEvent.lastIndexOf('.') + 1) : triggerEvent;
|
||||
String smConst = smEvent.contains(".") ? smEvent.substring(smEvent.lastIndexOf('.') + 1) : smEvent;
|
||||
|
||||
if (!tConst.equals(smConst)) return false;
|
||||
|
||||
if (eventTypeFqn != null && eventTypeFqn.contains(".") && smEvent.contains(".")) {
|
||||
String fullTriggerFqn = eventTypeFqn + "." + tConst;
|
||||
return fullTriggerFqn.equals(smEvent);
|
||||
}
|
||||
|
||||
if (triggerEvent.contains(".") && smEvent.contains(".")) {
|
||||
String tClass = triggerEvent.substring(0, triggerEvent.lastIndexOf('.'));
|
||||
String smClass = smEvent.substring(0, smEvent.lastIndexOf('.'));
|
||||
String tClassSimple = tClass.contains(".") ? tClass.substring(tClass.lastIndexOf('.') + 1) : tClass;
|
||||
String smClassSimple = smClass.contains(".") ? smClass.substring(smClass.lastIndexOf('.') + 1) : smClass;
|
||||
return tClassSimple.equals(smClassSimple);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isWildcardVariable(String eventStr) {
|
||||
|
||||
@@ -64,6 +64,7 @@ public class TriggerPoint {
|
||||
}
|
||||
|
||||
private static String qualifyEvent(String e, String eventTypeFqn) {
|
||||
System.out.println("qualifyEvent e=" + e + " eventTypeFqn=" + eventTypeFqn);
|
||||
if (e == null || eventTypeFqn == null || e.isEmpty()) {
|
||||
return e;
|
||||
}
|
||||
@@ -79,21 +80,23 @@ public class TriggerPoint {
|
||||
if (!isEnumConstantCandidate(e)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
String simpleEventType = eventTypeFqn.contains(".") ? eventTypeFqn.substring(eventTypeFqn.lastIndexOf('.') + 1) : eventTypeFqn;
|
||||
|
||||
if (e.contains(".")) {
|
||||
String qualifier = e.substring(0, e.lastIndexOf('.'));
|
||||
String lastSegment = e.substring(e.lastIndexOf('.') + 1);
|
||||
if (qualifier.equals(eventTypeFqn)) {
|
||||
return e;
|
||||
}
|
||||
if (eventTypeFqn.endsWith("." + qualifier) || eventTypeFqn.equals(qualifier)) {
|
||||
return eventTypeFqn + "." + lastSegment;
|
||||
String simpleQualifier = qualifier.contains(".") ? qualifier.substring(qualifier.lastIndexOf('.') + 1) : qualifier;
|
||||
|
||||
if (simpleQualifier.equals(simpleEventType)) {
|
||||
return simpleEventType + "." + lastSegment;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
if (eventTypeFqn.startsWith("java.lang.") || eventTypeFqn.equals("int") || eventTypeFqn.equals("long") || eventTypeFqn.equals("char")) {
|
||||
if (eventTypeFqn.startsWith("java.lang.") || eventTypeFqn.equals("String") || eventTypeFqn.equals("int") || eventTypeFqn.equals("long") || eventTypeFqn.equals("char")) {
|
||||
return e;
|
||||
}
|
||||
return eventTypeFqn + "." + e;
|
||||
return simpleEventType + "." + e;
|
||||
}
|
||||
|
||||
private static boolean isEnumConstantCandidate(String eventStr) {
|
||||
|
||||
@@ -257,6 +257,9 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
.lineNumber(tp.getLineNumber())
|
||||
.polymorphicEvents(setterEvents)
|
||||
.constraint(tp.getConstraint())
|
||||
.stateTypeFqn(tp.getStateTypeFqn())
|
||||
.eventTypeFqn(tp.getEventTypeFqn())
|
||||
.external(tp.isExternal())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -278,6 +281,9 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
.lineNumber(tp.getLineNumber())
|
||||
.polymorphicEvents(getterEvents)
|
||||
.constraint(tp.getConstraint())
|
||||
.stateTypeFqn(tp.getStateTypeFqn())
|
||||
.eventTypeFqn(tp.getEventTypeFqn())
|
||||
.external(tp.isExternal())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -311,6 +317,9 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
.lineNumber(tp.getLineNumber())
|
||||
.polymorphicEvents(polymorphicEvents)
|
||||
.constraint(tp.getConstraint())
|
||||
.stateTypeFqn(tp.getStateTypeFqn())
|
||||
.eventTypeFqn(tp.getEventTypeFqn())
|
||||
.external(tp.isExternal())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -318,7 +327,6 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
exprParser.setKind(ASTParser.K_EXPRESSION);
|
||||
exprParser.setSource(resolvedValue.toCharArray());
|
||||
ASTNode exprNode = exprParser.createAST(null);
|
||||
System.out.println("DEBUG resolvedValue=" + resolvedValue + ", exprNode=" + exprNode.getClass().getSimpleName());
|
||||
|
||||
String varName = null;
|
||||
String methodName = null;
|
||||
@@ -425,7 +433,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
resolvedValue = cic.toString() + "." + methodName + "()";
|
||||
}
|
||||
}
|
||||
System.out.println("Returning early with events: " + polymorphicEvents + " for " + resolvedValue); if (!polymorphicEvents.isEmpty()) {
|
||||
if (!polymorphicEvents.isEmpty()) {
|
||||
return TriggerPoint.builder()
|
||||
.event(resolvedValue)
|
||||
.className(tp.getClassName())
|
||||
@@ -437,6 +445,9 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
.lineNumber(tp.getLineNumber())
|
||||
.polymorphicEvents(polymorphicEvents)
|
||||
.constraint(tp.getConstraint())
|
||||
.stateTypeFqn(tp.getStateTypeFqn())
|
||||
.eventTypeFqn(tp.getEventTypeFqn())
|
||||
.external(tp.isExternal())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -509,7 +520,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
TypeDeclaration currentTd = context.getTypeDeclaration(methodFqn.substring(0, methodFqn.lastIndexOf('.')));
|
||||
CompilationUnit cu = currentTd != null && currentTd.getRoot() instanceof CompilationUnit ? (CompilationUnit) currentTd.getRoot() : null;
|
||||
List<String> values = constantExtractor.resolveMethodReturnConstant(declaredType, methodName, 0, new HashSet<>(), cu);
|
||||
System.out.println("RESOLVED VALUES FOR " + methodName + " in " + currentTd.getName() + ": " + values); if (values != null && !values.isEmpty()) {
|
||||
if (values != null && !values.isEmpty()) {
|
||||
polymorphicEvents.addAll(values);
|
||||
}
|
||||
if (polymorphicEvents.isEmpty() && variableTracer != null) {
|
||||
@@ -550,7 +561,6 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
if (currentTd != null && context.findMethodDeclaration(currentTd, methodName, true) != null) {
|
||||
CompilationUnit cu = currentTd.getRoot() instanceof CompilationUnit ? (CompilationUnit) currentTd.getRoot() : null;
|
||||
List<String> values = constantExtractor.resolveMethodReturnConstant(context.getFqn(currentTd), methodName, 0, new HashSet<>(), cu);
|
||||
System.out.println("DEBUG RESOLVED VALUES FOR " + methodName + " in " + currentTd.getName() + " -> " + values);
|
||||
if (values != null && !values.isEmpty()) {
|
||||
polymorphicEvents.addAll(values);
|
||||
sourceMethod = methodFqn;
|
||||
@@ -688,6 +698,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
|
||||
polymorphicEvents = polymorphicEvents.stream().distinct().collect(java.util.stream.Collectors.toList());
|
||||
|
||||
System.out.println("JSON DEBUG: building final TriggerPoint. resolvedValue=" + resolvedValue + ", event=" + event);
|
||||
if (!resolvedValue.equals(event) || !polymorphicEvents.isEmpty()) {
|
||||
return TriggerPoint.builder()
|
||||
.event(resolvedValue)
|
||||
@@ -695,8 +706,14 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
.methodName(tp.getMethodName())
|
||||
.sourceFile(tp.getSourceFile())
|
||||
.lineNumber(tp.getLineNumber())
|
||||
.sourceModule(tp.getSourceModule())
|
||||
.stateMachineId(tp.getStateMachineId())
|
||||
.sourceState(tp.getSourceState())
|
||||
.polymorphicEvents(polymorphicEvents)
|
||||
.constraint(tp.getConstraint())
|
||||
.stateTypeFqn(tp.getStateTypeFqn())
|
||||
.eventTypeFqn(tp.getEventTypeFqn())
|
||||
.external(tp.isExternal())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -789,7 +806,7 @@ public abstract class AbstractCallGraphEngine implements CallGraphEngine {
|
||||
val = expr.toString();
|
||||
}
|
||||
|
||||
System.out.println("DEBUG resolveArgument expr=" + expr + ", val=" + val); return postProcessResolvedArgument(expr, val);
|
||||
return postProcessResolvedArgument(expr, val);
|
||||
}
|
||||
|
||||
protected String postProcessResolvedArgument(Expression originalExpr, String resolvedValue) {
|
||||
|
||||
@@ -524,7 +524,24 @@ public class GenericEventDetector {
|
||||
}
|
||||
|
||||
private String[] resolveStateMachineTypeArguments(MethodInvocation node) {
|
||||
System.out.println("resolveStateMachineTypeArguments CALLED for node: " + node);
|
||||
Expression receiver = node.getExpression();
|
||||
System.out.println("initial receiver: " + receiver);
|
||||
|
||||
// Trace back the receiver if it's a builder chain
|
||||
while (receiver instanceof MethodInvocation mi) {
|
||||
if (mi.getName().getIdentifier().equals("sendEvent")) {
|
||||
receiver = mi.getExpression();
|
||||
break;
|
||||
}
|
||||
receiver = mi.getExpression();
|
||||
}
|
||||
|
||||
// Also if the node itself is sendEvent, receiver is already correct
|
||||
if (node.getName().getIdentifier().equals("sendEvent")) {
|
||||
receiver = node.getExpression();
|
||||
}
|
||||
|
||||
if (receiver == null) return new String[]{null, null};
|
||||
|
||||
ITypeBinding binding = receiver.resolveTypeBinding();
|
||||
@@ -540,16 +557,19 @@ public class GenericEventDetector {
|
||||
|
||||
// Fallback: search enclosing class/method for variable declaration
|
||||
Type declType = findReceiverTypeManually(receiver, node);
|
||||
System.out.println("findReceiverTypeManually returned: " + declType);
|
||||
if (declType instanceof ParameterizedType pt) {
|
||||
List<?> typeArgs = pt.typeArguments();
|
||||
System.out.println("typeArgs size: " + typeArgs.size());
|
||||
if (typeArgs.size() >= 2) {
|
||||
CompilationUnit cu = (CompilationUnit) node.getRoot();
|
||||
String stateType = resolveTypeToFqn((Type) typeArgs.get(0), cu);
|
||||
String eventType = resolveTypeToFqn((Type) typeArgs.get(1), cu);
|
||||
System.out.println("Resolved types: state=" + stateType + " event=" + eventType);
|
||||
return new String[]{stateType, eventType};
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Returning null, null");
|
||||
return new String[]{null, null};
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,10 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
||||
|
||||
List<String> allResolved = new ArrayList<>();
|
||||
|
||||
if (node.getExpression() == null) {
|
||||
return Collections.singletonList(baseCalled);
|
||||
}
|
||||
|
||||
if (baseCalled.contains(".")) {
|
||||
String className = baseCalled.substring(0, baseCalled.lastIndexOf('.'));
|
||||
String methodName = baseCalled.substring(baseCalled.lastIndexOf('.') + 1);
|
||||
@@ -180,7 +184,8 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
||||
if (td != null) {
|
||||
isAbstractOrInterface = td.isInterface() || (td.modifiers() != null && td.modifiers().toString().contains("abstract"));
|
||||
}
|
||||
if (!isAbstractOrInterface) {
|
||||
boolean isImplicitThis = node.getExpression() == null || node.getExpression() instanceof ThisExpression || node.getExpression() instanceof SuperMethodInvocation;
|
||||
if (!isAbstractOrInterface || isImplicitThis) {
|
||||
allResolved.add(className + "." + methodName);
|
||||
}
|
||||
for (String impl : impls) {
|
||||
@@ -650,6 +655,12 @@ public class HeuristicCallGraphEngine extends AbstractCallGraphEngine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMethodBinding methodBinding = mi.resolveMethodBinding();
|
||||
if (methodBinding != null && methodBinding.getReturnType() != null) {
|
||||
return methodBinding.getReturnType().getErasure().getQualifiedName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -459,6 +459,14 @@ public class VariableTracer {
|
||||
return argValue;
|
||||
}
|
||||
|
||||
String tracedLocal = traceLocalVariable(callerMethod, argValue);
|
||||
if (tracedLocal != null && !tracedLocal.equals(argValue)) {
|
||||
if (tracedLocal.contains(".") || tracedLocal.startsWith("new ") || tracedLocal.matches(".*[0-9].*") || tracedLocal.contains("(")) {
|
||||
return tracedLocal;
|
||||
}
|
||||
argValue = tracedLocal;
|
||||
}
|
||||
|
||||
int callerIndex = path.indexOf(callerMethod);
|
||||
if (callerIndex <= 0) return argValue;
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ public class SpringContextScanner extends ASTVisitor {
|
||||
ITypeBinding typeBinding = node.resolveBinding();
|
||||
if (typeBinding == null) return true;
|
||||
|
||||
if (isSpringComponent(typeBinding)) {
|
||||
if (isSpringComponent(typeBinding, node)) {
|
||||
SpringBean bean = SpringBean.builder()
|
||||
.typeFqn(typeBinding.getQualifiedName())
|
||||
.assignableTypes(getAssignableTypes(typeBinding))
|
||||
.isPrimary(hasAnnotation(typeBinding, "org.springframework.context.annotation.Primary"))
|
||||
.isPrimary(hasPrimary(typeBinding, node))
|
||||
.qualifiers(extractQualifiers(typeBinding))
|
||||
.order(extractOrder(typeBinding))
|
||||
.declaringClassFqn(typeBinding.getQualifiedName())
|
||||
@@ -73,7 +73,7 @@ public class SpringContextScanner extends ASTVisitor {
|
||||
SpringBean bean = SpringBean.builder()
|
||||
.typeFqn(concreteType[0])
|
||||
.assignableTypes(assignables)
|
||||
.isPrimary(hasAnnotation(methodBinding, "org.springframework.context.annotation.Primary"))
|
||||
.isPrimary(hasPrimaryMethod(methodBinding, node))
|
||||
.qualifiers(extractQualifiers(methodBinding))
|
||||
.order(extractOrder(methodBinding))
|
||||
.declaringClassFqn(methodBinding.getDeclaringClass().getQualifiedName())
|
||||
@@ -97,11 +97,50 @@ public class SpringContextScanner extends ASTVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isSpringComponent(ITypeBinding binding) {
|
||||
return hasMetaAnnotation(binding, "org.springframework.stereotype.Component") ||
|
||||
hasMetaAnnotation(binding, "org.springframework.web.bind.annotation.RestController");
|
||||
private boolean isSpringComponent(ITypeBinding binding, TypeDeclaration node) {
|
||||
if (hasMetaAnnotation(binding, "org.springframework.stereotype.Component") ||
|
||||
hasMetaAnnotation(binding, "org.springframework.web.bind.annotation.RestController") ||
|
||||
hasAnnotation(binding, "org.springframework.stereotype.Component") ||
|
||||
hasAnnotation(binding, "org.springframework.stereotype.Service") ||
|
||||
hasAnnotation(binding, "org.springframework.stereotype.Repository") ||
|
||||
hasAnnotation(binding, "org.springframework.stereotype.Controller") ||
|
||||
hasAnnotation(binding, "org.springframework.web.bind.annotation.RestController") ||
|
||||
hasAnnotation(binding, "org.springframework.context.annotation.Configuration")) {
|
||||
return true;
|
||||
}
|
||||
for (Object modObj : node.modifiers()) {
|
||||
if (modObj instanceof Annotation ann) {
|
||||
String name = ann.getTypeName().getFullyQualifiedName();
|
||||
if (name.equals("Component") || name.equals("Service") || name.equals("Repository") ||
|
||||
name.equals("Controller") || name.equals("RestController") || name.equals("Configuration")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasPrimary(ITypeBinding binding, TypeDeclaration node) {
|
||||
if (hasAnnotation(binding, "org.springframework.context.annotation.Primary")) return true;
|
||||
for (Object modObj : node.modifiers()) {
|
||||
if (modObj instanceof Annotation ann) {
|
||||
String name = ann.getTypeName().getFullyQualifiedName();
|
||||
if (name.equals("Primary")) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasPrimaryMethod(IMethodBinding binding, MethodDeclaration node) {
|
||||
if (hasAnnotation(binding, "org.springframework.context.annotation.Primary")) return true;
|
||||
for (Object modObj : node.modifiers()) {
|
||||
if (modObj instanceof Annotation ann) {
|
||||
String name = ann.getTypeName().getFullyQualifiedName();
|
||||
if (name.equals("Primary")) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private boolean hasMetaAnnotation(ITypeBinding binding, String targetFqn) {
|
||||
return checkMetaAnnotation(binding.getAnnotations(), targetFqn, new HashSet<>());
|
||||
}
|
||||
@@ -202,9 +241,15 @@ public class SpringContextScanner extends ASTVisitor {
|
||||
|
||||
private String extractStereotypeValue(ITypeBinding binding) {
|
||||
for (IAnnotationBinding ann : binding.getAnnotations()) {
|
||||
// Check if annotation itself is meta-annotated with @Component
|
||||
if (ann.getAnnotationType() == null) continue;
|
||||
String fqn = ann.getAnnotationType().getQualifiedName();
|
||||
if (checkMetaAnnotation(new IAnnotationBinding[]{ann}, "org.springframework.stereotype.Component", new HashSet<>()) ||
|
||||
"org.springframework.stereotype.Component".equals(ann.getAnnotationType().getQualifiedName())) {
|
||||
"org.springframework.stereotype.Component".equals(fqn) ||
|
||||
"org.springframework.stereotype.Service".equals(fqn) ||
|
||||
"org.springframework.stereotype.Repository".equals(fqn) ||
|
||||
"org.springframework.stereotype.Controller".equals(fqn) ||
|
||||
"org.springframework.web.bind.annotation.RestController".equals(fqn) ||
|
||||
"org.springframework.context.annotation.Configuration".equals(fqn)) {
|
||||
for (IMemberValuePairBinding pair : ann.getDeclaredMemberValuePairs()) {
|
||||
if ("value".equals(pair.getName()) && pair.getValue() instanceof String) {
|
||||
return (String) pair.getValue();
|
||||
|
||||
@@ -291,7 +291,6 @@ public class CodebaseContext {
|
||||
}
|
||||
Set<String> allImpls = new HashSet<>();
|
||||
collectImplementations(cleanName, allImpls, new HashSet<>());
|
||||
System.out.println("GET IMPLEMENTATIONS FOR: " + interfaceName + " -> " + allImpls);
|
||||
return new ArrayList<>(allImpls);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user