Skip to content

Commit

Permalink
proper casts and erasure for arbitrary amount of type args
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixAnthonisen committed Oct 25, 2024
1 parent 39dc8c3 commit 1e7a662
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 69 deletions.
54 changes: 25 additions & 29 deletions src/main/java/anthonisen/felix/astParsing/Covariancer.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package anthonisen.felix.astParsing;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.TypeParameter;
import com.github.javaparser.utils.CodeGenerationUtils;
import com.github.javaparser.utils.SourceRoot;

Expand All @@ -13,8 +17,6 @@
import anthonisen.felix.astParsing.visitors.TypeEraserVisitor;
import anthonisen.felix.astParsing.visitors.VariableCollector;
import anthonisen.felix.util.Pair;
import anthonisen.felix.astParsing.visitors.ClassCollector;

import java.io.File;
import java.nio.file.Paths;
import java.util.Arrays;
Expand All @@ -29,7 +31,6 @@ public class Covariancer {
private Messager messager;
private String sourceFolder;
private SourceRoot sourceRoot;
private Map<String, CompilationUnit> compilationUnits = new HashMap<>();

public Covariancer(Messager messager, String sourceFolder) {
this.messager = messager;
Expand All @@ -45,55 +46,50 @@ public void eraseTypesAndInsertCasts(String cls, String packageName, String type
assert dir.exists();
assert dir.isDirectory();

Set<ClassData> classesToWatch = computeClassesToWatch(dir, "");
ClassData classData = computeClassData(cls, packageName, typeOfInterest);
System.out.println(classData);
Map<String, MethodData> methodMap = new HashMap<>();

sourceRoot.parse(packageName, cls).accept(new MethodCollector(Arrays.asList(typeOfInterest)),
methodMap);
messager.printMessage(Kind.NOTE,
String.format("Method data collected for class %s and param %s", cls, typeOfInterest));
for (var m : methodMap.values()) {
messager.printMessage(Kind.NOTE, m.toString());
}
changeAST(dir, classesToWatch, methodMap, "");

changeAST(dir, classData, methodMap, "");

}

private Set<ClassData> computeClassesToWatch(File dir, String packageName) {
Set<ClassData> classesToWatch = new HashSet<>();
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
if (!file.getName().equals("output"))
classesToWatch
.addAll(computeClassesToWatch(file, appendPackageDeclaration(packageName, file.getName())));
continue;
private ClassData computeClassData(String cls, String packageName, String typeOfInterest) {
CompilationUnit cu = sourceRoot.parse(packageName, cls);
var a = cu.findAll(ClassOrInterfaceDeclaration.class).get(0).getTypeParameters();
for (int i = 0; i < a.size(); ++i) {
TypeParameter type = a.get(i);
NodeList<ClassOrInterfaceType> boundList = type.getTypeBound();
String leftMostBound = boundList == null || boundList.size() == 0 ? "Object" : boundList.get(0).asString();
if (type.getNameAsString().equals(typeOfInterest)) {
a.get(i);
return new ClassData(cls.replaceFirst("\\.java$", ""), leftMostBound, i);
}
CompilationUnit cu = sourceRoot.parse(packageName, file.getName());
cu.accept(new ClassCollector(), classesToWatch);

}
return classesToWatch;
return null;
}

private void changeAST(File dir, Set<ClassData> classesToWatch, Map<String, MethodData> methodMap,
private void changeAST(File dir, ClassData classData, Map<String, MethodData> methodMap,
String packageName) {
for (File file : dir.listFiles()) {
String fileName = file.getName();
if (file.isDirectory()) {
if (!fileName.equals("output"))
changeAST(file, classesToWatch, methodMap, appendPackageDeclaration(packageName, fileName));
changeAST(file, classData, methodMap, appendPackageDeclaration(packageName, fileName));
continue;
}
if (!isJavaFile(file))
continue;

CompilationUnit cu = compilationUnits.getOrDefault(fileName,
sourceRoot.parse(packageName, fileName));
if (compilationUnits.putIfAbsent(fileName, cu) != null)
messager.printMessage(Kind.NOTE, "Already created cu for class " + fileName);
CompilationUnit cu = sourceRoot.parse(packageName, fileName);

Set<Pair<String, String>> varsToWatch = new HashSet<>();
cu.accept(new VariableCollector(classesToWatch), varsToWatch);
cu.accept(new TypeEraserVisitor(classesToWatch), null);
cu.accept(new VariableCollector(classData), varsToWatch);
cu.accept(new TypeEraserVisitor(classData), null);
for (Pair<String, String> var : varsToWatch) {
CastInsertionVisitor castInsertionVisitor = new CastInsertionVisitor(var, methodMap);
cu.accept(castInsertionVisitor, null);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package anthonisen.felix.astParsing.util;

public record ClassData(String className, String leftmostBound) {
public record ClassData(String className, String leftmostBound, int indexOfParam) {

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,27 @@
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.visitor.ModifierVisitor;
import com.github.javaparser.ast.visitor.Visitable;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import anthonisen.felix.astParsing.util.ClassData;
import anthonisen.felix.astParsing.util.TypeHandler;

public class TypeEraserVisitor extends ModifierVisitor<Void> {

Map<String, String> classCasts = new HashMap<>();
private ClassData classData;

public TypeEraserVisitor(Set<ClassData> classData) {
classData
.forEach(data -> classCasts.put(data.className(), data.className() + "<" + data.leftmostBound() + ">"));
public TypeEraserVisitor(ClassData classData) {
this.classData = classData;
}

@Override
public Visitable visit(VariableDeclarationExpr n, Void arg) {
TypeHandler.replaceTypes(n.getElementType(), classCasts);
TypeHandler.replaceTypeArgument(n.getElementType(), classData.className(), classData.indexOfParam(),
classData.leftmostBound());
return super.visit(n, arg);
}

public Visitable visit(Parameter n, Void arg) {
TypeHandler.replaceTypes(n.getType(), classCasts);
TypeHandler.replaceTypeArgument(n.getType(), classData.className(), classData.indexOfParam(),
classData.leftmostBound());
return super.visit(n, arg);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package anthonisen.felix.astParsing.visitors;

import java.util.HashSet;
import java.util.Set;

import com.github.javaparser.ast.body.Parameter;
Expand All @@ -14,10 +13,10 @@
import com.github.javaparser.ast.type.Type;

public class VariableCollector extends VoidVisitorAdapter<Set<Pair<String, String>>> {
Set<String> classesToWatch = new HashSet<>();
ClassData classData;

public VariableCollector(Set<ClassData> classData) {
classData.forEach(data -> classesToWatch.add(data.className()));
public VariableCollector(ClassData classData) {
this.classData = classData;
}

@Override
Expand All @@ -38,8 +37,8 @@ private void handleType(String varName, Type type, Set<Pair<String, String>> arg

ClassOrInterfaceType classType = (ClassOrInterfaceType) type;

if (!classesToWatch.contains(classType.getNameAsString()))
if (!classData.className().equals(classType.getNameAsString()))
return; // visit typeparams, if present
arg.add(new Pair<>(varName, classType.getTypeArguments().get().get(0).toString()));
arg.add(new Pair<>(varName, classType.getTypeArguments().get().get(classData.indexOfParam()).toString()));
}
}

0 comments on commit 1e7a662

Please sign in to comment.