From 1e7a662960d9f9c5ee74d873e4ad59af019e2232 Mon Sep 17 00:00:00 2001 From: FelixAnthonisen Date: Fri, 25 Oct 2024 19:38:47 +0200 Subject: [PATCH] proper casts and erasure for arbitrary amount of type args --- .../felix/astParsing/Covariancer.java | 54 +++++++++---------- .../felix/astParsing/util/ClassData.java | 2 +- .../astParsing/visitors/ClassCollector.java | 22 -------- .../visitors/TypeEraserVisitor.java | 18 +++---- .../visitors/VariableCollector.java | 11 ++-- 5 files changed, 38 insertions(+), 69 deletions(-) delete mode 100644 src/main/java/anthonisen/felix/astParsing/visitors/ClassCollector.java diff --git a/src/main/java/anthonisen/felix/astParsing/Covariancer.java b/src/main/java/anthonisen/felix/astParsing/Covariancer.java index 160b474..43bcf69 100644 --- a/src/main/java/anthonisen/felix/astParsing/Covariancer.java +++ b/src/main/java/anthonisen/felix/astParsing/Covariancer.java @@ -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; @@ -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; @@ -29,7 +31,6 @@ public class Covariancer { private Messager messager; private String sourceFolder; private SourceRoot sourceRoot; - private Map compilationUnits = new HashMap<>(); public Covariancer(Messager messager, String sourceFolder) { this.messager = messager; @@ -45,55 +46,50 @@ public void eraseTypesAndInsertCasts(String cls, String packageName, String type assert dir.exists(); assert dir.isDirectory(); - Set classesToWatch = computeClassesToWatch(dir, ""); + ClassData classData = computeClassData(cls, packageName, typeOfInterest); + System.out.println(classData); Map 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 computeClassesToWatch(File dir, String packageName) { - Set 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 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 classesToWatch, Map methodMap, + private void changeAST(File dir, ClassData classData, Map 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> 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 var : varsToWatch) { CastInsertionVisitor castInsertionVisitor = new CastInsertionVisitor(var, methodMap); cu.accept(castInsertionVisitor, null); diff --git a/src/main/java/anthonisen/felix/astParsing/util/ClassData.java b/src/main/java/anthonisen/felix/astParsing/util/ClassData.java index f6d21aa..ab560c3 100644 --- a/src/main/java/anthonisen/felix/astParsing/util/ClassData.java +++ b/src/main/java/anthonisen/felix/astParsing/util/ClassData.java @@ -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) { } diff --git a/src/main/java/anthonisen/felix/astParsing/visitors/ClassCollector.java b/src/main/java/anthonisen/felix/astParsing/visitors/ClassCollector.java deleted file mode 100644 index 0ae1154..0000000 --- a/src/main/java/anthonisen/felix/astParsing/visitors/ClassCollector.java +++ /dev/null @@ -1,22 +0,0 @@ -package anthonisen.felix.astParsing.visitors; - -import java.util.Set; - -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import com.github.javaparser.ast.type.ClassOrInterfaceType; -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; - -import anthonisen.felix.astParsing.util.ClassData; - -public class ClassCollector extends VoidVisitorAdapter> { - @Override - public void visit(ClassOrInterfaceDeclaration n, Set arg) { - super.visit(n, arg); - if (n.getTypeParameters().isNonEmpty()) { - NodeList boundList = n.getTypeParameter(0).getTypeBound(); - arg.add(new ClassData(n.getNameAsString(), - boundList == null || boundList.size() == 0 ? "Object" : boundList.get(0).asString())); - } - } -} diff --git a/src/main/java/anthonisen/felix/astParsing/visitors/TypeEraserVisitor.java b/src/main/java/anthonisen/felix/astParsing/visitors/TypeEraserVisitor.java index 78d13f5..7aa21d8 100644 --- a/src/main/java/anthonisen/felix/astParsing/visitors/TypeEraserVisitor.java +++ b/src/main/java/anthonisen/felix/astParsing/visitors/TypeEraserVisitor.java @@ -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 { - Map classCasts = new HashMap<>(); + private ClassData classData; - public TypeEraserVisitor(Set 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); } } diff --git a/src/main/java/anthonisen/felix/astParsing/visitors/VariableCollector.java b/src/main/java/anthonisen/felix/astParsing/visitors/VariableCollector.java index a329ea2..366c247 100644 --- a/src/main/java/anthonisen/felix/astParsing/visitors/VariableCollector.java +++ b/src/main/java/anthonisen/felix/astParsing/visitors/VariableCollector.java @@ -1,6 +1,5 @@ package anthonisen.felix.astParsing.visitors; -import java.util.HashSet; import java.util.Set; import com.github.javaparser.ast.body.Parameter; @@ -14,10 +13,10 @@ import com.github.javaparser.ast.type.Type; public class VariableCollector extends VoidVisitorAdapter>> { - Set classesToWatch = new HashSet<>(); + ClassData classData; - public VariableCollector(Set classData) { - classData.forEach(data -> classesToWatch.add(data.className())); + public VariableCollector(ClassData classData) { + this.classData = classData; } @Override @@ -38,8 +37,8 @@ private void handleType(String varName, Type type, Set> 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())); } }