cleanup
This commit is contained in:
@@ -1,165 +0,0 @@
|
||||
package click.kamil.callgraphexporter;
|
||||
|
||||
import click.kamil.callgraphexporter.domain.MethodMetadata;
|
||||
import click.kamil.callgraphexporter.domain.MethodSignature;
|
||||
import click.kamil.callgraphexporter.domain.Modifiers;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
public class JdtResolvedCallGraph {
|
||||
|
||||
// Use signature as the unique key
|
||||
static Map<MethodSignature, Set<MethodSignature>> callGraph = new HashMap<>();
|
||||
|
||||
// Optionally store metadata
|
||||
static Map<MethodSignature, MethodMetadata> metadataMap = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
File sourceDir = new File("src/main/java/click/kamil/callgraphexporter/simple");
|
||||
|
||||
List<File> javaFiles = new ArrayList<>();
|
||||
collectJavaFiles(sourceDir, javaFiles);
|
||||
|
||||
for (File file : javaFiles) {
|
||||
parseFileWithBinding(file, sourceDir);
|
||||
}
|
||||
|
||||
generateDotFile("callgraph.dot");
|
||||
System.out.println("Call graph saved to callgraph.dot");
|
||||
}
|
||||
|
||||
private static void collectJavaFiles(File dir, List<File> javaFiles) {
|
||||
for (File file : Objects.requireNonNull(dir.listFiles())) {
|
||||
if (file.isDirectory()) {
|
||||
collectJavaFiles(file, javaFiles);
|
||||
} else if (file.getName().endsWith(".java")) {
|
||||
javaFiles.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseFileWithBinding(File file, File sourceRoot) throws IOException {
|
||||
String source = Files.readString(file.toPath());
|
||||
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS21);
|
||||
parser.setSource(source.toCharArray());
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
|
||||
parser.setEnvironment(
|
||||
null,
|
||||
new String[]{sourceRoot.getAbsolutePath()},
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
parser.setUnitName(file.getName());
|
||||
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_17);
|
||||
parser.setCompilerOptions(options);
|
||||
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
|
||||
cu.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration method) {
|
||||
IMethodBinding binding = method.resolveBinding();
|
||||
if (binding == null) return super.visit(method);
|
||||
|
||||
MethodSignature callerSig = toSignature(binding);
|
||||
MethodMetadata callerMeta = toMetadata(binding, method);
|
||||
metadataMap.put(callerSig, callerMeta);
|
||||
callGraph.putIfAbsent(callerSig, new HashSet<>());
|
||||
|
||||
method.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
IMethodBinding calleeBinding = node.resolveMethodBinding();
|
||||
if (calleeBinding != null) {
|
||||
MethodSignature calleeSig = toSignature(calleeBinding);
|
||||
callGraph.get(callerSig).add(calleeSig);
|
||||
// You can collect metadata for callees too if needed
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
|
||||
return super.visit(method);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fixed: matches your MethodSignature record with only methodName and paramTypes
|
||||
private static MethodSignature toSignature(IMethodBinding binding) {
|
||||
String methodName = binding.getName();
|
||||
|
||||
List<String> paramTypes = new ArrayList<>();
|
||||
for (ITypeBinding param : binding.getParameterTypes()) {
|
||||
paramTypes.add(param.getName());
|
||||
}
|
||||
|
||||
return new MethodSignature(methodName, paramTypes);
|
||||
}
|
||||
|
||||
private static MethodMetadata toMetadata(IMethodBinding binding, MethodDeclaration method) {
|
||||
String returnType = binding.getReturnType().getName();
|
||||
|
||||
Set<String> exceptions = new HashSet<>();
|
||||
for (ITypeBinding ex : binding.getExceptionTypes()) {
|
||||
exceptions.add(ex.getName());
|
||||
}
|
||||
|
||||
Set<Modifiers> modifiers = extractModifiers(binding, method);
|
||||
List<String> annotations = new ArrayList<>();
|
||||
|
||||
return new MethodMetadata(returnType, exceptions, modifiers, annotations, null);
|
||||
}
|
||||
|
||||
private static void generateDotFile(String filename) throws IOException {
|
||||
StringBuilder sb = new StringBuilder("digraph G {\n");
|
||||
for (MethodSignature caller : callGraph.keySet()) {
|
||||
String callerLabel = formatSignature(caller);
|
||||
for (MethodSignature callee : callGraph.get(caller)) {
|
||||
String calleeLabel = formatSignature(callee);
|
||||
sb.append(" \"").append(callerLabel).append("\" -> \"").append(calleeLabel).append("\";\n");
|
||||
}
|
||||
}
|
||||
sb.append("}");
|
||||
Files.writeString(new File(filename).toPath(), sb.toString());
|
||||
}
|
||||
|
||||
private static String formatSignature(MethodSignature sig) {
|
||||
// Build a readable label (methodName + param list)
|
||||
return sig.methodName() + sig.parameterTypes();
|
||||
}
|
||||
|
||||
private static Set<Modifiers> extractModifiers(IMethodBinding binding, MethodDeclaration method) {
|
||||
Set<Modifiers> result = new HashSet<>();
|
||||
int mods = binding.getModifiers();
|
||||
|
||||
if (Modifier.isPublic(mods)) result.add(Modifiers.PUBLIC);
|
||||
if (Modifier.isPrivate(mods)) result.add(Modifiers.PRIVATE);
|
||||
if (Modifier.isProtected(mods)) result.add(Modifiers.PROTECTED);
|
||||
if (Modifier.isStatic(mods)) result.add(Modifiers.STATIC);
|
||||
if (Modifier.isAbstract(mods)) result.add(Modifiers.ABSTRACT);
|
||||
if (Modifier.isFinal(mods)) result.add(Modifiers.FINAL);
|
||||
if (Modifier.isNative(mods)) result.add(Modifiers.NATIVE);
|
||||
if (Modifier.isSynchronized(mods)) result.add(Modifiers.SYNCHRONIZED);
|
||||
if (Modifier.isStrictfp(mods)) result.add(Modifiers.STRICTFP);
|
||||
|
||||
for (Object mod : method.modifiers()) {
|
||||
if (mod instanceof Modifier keyword) {
|
||||
if (keyword.isDefault()) result.add(Modifiers.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package click.kamil.callgraphexporter.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Method {
|
||||
private MethodSignature signature;
|
||||
private MethodMetadata metadata;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package click.kamil.callgraphexporter.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public record MethodMetadata(
|
||||
String returnType,
|
||||
Set<String> thrownExceptions,
|
||||
Set<Modifiers> modifiers,
|
||||
List<String> annotations,
|
||||
String documentationComment // Optional: Javadoc
|
||||
) {}
|
||||
@@ -1,9 +0,0 @@
|
||||
package click.kamil.callgraphexporter.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record MethodSignature(
|
||||
String methodName,
|
||||
List<String> parameterTypes
|
||||
) {
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package click.kamil.callgraphexporter.domain;
|
||||
|
||||
public enum Modifiers {
|
||||
PUBLIC,
|
||||
PROTECTED,
|
||||
PRIVATE,
|
||||
STATIC,
|
||||
ABSTRACT,
|
||||
FINAL,
|
||||
NATIVE,
|
||||
SYNCHRONIZED,
|
||||
TRANSIENT,
|
||||
VOLATILE,
|
||||
STRICTFP,
|
||||
DEFAULT,
|
||||
SEALED,
|
||||
NON_SEALED,
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package click.kamil.callgraphexporter.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TypeGroup {
|
||||
private String packageName;
|
||||
private String typeName;
|
||||
private TypeKind typeKind;
|
||||
private EnumSet<Modifiers> modifiers = EnumSet.noneOf(Modifiers.class);
|
||||
private List<Method> methods = new ArrayList<>();
|
||||
|
||||
public void addMethod(Method method) {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package click.kamil.callgraphexporter.domain;
|
||||
|
||||
public enum TypeKind {
|
||||
CLASS,
|
||||
INTERFACE,
|
||||
RECORD,
|
||||
ENUM,
|
||||
ANNOTATION
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package click.kamil.callgraphexporter.simple;
|
||||
|
||||
public class Kamil {
|
||||
|
||||
void a(){
|
||||
b();
|
||||
}
|
||||
void b(){
|
||||
c();
|
||||
}
|
||||
void c(){}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package click.kamil.callgraphexporter.simple;
|
||||
|
||||
public class Kamil2 {
|
||||
void ka() {
|
||||
new Kamil().b();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user