Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 23 additions & 62 deletions src/main/java/io/github/bldl/astParsing/AstManipulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
import com.github.javaparser.ast.type.TypeParameter;
import com.github.javaparser.ast.visitor.ModifierVisitor;
import com.github.javaparser.ast.visitor.Visitable;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import com.github.javaparser.utils.CodeGenerationUtils;
import com.github.javaparser.utils.SourceRoot;
import io.github.bldl.annotationProcessing.annotations.MyVariance;
Expand Down Expand Up @@ -46,9 +50,14 @@ public class AstManipulator {
public AstManipulator(Messager messager, String sourceFolder) {
this.messager = messager;
this.sourceFolder = sourceFolder;
CombinedTypeSolver typeSolver = new CombinedTypeSolver();
typeSolver.add(new ReflectionTypeSolver());
typeSolver.add(new JavaParserTypeSolver(Paths.get("src/main/java")));
JavaSymbolSolver symbolSolver = new JavaSymbolSolver(typeSolver);
sourceRoot = new SourceRoot(
CodeGenerationUtils.mavenModuleRoot(AstManipulator.class).resolve(sourceFolder));
classHierarchy = computeClassHierarchy();
sourceRoot.getParserConfiguration().setSymbolResolver(symbolSolver);
classHierarchy = (new ClassHierarchyComputer(sourceRoot, messager, sourceFolder)).computeClassHierarchy();
}

public void applyChanges() {
Expand Down Expand Up @@ -110,13 +119,6 @@ public Visitable visit(TypeParameter n, Void arg) {
}, null);
}

public ClassHierarchyGraph<String> computeClassHierarchy() {
ClassHierarchyGraph<String> g = new ClassHierarchyGraph<>();
g.addVertex("Object");
computeClassHierarchyRec(g, Paths.get(sourceFolder).toFile(), "");
return g;
}

private ClassData computeClassData(String cls, String packageName, Map<String, MyVariance> mp) {
CompilationUnit cu = sourceRoot.parse(packageName, cls);
Map<String, ParamData> indexAndBound = new HashMap<>();
Expand Down Expand Up @@ -151,9 +153,7 @@ private void changeAST(File dir, ClassData classData, Map<String, MethodData> me
Set<Pair<String, ClassOrInterfaceType>> varsToWatch = new HashSet<>();
cu.accept(new VariableCollector(classData), varsToWatch);
cu.accept(
new SubtypingCheckVisitor(collectMethodParams(cu, classData), collectMethodTypes(cu), messager,
varsToWatch, classData,
classHierarchy),
new SubtypingCheckVisitor(collectMethodParams(cu, classData), messager, classData, classHierarchy),
null);
cu.accept(new TypeEraserVisitor(classData), null);
for (Pair<String, ClassOrInterfaceType> var : varsToWatch) {
Expand All @@ -163,35 +163,7 @@ private void changeAST(File dir, ClassData classData, Map<String, MethodData> me
}
}

private void computeClassHierarchyRec(ClassHierarchyGraph<String> g, File dir, String packageName) {
for (File file : dir.listFiles()) {
String fileName = file.getName();
if (file.isDirectory()) {
if (!fileName.equals(OUTPUT_NAME))
computeClassHierarchyRec(g, file, appendPackageDeclaration(packageName, fileName));
continue;
}
if (!isJavaFile(file))
continue;

CompilationUnit cu = sourceRoot.parse(packageName, fileName);

cu.findAll(ClassOrInterfaceDeclaration.class).forEach(cls -> {
NodeList<ClassOrInterfaceType> supertypes = cls.getExtendedTypes();
supertypes.addAll(cls.getImplementedTypes());
g.addVertex(cls.getNameAsString());
for (ClassOrInterfaceType supertype : supertypes) {
if (!g.containsVertex(supertype.getNameAsString()))
g.addVertex(supertype.getNameAsString());
g.addEdge(supertype.getNameAsString(), cls.getNameAsString());
}
if (supertypes.isEmpty())
g.addEdge("Object", cls.getNameAsString());
});
}
}

private boolean isJavaFile(File file) {
public static boolean isJavaFile(File file) {
return file.getName().endsWith(".java");
}

Expand All @@ -200,38 +172,27 @@ private void changePackageDeclaration(CompilationUnit cu) {
cu.setPackageDeclaration(new PackageDeclaration(new Name(newPackageName)));
}

private String appendPackageDeclaration(String existing, String toAppend) {
public static String appendPackageDeclaration(String existing, String toAppend) {
if (existing.equals(""))
return toAppend;
return existing + "." + toAppend;
}

private Map<String, Map<Integer, Type>> collectMethodParams(CompilationUnit cu, ClassData classData) {
Map<String, Map<Integer, Type>> mp = new HashMap<>();
Map<String, Map<Integer, Type>> methodParams = new HashMap<>();
cu.findAll(MethodDeclaration.class).forEach(dec -> {
String methodName = dec.getNameAsString();
if (methodParams.containsKey(methodName)) {
messager.printMessage(Kind.ERROR, "Duplicate methods inside a class. Can't handle polymorphism.");
return;
}
methodParams.put(methodName, new HashMap<>());
NodeList<Parameter> params = dec.getParameters();
for (int i = 0; i < params.size(); ++i) {
Parameter param = params.get(i);
if (!(param.getType() instanceof ClassOrInterfaceType))
continue;
ClassOrInterfaceType type = ((ClassOrInterfaceType) param.getType());
String methodName = dec.getNameAsString();
if (type.getNameAsString().equals(classData.className())) {
mp.putIfAbsent(methodName, new HashMap<>());
mp.get(methodName).put(i,
type);
}
Type type = params.get(i).getType();
methodParams.get(methodName).put(i, type);
}
});
return mp;
}

private Map<String, Type> collectMethodTypes(CompilationUnit cu) {
Map<String, Type> mp = new HashMap<>();
cu.findAll(MethodDeclaration.class).forEach(dec -> {
String methodName = dec.getNameAsString();
mp.put(methodName, dec.getType());
});
return mp;
return methodParams;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.github.bldl.astParsing;

import java.io.File;
import java.nio.file.Paths;

import javax.annotation.processing.Messager;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.RecordDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.utils.SourceRoot;

import io.github.bldl.graph.ClassHierarchyGraph;

public class ClassHierarchyComputer {

private SourceRoot sourceRoot;
private Messager messager;
private String sourceFolder;

public ClassHierarchyComputer(SourceRoot sourceRoot, Messager messager, String sourceFolder) {
this.sourceRoot = sourceRoot;
this.messager = messager;
this.sourceFolder = sourceFolder;
}

public ClassHierarchyGraph<String> computeClassHierarchy() {
ClassHierarchyGraph<String> g = new ClassHierarchyGraph<>();
g.addVertex("Object");
computeClassHierarchyRec(g, Paths.get(sourceFolder).toFile(), "");
return g;
}

private void computeClassHierarchyRec(ClassHierarchyGraph<String> g, File dir, String packageName) {
for (File file : dir.listFiles()) {
String fileName = file.getName();
if (file.isDirectory()) {
if (!fileName.equals(AstManipulator.OUTPUT_NAME))
computeClassHierarchyRec(g, file, AstManipulator.appendPackageDeclaration(packageName, fileName));
continue;
}
if (!AstManipulator.isJavaFile(file))
continue;

CompilationUnit cu = sourceRoot.parse(packageName, fileName);

cu.findAll(RecordDeclaration.class).forEach(record -> {
NodeList<ClassOrInterfaceType> supertypes = record.getImplementedTypes();
handleDeclaration(packageName, g, supertypes, record);
});

cu.findAll(EnumDeclaration.class).forEach(enm -> {
NodeList<ClassOrInterfaceType> supertypes = enm.getImplementedTypes();
handleDeclaration(packageName, g, supertypes, enm);
});

cu.findAll(ClassOrInterfaceDeclaration.class).forEach(cls -> {
NodeList<ClassOrInterfaceType> supertypes = cls.getExtendedTypes();
supertypes.addAll(cls.getImplementedTypes());
handleDeclaration(packageName, g, supertypes, cls);
});
}
}

private void handleDeclaration(String packageName, ClassHierarchyGraph<String> g,
NodeList<ClassOrInterfaceType> supertypes,
TypeDeclaration<?> declaration) {
g.addVertex(getQualifiedName(packageName, declaration.getNameAsString()));
for (ClassOrInterfaceType supertype : supertypes) {
if (!g.containsVertex(supertype.getNameAsString()))
g.addVertex(supertype.getNameAsString());
g.addEdge(supertype.getNameAsString(), declaration.getNameAsString());
}
if (supertypes.isEmpty())
g.addEdge("Object", declaration.getNameAsString());
}

private String getQualifiedName(String packageName, String typeName) {
return packageName + "." + typeName;
}
}
Loading
Loading