package targetast; import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.Field; import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.target.generate.ASTToTargetAST; import static de.dhbwstuttgart.target.generate.ASTToTargetAST.OBJECT; import de.dhbwstuttgart.target.generate.Bound; import static de.dhbwstuttgart.target.generate.Bound.*; import de.dhbwstuttgart.target.generate.BoundsList; import de.dhbwstuttgart.target.generate.GenericsResult; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @Ignore("TODO: Rewrite with the new algorithm") public class TestGenerics { private static final String rootDirectory = System.getProperty("user.dir") + "/resources/insertGenerics/javFiles/"; private static final String bytecodeDirectory = System.getProperty("user.dir") + "targetTest"; private record Result(List genericsResults, ClassOrInterface clazz) { Method findMethod(String name) { return clazz.getMethods().stream().filter(m -> m.getName().equals(name)).findFirst().orElse(null); } Field findField(String name) { return clazz.getFieldDecl().stream().filter(field -> field.getName().equals(name)).findFirst().orElse(null); } } private static void assertStrictlyEquals(BoundsList a, BoundsList b) { assertEquals(a.base, b.base); assertEquals(a, b); } private static void assertStrictlyNotEquals(BoundsList a, BoundsList b) { assertNotEquals(a.base, b.base); } private static Result computeGenerics(String filename) throws IOException, ClassNotFoundException { var file = Path.of(rootDirectory + filename).toFile(); var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()), new File(bytecodeDirectory)); var inference = compiler.typeInference(file); compiler.generateBytecode(new File(bytecodeDirectory), inference); var sf = compiler.sourceFiles.get(file); var clazz = sf.getClasses().get(0); return new Result(compiler.getGeneratedGenerics().get(sf), clazz); } @Test public void testAny() throws Exception { var result = computeGenerics("TestAny.jav"); var anyMethod = result.findMethod("anyMethod"); var otherMethod = result.findMethod("otherMethod"); var a = result.findField("a"); var b = result.findField("b"); var generics = result.genericsResults.get(0); assertEquals(1, generics.get(anyMethod).size()); assertEquals(2, generics.get(result.clazz).size()); var ECK1 = generics.getBounds(otherMethod.getParameterList().getParameterAt(0).getType(), result.clazz, anyMethod); var ECK2 = generics.getBounds(otherMethod.getReturnType(), result.clazz, anyMethod); var ECKChain = new BoundsList(onClass(OBJECT)); assertStrictlyEquals(ECK1, ECK2); assertEquals(ECK2, generics.getBounds(b.getType(), result.clazz)); var M = generics.getBounds(a.getType(), result.clazz); var MChain = new BoundsList(onClass("ECK"), onClass(OBJECT)); assertEquals(M, MChain); } @Test public void testClassField() throws Exception { var result = computeGenerics("TestClassField.jav"); var fReturn = result.findMethod("fReturn"); var generics = result.genericsResults.get(0); assertEquals(1, generics.get(result.clazz).size()); assertEquals(0, generics.get(fReturn).size()); var N = generics.getBounds(fReturn.getReturnType(), result.clazz); var NChain = new BoundsList(onClass(OBJECT)); assertEquals(N, NChain); } @Test public void testContraVariant() throws Exception { var result = computeGenerics("TestContraVariant.jav"); var m = result.findMethod("m"); var main = result.findMethod("main"); var generics = result.genericsResults.get(0); assertEquals(0, generics.get(result.clazz).size()); assertEquals(3, generics.get(m).size()); assertEquals(3, generics.get(main).size()); { var AJ = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m); var AK = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m); var KWU = generics.getBounds(((RefType) generics.resolve(m.getReturnType())).getParaList().get(0), result.clazz, m); var AK2 = generics.getBounds(((RefType) generics.resolve(m.getReturnType())).getParaList().get(1), result.clazz, m); assertStrictlyEquals(AK, AK2); assertStrictlyNotEquals(AJ, KWU); var NChain = new BoundsList(onMethod(OBJECT)); assertEquals(AJ, NChain); assertEquals(AK, NChain); assertEquals(KWU, NChain); } { var O = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main); var P = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main); var KWQ = generics.getBounds(((RefType) generics.resolve(main.getReturnType())).getParaList().get(1), result.clazz, main); var O2 = generics.getBounds(((RefType) generics.resolve(main.getReturnType())).getParaList().get(0), result.clazz, main); assertStrictlyEquals(O, O2); assertStrictlyNotEquals(P, KWQ); var NChain = new BoundsList(onMethod(OBJECT)); assertEquals(O, NChain); assertEquals(P, NChain); assertEquals(KWQ, NChain); } } @Test public void testGGFinder() throws Exception { var result = computeGenerics("TestGGFinder.jav"); var id = result.findMethod("id"); var setA = result.findMethod("setA"); var m = result.findMethod("m"); var a = result.findField("a"); var generics = result.genericsResults.get(0); assertEquals(1, generics.get(result.clazz).size()); assertEquals(2, generics.get(id).size()); assertEquals(1, generics.get(setA).size()); assertEquals(2, generics.get(m).size()); var R = generics.getBounds(a.getType(), result.clazz); var RChain = new BoundsList(onClass(OBJECT)); assertEquals(R, RChain); var O = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id); var AB = generics.getBounds(id.getReturnType(), result.clazz, id); assertEquals(O, AB); assertEquals(AB, new BoundsList(onMethod(OBJECT))); var S = generics.getBounds(setA.getParameterList().getParameterAt(0).getType(), result.clazz, setA); assertEquals(S, RChain); assertEquals(generics.getBounds(setA.getReturnType(), result.clazz, setA), RChain); var X = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m); var Y = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m); var XChain = new BoundsList(onMethod(OBJECT)); assertEquals(X, XChain); assertEquals(Y, X); } @Test public void testLocalVarLambda() throws Exception { var result = computeGenerics("TestLocalVarLambda.jav"); // TODO Generics of lambdas } @Test public void testMutualRecursion() throws Exception { var result = computeGenerics("TestMutualRecursion.jav"); var id = result.findMethod("id"); var m = result.findMethod("m"); var main = result.findMethod("main"); var a = result.findField("a"); var generics = result.genericsResults.get(0); assertEquals(1, generics.get(result.clazz).size()); assertEquals(2, generics.get(id).size()); assertEquals(2, generics.get(m).size()); assertEquals(3, generics.get(main).size()); var N = generics.getBounds(a.getType(), result.clazz); assertEquals(N, new BoundsList(onClass(OBJECT))); var P = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id); var O = generics.getBounds(id.getReturnType(), result.clazz, id); assertEquals(P, O); assertEquals(O, new BoundsList(onMethod(OBJECT))); assertEquals(generics.resolve(m.getParameterList().getParameterAt(0).getType()), generics.resolve(m.getReturnType())); var Y = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m); var AA = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m); assertEquals(Y, AA); assertEquals(AA, new BoundsList(onMethod(OBJECT))); var AI = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m); var AJ = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m); var AH = generics.getBounds(m.getReturnType(), result.clazz, m); assertEquals(AI, AJ); assertEquals(AJ, AH); assertEquals(AH, new BoundsList(onMethod(OBJECT))); } @Test public void testReturnVar() throws Exception { var result = computeGenerics("TestReturnVar.jav"); var anyMethod = result.findMethod("anyMethod"); var generics = result.genericsResults.get(0); assertEquals(1, generics.get(anyMethod).size()); var M = generics.getBounds(anyMethod.getReturnType(), result.clazz, anyMethod); assertEquals(M, new BoundsList(onMethod(OBJECT))); } @Test public void testSecondLineOfClassConstraints() throws Exception { var result = computeGenerics("TestSecondLineOfClassConstraints.jav"); var a = result.findField("a"); var b = result.findField("b"); var anyMethod = result.findMethod("anyMethod"); var otherMethod = result.findMethod("otherMethod"); var generics = result.genericsResults.get(0); var M = generics.getBounds(a.getType(), result.clazz); var DYX = generics.getBounds(b.getType(), result.clazz); var MChain = new BoundsList(onClass("DYX"), onClass(OBJECT)); var DYXChain = new BoundsList(onClass(OBJECT)); assertEquals(M, MChain); var Q = generics.getBounds(anyMethod.getReturnType(), result.clazz, anyMethod); assertEquals(Q, new BoundsList(onMethod(OBJECT))); System.out.println(otherMethod.getReturnType()); var DYX2 = generics.getBounds(otherMethod.getReturnType(), result.clazz, otherMethod); assertEquals(DYX, DYX2); assertEquals(DYX, generics.getBounds(otherMethod.getReturnType(), result.clazz, otherMethod)); } @Test public void testThreeArgs() throws Exception { var result = computeGenerics("TestThreeArgs.jav"); } @Test public void testTPHsAndGenerics() throws Exception { var result = computeGenerics("TestTPHsAndGenerics.jav"); var id2 = result.findMethod("id2"); var m = result.findMethod("m"); var m2 = result.findMethod("m2"); var generics = result.genericsResults.get(0); var U = generics.getBounds(id2.getParameterList().getParameterAt(0).getType(), result.clazz, id2); var FPT = generics.getBounds(id2.getReturnType(), result.clazz, id2); assertEquals(U, new BoundsList(onMethod("FPT"), onClass(OBJECT))); assertEquals(FPT, new BoundsList(onClass(OBJECT))); var AA = generics.getBounds(m.getReturnType(), result.clazz, m); var AC = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m); assertEquals(AA, new BoundsList(onMethod(OBJECT))); assertEquals(AC, new BoundsList(onMethod(OBJECT))); var AH = generics.getBounds(m2.getReturnType(), result.clazz, m2); var AL = generics.getBounds(m2.getParameterList().getParameterAt(0).getType(), result.clazz, m2); assertEquals(AH, new BoundsList(onMethod(OBJECT))); assertEquals(AH, AL); } @Test public void testTwoArgs() throws Exception { var result = computeGenerics("TestTwoArgs.jav"); var a = result.findField("a"); var id = result.findMethod("id"); var setA = result.findMethod("setA"); var m = result.findMethod("m"); var main = result.findMethod("main"); var generics = result.genericsResults.get(0); var AO = generics.getBounds(a.getType(), result.clazz); var AOBound = new BoundsList( onClass("Y"), onClass("AK"), onClass("AE"), onClass(OBJECT) ); assertEquals(AO, AOBound); var S = generics.getBounds(setA.getParameterList().getParameterAt(0).getType(), result.clazz, setA); var c = new ArrayList(); c.add(onMethod("AO")); c.addAll(AOBound); var SChain = new BoundsList(c); assertEquals(S, SChain); var Y = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m); var YChain = new BoundsList(onMethod("AE"), onClass(OBJECT)); var AE = generics.getBounds(m.getReturnType(), result.clazz, m); assertEquals(Y, YChain); assertEquals(AE, new BoundsList(onClass(OBJECT))); // TODO main seems to change between runs /*var AE2 = generics.getBounds(main.getReturnType(), result.clazz, main); var AF = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main); var AG = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main); assertEquals(AE, AE2)); assertEquals(AF, new BoundsList(onMethod("AK"), onMethod("AE"), onClass(OBJECT)))); assertEquals(AG, SChain));*/ } @Test public void testTwoArgs2() throws Exception { var result = computeGenerics("TestTwoArgs2.jav"); // TODO Test generics } @Test public void testTwoCalls() throws Exception { var result = computeGenerics("TestTwoCalls.jav"); var id = result.findMethod("id"); var main = result.findMethod("main"); var generics = result.genericsResults.get(0); var O = generics.getBounds(id.getReturnType(), result.clazz, id); var O2 = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id); assertStrictlyEquals(O, O2); assertEquals(O2, new BoundsList(onMethod(OBJECT))); // TODO Maybe test in other ways if the parameter generics equals the return generics var S = generics.getBounds(main.getReturnType(), result.clazz, main); var S2 = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main); var T = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main); assertStrictlyEquals(S, S2); assertEquals(S2, new BoundsList(onMethod(OBJECT))); assertEquals(T, new BoundsList(onMethod(OBJECT))); } @Test public void testVector() throws Exception { var result = computeGenerics("TestVector.jav"); var m = result.findMethod("m"); var id = result.findMethod("id"); var generics = result.genericsResults.get(0); var par1 = generics.resolve(m.getParameterList().getParameterAt(0).getType()); var par2 = generics.resolve(m.getParameterList().getParameterAt(1).getType()); var S = generics.getBounds(((RefType) par1).getParaList().get(0), result.clazz, m); var ACM = generics.getBounds(((RefType) par2).getParaList().get(0), result.clazz, m); assertEquals(S, new BoundsList(onMethod("V"), onMethod(OBJECT))); assertEquals(ACM, new BoundsList(onMethod(OBJECT))); var Y = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id); assertEquals(Y, new BoundsList(onMethod(OBJECT))); assertEquals(Y, generics.getBounds(id.getReturnType(), result.clazz, id)); } @Test public void testVectorArg() throws Exception { var result = computeGenerics("TestVectorArg.jav"); var add = result.findMethod("add"); var main = result.findMethod("main"); var generics = result.genericsResults.get(0); var par1 = generics.resolve(add.getParameterList().getParameterAt(0).getType()); var ACK = generics.getBounds(((RefType) par1).getParaList().get(0), result.clazz, add); var O = generics.getBounds(add.getParameterList().getParameterAt(1).getType(), result.clazz, add); assertEquals(ACK, new BoundsList(onMethod(OBJECT))); assertEquals(O, new BoundsList(onMethod("ACK"), onMethod(OBJECT))); var par2 = generics.resolve(main.getParameterList().getParameterAt(0).getType()); var ACK2 = generics.getBounds(((RefType) par2).getParaList().get(0), result.clazz, add); var V = generics.getBounds(add.getParameterList().getParameterAt(1).getType(), result.clazz, add); assertStrictlyEquals(ACK2, ACK); assertEquals(V, O); } @Test public void testVoidMeth() throws Exception { var result = computeGenerics("TestVoidMeth.jav"); } @Test public void testAssign() throws Exception { // TODO Check generics var result = computeGenerics("TestAssign.jav"); } }