diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 10f3452f..9493b673 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -1,8 +1,6 @@ package de.dhbwstuttgart.target.generate; -import com.google.j2objc.annotations.LoopTranslation; import de.dhbwstuttgart.bytecode.funN.FunNGenerator; -import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.factory.ASTFactory; @@ -89,6 +87,19 @@ public class ASTToTargetAST { return containsLeft && containsRight; } + static void addToPairs(Set> input, ResultPair pair) { + if (pair instanceof PairTPHsmallerTPH) { + input.removeIf(pair2 -> { + if (pair2 instanceof PairTPHequalRefTypeOrWildcardType) { + return pair2.getLeft().equals(pair.getLeft()) && pair2.getRight().equals(OBJECT); + } + return false; + }); + } + + input.add(pair); + } + // Family of generated Generics Set> generics(ClassOrInterface owner, Method method) { if (computedGenericsOfMethods.containsKey(method)) @@ -133,7 +144,7 @@ public class ASTToTargetAST { for (var typeVariable : new HashSet<>(typeVariables)) { for (var pair : simplifiedConstraints) { if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) { - result.add(new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); + addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); typeVariables.add(pair.right); } } @@ -199,7 +210,7 @@ public class ASTToTargetAST { newPairs.add(newPair); if (!containsRelation(result, newPair)) - result.add(newPair); + addToPairs(result, newPair); continue outer; } } @@ -216,7 +227,7 @@ public class ASTToTargetAST { for (var typeVariable : new HashSet<>(typeVariables)) { for (var pair : simplifiedConstraints) { if (pair.left.equals(typeVariable) && typeVariablesOfFields.contains(pair.right)) { - result.add(new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); + addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); typeVariables.add(pair.right); } } @@ -230,7 +241,7 @@ public class ASTToTargetAST { continue outer; } if (!hasBound(typeVariable, genericsOfClass)) - result.add(new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT)); + addToPairs(result, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT)); } // All unbounded bounds @@ -241,7 +252,7 @@ public class ASTToTargetAST { continue outer; } if (!hasBound(pair.right, genericsOfClass) && typeVariables.contains(pair.right)) - result.add(new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT)); + addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT)); } eliminateCyclesAndInfima(result); @@ -309,7 +320,7 @@ public class ASTToTargetAST { for (var pair2 : new HashSet<>(input)) { if (pair2 instanceof PairTPHsmallerTPH ptph2 && ptph2.right.equals(ptph.left)) { input.remove(pair2); - input.add(new PairTPHsmallerTPH(ptph2.left, ptph.right)); + addToPairs(input, new PairTPHsmallerTPH(ptph2.left, ptph.right)); } } } @@ -351,9 +362,9 @@ public class ASTToTargetAST { if (pair2.getRight().equals(pair.getLeft())) { input.remove(pair2); if (pair instanceof PairTPHsmallerTPH) - input.add(new PairTPHsmallerTPH((TypePlaceholder) pair2.getLeft(), (TypePlaceholder) pair.getRight())); + addToPairs(input, new PairTPHsmallerTPH((TypePlaceholder) pair2.getLeft(), (TypePlaceholder) pair.getRight())); else - input.add(new PairTPHequalRefTypeOrWildcardType((TypePlaceholder) pair2.getLeft(), pair.getRight())); + addToPairs(input, new PairTPHequalRefTypeOrWildcardType((TypePlaceholder) pair2.getLeft(), pair.getRight())); } } } @@ -365,7 +376,7 @@ public class ASTToTargetAST { var cycles = findCycles(input); for (var cycle : cycles) { var newTph = TypePlaceholder.fresh(new NullToken()); - input.add(new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT)); + addToPairs(input, new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT)); cycle.add(cycle.get(0)); // Make it a complete cycle for (var i = 0; i < cycle.size() - 1; i++) { var left = cycle.get(i); @@ -390,7 +401,7 @@ public class ASTToTargetAST { if (infima.size() > 1) { foundInfima = true; var newTph = TypePlaceholder.fresh(new NullToken()); - input.add(new PairTPHsmallerTPH(left, newTph)); + addToPairs(input, new PairTPHsmallerTPH(left, newTph)); input.removeAll(infima); for (var infimum : infima) { equality.put(infimum.right, newTph); @@ -398,14 +409,14 @@ public class ASTToTargetAST { if (pair.getLeft().equals(infimum.right)) { input.remove(pair); if (pair instanceof PairTPHsmallerTPH stph) { - input.add(new PairTPHsmallerTPH(newTph, stph.right)); + addToPairs(input, new PairTPHsmallerTPH(newTph, stph.right)); } else if (pair instanceof PairTPHequalRefTypeOrWildcardType rtph) { - input.add(new PairTPHequalRefTypeOrWildcardType(newTph, rtph.getRight())); + addToPairs(input, new PairTPHequalRefTypeOrWildcardType(newTph, rtph.getRight())); } } else if (pair.getRight().equals(infimum.right)) { input.remove(pair); if (pair instanceof PairTPHsmallerTPH stph) { - input.add(new PairTPHsmallerTPH(stph.left, newTph)); + addToPairs(input, new PairTPHsmallerTPH(stph.left, newTph)); } } }); @@ -413,15 +424,6 @@ public class ASTToTargetAST { } } } while (foundInfima); - - // Remove duplicate bounds - for (var pair : new HashSet<>(input)) { - if (pair instanceof PairTPHequalRefTypeOrWildcardType) { - if (input.stream().anyMatch(p -> p instanceof PairTPHsmallerTPH && p.getLeft().equals(pair.getLeft()))) { - input.remove(pair); - } - } - } } TargetType get(TypePlaceholder tph) { diff --git a/src/test/java/targetast/TestComplete.java b/src/test/java/targetast/TestComplete.java index 83ea8ec4..ab42a8b6 100644 --- a/src/test/java/targetast/TestComplete.java +++ b/src/test/java/targetast/TestComplete.java @@ -4,7 +4,9 @@ import de.dhbwstuttgart.target.ByteArrayClassLoader; import org.junit.Ignore; import org.junit.Test; +import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.TypeVariable; import java.util.Arrays; import java.util.Vector; @@ -135,6 +137,7 @@ public class TestComplete { public void infTest() throws Exception { var classFiles = generateClassFiles("Inf.jav", new ByteArrayClassLoader()); var instance = classFiles.get("Inf").getDeclaredConstructor().newInstance(); + // TODO check generics } @Test @@ -342,13 +345,53 @@ public class TestComplete { @Test public void tph2Test() throws Exception { var classFiles = generateClassFiles("Tph2.jav", new ByteArrayClassLoader()); - var instance = classFiles.get("Tph2").getDeclaredConstructor().newInstance(); + var tph2 = classFiles.get("Tph2"); + var instance = tph2.getDeclaredConstructor().newInstance(); + + assertEquals(1, tph2.getTypeParameters().length); + // public class Tph2 + var DZG = tph2.getTypeParameters()[0]; + + var id = tph2.getDeclaredField("id"); + // public Fun1$$ id + var idParams = ((ParameterizedType) id.getGenericType()).getActualTypeArguments(); + assertEquals(2, idParams.length); + assertEquals(DZG, idParams[0]); + assertEquals(DZG, idParams[1]); + + var id3 = tph2.getDeclaredMethod("id3", Object.class); + // public DZG id3(U var1) + var paraTypes = id3.getGenericParameterTypes(); + var typeParaTypes = id3.getTypeParameters(); + + var U = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[0])).findFirst().get(); + assertEquals(DZG, U.getBounds()[0]); + assertEquals(DZG, id3.getGenericReturnType()); } @Test public void tph3Test() throws Exception { var classFiles = generateClassFiles("Tph3.jav", new ByteArrayClassLoader()); - var instance = classFiles.get("Tph3").getDeclaredConstructor().newInstance(); + var tph3 = classFiles.get("Tph3"); + var instance = tph3.getDeclaredConstructor().newInstance(); + var m1 = tph3.getDeclaredMethod("m1", Object.class, Object.class); + + // public void m1(DZC var1, DZC var2) + var paraTypes = m1.getGenericParameterTypes(); + var typeParaTypes = m1.getTypeParameters(); + + var DZC = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[0])).findFirst().get(); + assertEquals(DZC, Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[1])).findFirst().get()); + assertEquals(Object.class, DZC.getBounds()[0]); + + var m2 = tph3.getDeclaredMethod("m2", Object.class); + + // public void m2(V var1) + var paraTypes2 = m2.getGenericParameterTypes(); + var typeParaTypes2 = m2.getTypeParameters(); + + var V = Arrays.stream(typeParaTypes2).filter(t -> t.equals(paraTypes2[0])).findFirst().get(); + assertEquals(Object.class, V.getBounds()[0]); } @Test @@ -356,6 +399,30 @@ public class TestComplete { var classFiles = generateClassFiles("Tph4.jav", new ByteArrayClassLoader()); var tph4 = classFiles.get("Tph4"); var instance = tph4.getDeclaredConstructor().newInstance(); + var m = tph4.getDeclaredMethod("m", Object.class, Object.class); + + // public M m(N var1, O var2) + var paraTypes = m.getGenericParameterTypes(); + var typeParaTypes = m.getTypeParameters(); + + var N = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[0])).findFirst().get(); + assertEquals(Object.class, N.getBounds()[0]); + + var O = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[1])).findFirst().get(); + var P = Arrays.stream(typeParaTypes).filter(t -> t.equals(O.getBounds()[0])).findFirst().get(); + var M = Arrays.stream(typeParaTypes).filter(t -> t.equals(P.getBounds()[0])).findFirst().get(); + assertEquals(Object.class, M.getBounds()[0]); + assertEquals(M, m.getGenericReturnType()); + + var m2 = tph4.getDeclaredMethod("m2", Object.class); + + // public X m2(X var1) + var paraTypes2 = m2.getGenericParameterTypes(); + var typeParaTypes2 = m2.getTypeParameters(); + + var X = Arrays.stream(typeParaTypes2).filter(t -> t.equals(paraTypes2[0])).findFirst().get(); + assertEquals(Object.class, X.getBounds()[0]); + assertEquals(X, m2.getGenericReturnType()); } @Test @@ -364,6 +431,26 @@ public class TestComplete { var tph5 = classFiles.get("Tph5"); var instance = tph5.getDeclaredConstructor().newInstance(); var m = tph5.getDeclaredMethod("m", Object.class, Object.class); + + // public void m(N var1, O var2) + var paraTypes = m.getGenericParameterTypes(); + var typeParaTypes = m.getTypeParameters(); + + var N = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[0])).findFirst().get(); + var O = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[1])).findFirst().get(); + + assertEquals(O.getBounds()[0], N); + assertEquals(Object.class, N.getBounds()[0]); + + var m2 = tph5.getDeclaredMethod("m2", Object.class); + + // public R m2(R var1) + var paraTypes2 = m2.getGenericParameterTypes(); + var typeParaTypes2 = m2.getTypeParameters(); + + var R = Arrays.stream(typeParaTypes2).filter(t -> t.equals(paraTypes2[0])).findFirst().get(); + assertEquals(Object.class, R.getBounds()[0]); + assertEquals(R, m2.getGenericReturnType()); } @Test @@ -372,73 +459,96 @@ public class TestComplete { var tph5 = classFiles.get("Tph6"); var instance = tph5.getDeclaredConstructor().newInstance(); var m = tph5.getDeclaredMethod("m", Object.class, Object.class); + + // public void m(N var1, O var2) + var paraTypes = m.getGenericParameterTypes(); + var typeParaTypes = m.getTypeParameters(); + + var N = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[0])).findFirst().get(); + var O = Arrays.stream(typeParaTypes).filter(t -> t.equals(paraTypes[1])).findFirst().get(); + + var PT = N.getBounds()[0]; + assertEquals(PT, O.getBounds()[0]); + + var P = Arrays.stream(typeParaTypes).filter(t -> t.equals(PT)).findFirst().get(); + assertEquals(Object.class, P.getBounds()[0]); + + var m2 = tph5.getDeclaredMethod("m2", Object.class); + + // public W m2(W var1) + var paraTypes2 = m2.getGenericParameterTypes(); + var typeParaTypes2 = m2.getTypeParameters(); + + var W = Arrays.stream(typeParaTypes2).filter(t -> t.equals(paraTypes2[0])).findFirst().get(); + assertEquals(Object.class, W.getBounds()[0]); + assertEquals(W, m2.getGenericReturnType()); } - @Test - public void Tph7Test() throws Exception { - var classFiles = TestCodegen.generateClassFiles("Tph7.jav", new ByteArrayClassLoader()); - var classToTest = classFiles.get("Tph7"); - var instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + @Test + public void Tph7Test() throws Exception { + var classFiles = TestCodegen.generateClassFiles("Tph7.jav", new ByteArrayClassLoader()); + var classToTest = classFiles.get("Tph7"); + var instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); - //public DZU m(DZL, DZM); - Method m = classToTest.getDeclaredMethod("m", Object.class, Object.class); + //public DZU m(DZL, DZM); + Method m = classToTest.getDeclaredMethod("m", Object.class, Object.class); - //System.out.println(m.toString()); + //System.out.println(m.toString()); - //Argumenttypes of the method m - var paraTypes = m.getGenericParameterTypes(); + //Argumenttypes of the method m + var paraTypes = m.getGenericParameterTypes(); - //Typeparameters of the method m - var typeParaTypes = m.getTypeParameters(); + //Typeparameters of the method m + var typeParaTypes = m.getTypeParameters(); - //Typeparameters are extracted from the argumenttypes - //Conditions for the extracted typeparameters are set + //Typeparameters are extracted from the argumenttypes + //Conditions for the extracted typeparameters are set - //paraTypes[0] = DLZ - var boundFstArg = Arrays.stream(typeParaTypes) - .filter(x -> x.equals(paraTypes[0])).findFirst().get().getBounds(); + //paraTypes[0] = DLZ + var boundFstArg = Arrays.stream(typeParaTypes) + .filter(x -> x.equals(paraTypes[0])).findFirst().get().getBounds(); - //Bound of DLZ has to be Object - assertEquals(Object.class, Arrays.stream(boundFstArg).findFirst().get()); + //Bound of DLZ has to be Object + assertEquals(Object.class, Arrays.stream(boundFstArg).findFirst().get()); - //paraTypes[0] = DZM - var boundSndArg = Arrays.stream(typeParaTypes) - .filter(x -> x.equals(paraTypes[1])).findFirst().get().getBounds(); + //paraTypes[0] = DZM + var boundSndArg = Arrays.stream(typeParaTypes) + .filter(x -> x.equals(paraTypes[1])).findFirst().get().getBounds(); - //Bound of DZM has to be the return type of m - assertEquals(Arrays.stream(boundSndArg).findFirst().get(), m.getGenericReturnType()); + //Bound of DZM has to be the return type of m + assertEquals(Arrays.stream(boundSndArg).findFirst().get(), m.getGenericReturnType()); - //Bound of the bound of DZM - var boundBoundSndArg = Arrays.stream(typeParaTypes).filter(x -> x.equals(Arrays.stream(boundSndArg) - .findFirst().get())).findFirst().get().getBounds(); + //Bound of the bound of DZM + var boundBoundSndArg = Arrays.stream(typeParaTypes).filter(x -> x.equals(Arrays.stream(boundSndArg) + .findFirst().get())).findFirst().get().getBounds(); - //boundBoundSndArg have to be a type variable (type of the local variable c) - assertEquals(true, Arrays.stream(boundBoundSndArg).findFirst().get() instanceof TypeVariable); - m.getGenericParameterTypes(); + //boundBoundSndArg have to be a type variable (type of the local variable c) + assertEquals(true, Arrays.stream(boundBoundSndArg).findFirst().get() instanceof TypeVariable); + m.getGenericParameterTypes(); - //public DZU m2(DZU); - Method m2 = classToTest.getDeclaredMethod("m2", Object.class); + //public DZU m2(DZU); + Method m2 = classToTest.getDeclaredMethod("m2", Object.class); - //Argumenttypes of the method m2 - var paraTypesm2 = m2.getGenericParameterTypes(); + //Argumenttypes of the method m2 + var paraTypesm2 = m2.getGenericParameterTypes(); - //Typeparameters of the method m2 - var typeParaTypesm2 = m2.getTypeParameters(); + //Typeparameters of the method m2 + var typeParaTypesm2 = m2.getTypeParameters(); - //Typeparameters are extracted from the argumenttypes - //Conditions for the extracted typeparameters are set + //Typeparameters are extracted from the argumenttypes + //Conditions for the extracted typeparameters are set - //paraTypes[0] = DZU - var fstArgm2 = Arrays.stream(typeParaTypesm2) - .filter(x -> x.equals(paraTypesm2[0])).findFirst().get(); + //paraTypes[0] = DZU + var fstArgm2 = Arrays.stream(typeParaTypesm2) + .filter(x -> x.equals(paraTypesm2[0])).findFirst().get(); - //Bound of DZU has to be Object - assertEquals(Object.class, Arrays.stream(fstArgm2.getBounds()).findFirst().get()); + //Bound of DZU has to be Object + assertEquals(Object.class, Arrays.stream(fstArgm2.getBounds()).findFirst().get()); - //DZU has to be the return type of m - assertEquals(fstArgm2, m2.getGenericReturnType()); - } + //DZU has to be the return type of m + assertEquals(fstArgm2, m2.getGenericReturnType()); + } @Test @@ -464,4 +574,10 @@ public class TestComplete { var classFiles = generateClassFiles("Y.jav", new ByteArrayClassLoader()); var instance = classFiles.get("Y").getDeclaredConstructor().newInstance(); } + + @Test + public void boxTest() throws Exception { + var classFiles = generateClassFiles("Box.jav", new ByteArrayClassLoader()); + var instance = classFiles.get("Box_Main").getDeclaredConstructor().newInstance(); + } } diff --git a/src/test/resources/bytecode/javFiles/Box.jav b/src/test/resources/bytecode/javFiles/Box.jav new file mode 100644 index 00000000..e83bde6d --- /dev/null +++ b/src/test/resources/bytecode/javFiles/Box.jav @@ -0,0 +1,11 @@ +class Box { + void m(A a) { } +} + +class B { } +class Box_Main extends B { + m(b) { + b.m(new Box_Main()); + b.m(new B()); + } +}