From 5b970f93592dab4607a4e9624ebd4c625e73b5a1 Mon Sep 17 00:00:00 2001 From: Etienne Zink Date: Sun, 3 Apr 2022 15:47:03 +0200 Subject: [PATCH] =?UTF-8?q?Hinzuf=C3=BCgen=20von=20FunNGenerator=20Tests?= =?UTF-8?q?=20und=20Bugfixing=20bei=20generateSpecializedBytecode().=20TPH?= =?UTF-8?q?s=20werden=20nun=20direkt=20zu=20Generics=20substituiert=20und?= =?UTF-8?q?=20TypeToSignature=20wurde=20verbessert,=20sodass=20korrekte=20?= =?UTF-8?q?Signaturen=20f=C3=BCr=20Generics=20generiert=20werden.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bytecode/funN/FunNGenerator.java | 20 ++- .../bytecode/signature/TypeToSignature.java | 13 +- .../java/bytecode/funN/FunNGeneratorTest.java | 141 +++++++++++++++--- 3 files changed, 144 insertions(+), 30 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/bytecode/funN/FunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/funN/FunNGenerator.java index e3c44223..6fb10244 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/funN/FunNGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/funN/FunNGenerator.java @@ -56,11 +56,11 @@ public final class FunNGenerator implements FunNUtilities{ for (int currentParameter = 1; currentParameter <= numberArguments; currentParameter++){ superFunNClassSignature.append(String.format("%s%d:%s",argumentGenericBase, currentParameter, objectSignature)); - superFunNMethodSignature.append(String.format("T%s;", applySignature( new GenericRefType(argumentGenericBase + currentParameter, null)))); + superFunNMethodSignature.append(applySignature( new GenericRefType(argumentGenericBase + currentParameter, null))); superFunNMethodDescriptor.append(objectSignature); } superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature)); - superFunNMethodSignature.append(String.format(")T%s;", applySignature(new GenericRefType(returnGeneric, null)))); + superFunNMethodSignature.append(String.format(")%s", applySignature(new GenericRefType(returnGeneric, null)))); superFunNMethodDescriptor.append(String.format(")%s", objectSignature)); ClassWriter classWriter = new ClassWriter(0); @@ -81,8 +81,10 @@ public final class FunNGenerator implements FunNUtilities{ public byte[] generateSpecializedBytecode(List argumentTypes, RefTypeOrTPHOrWildcardOrGeneric returnType) { Objects.requireNonNull(argumentTypes); Objects.requireNonNull(returnType); + //generates a list of all params and substitutes the TPH List parameters = Stream .concat(argumentTypes.stream(), Stream.of(returnType)) + .map(FunNGenerator::substituteTPH) .collect(Collectors.toList()); RefType superFunN = new RefType(new JavaClassName(getSuperClassName(argumentTypes.size())), parameters , null); StringBuilder funNClassSignature = new StringBuilder(objectSignature + (superFunN.acceptTV(new TypeToSignature(false)))); @@ -94,12 +96,6 @@ public final class FunNGenerator implements FunNUtilities{ GenericRefType generic = (GenericRefType) typeArgument; String signatureOfArgument = generic.getParsedName(); if(genericSignature.contains(signatureOfArgument)) continue; - genericSignature += String.format("%s:%s", signatureOfArgument, applyDescriptor(generic)); - containsGeneric = true; - } else if(typeArgument instanceof TypePlaceholder){ - TypePlaceholder placeholder = (TypePlaceholder) typeArgument; - String signatureOfArgument = applySignature(placeholder).substring(1); - if(genericSignature.contains(signatureOfArgument)) continue; genericSignature += String.format("%s:%s", signatureOfArgument, objectSignature); containsGeneric = true; } @@ -166,4 +162,12 @@ public final class FunNGenerator implements FunNUtilities{ * @return the name for the type {@code a} which should be used in the specialized name for FunN. */ private String applyNameDescriptor(RefTypeOrTPHOrWildcardOrGeneric a){ return a instanceof TypePlaceholder ? "LTPH;" : String.format("L%s;", applyDescriptor(a)); } + + private static RefTypeOrTPHOrWildcardOrGeneric substituteTPH(RefTypeOrTPHOrWildcardOrGeneric t) { + if (t instanceof TypePlaceholder) { + TypePlaceholder tph = (TypePlaceholder) t; + return new GenericRefType(tph.getName()+"$", t.getOffset()); + } + return t; + } } diff --git a/src/main/java/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java b/src/main/java/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java index 0026b85f..47ce65e4 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/signature/TypeToSignature.java @@ -102,9 +102,20 @@ public class TypeToSignature implements TypeVisitor { return sig; } + /** + * Changed that the correct signature is returned: + * returns now T...; expect of only ... + * where ... is {@code genericRefType.getParsedName()} + * + * @since Studienarbeit Type Erasure + * @author etiennezink + * + * @param genericRefType + * @return + */ @Override public String visit(GenericRefType genericRefType) { - return genericRefType.getParsedName().replace(".", "/"); + return String.format("T%s;", genericRefType.getParsedName()).replace(".", "/"); } private Optional getEqualTPHFromClassConstraints(List listOfConstraints, String tph) { diff --git a/src/test/java/bytecode/funN/FunNGeneratorTest.java b/src/test/java/bytecode/funN/FunNGeneratorTest.java index 89a2ad1c..d648f6a1 100644 --- a/src/test/java/bytecode/funN/FunNGeneratorTest.java +++ b/src/test/java/bytecode/funN/FunNGeneratorTest.java @@ -8,12 +8,13 @@ import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import org.junit.BeforeClass; import org.junit.Test; +import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; import java.util.Arrays; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; +import static org.objectweb.asm.Opcodes.*; public class FunNGeneratorTest { @@ -23,108 +24,206 @@ public class FunNGeneratorTest { static GenericRefType genericT = new GenericRefType("T", null); @BeforeClass - public static void StartUp(){ + public static void setUp(){ funNGenerator = FunNGenerator.getInstance(); } @Test - public void SuperClassName_0(){ + public void superClassName_0(){ var superClassName = funNGenerator.getSuperClassName(0); assertEquals("Fun0$$", superClassName); } @Test - public void SuperClassName_1(){ + public void superClassName_1(){ var superClassName = funNGenerator.getSuperClassName(1); assertEquals("Fun1$$", superClassName); } @Test - public void SpecializedClassName_VoidVoid(){ + public void specializedClassName_VoidVoid(){ var specializedClassName = funNGenerator.getSpecializedClassName(Arrays.asList(), voidType); assertEquals("Fun0$$Ljava$lang$Void$_$", specializedClassName); } @Test - public void SpecializedClassName_VoidInt(){ + public void specializedClassName_VoidInt(){ var specializedClassName = funNGenerator.getSpecializedClassName(Arrays.asList(), integerType); assertEquals("Fun0$$Ljava$lang$Integer$_$", specializedClassName); } @Test - public void SpecializedClassName_IntInt(){ + public void specializedClassName_IntInt(){ var specializedClassName = funNGenerator.getSpecializedClassName(Arrays.asList(integerType), integerType); assertEquals("Fun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$", specializedClassName); } @Test - public void SpecializedClassName_IntT(){ + public void specializedClassName_IntT(){ var specializedClassName = funNGenerator.getSpecializedClassName(Arrays.asList(integerType), genericT); assertEquals("Fun1$$Ljava$lang$Integer$_$LT$_$", specializedClassName); } @Test - public void SpecializedClassName_IntTPH(){ + public void specializedClassName_IntTPH(){ var specializedClassName = funNGenerator.getSpecializedClassName(Arrays.asList(integerType), TypePlaceholder.fresh(null)); assertEquals("Fun1$$Ljava$lang$Integer$_$LTPH$_$", specializedClassName); } @Test - public void Signature_IntInt(){ + public void signature_IntInt(){ var classSignature = funNGenerator.getSpecializedSignature(Arrays.asList(integerType), integerType); assertEquals("LFun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$;", classSignature); } @Test - public void Signature_IntT(){ + public void signature_IntT(){ var classSignature = funNGenerator.getSpecializedSignature(Arrays.asList(integerType), genericT); assertEquals("LFun1$$Ljava$lang$Integer$_$LT$_$;", classSignature); } @Test - public void Descriptor_IntInt(){ + public void descriptor_IntInt(){ var classSignature = funNGenerator.getSpecializedDescriptor(Arrays.asList(integerType), integerType); //does not have to contain L and ; because TypeToDescriptor returns the descriptor without these characters as well assertEquals("Fun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$", classSignature); } @Test - public void Descriptor_IntT(){ + public void descriptor_IntT(){ var classSignature = funNGenerator.getSpecializedDescriptor(Arrays.asList(integerType), genericT); //does not have to contain L and ; because TypeToDescriptor returns the descriptor without these characters as well assertEquals("Fun1$$Ljava$lang$Integer$_$LT$_$", classSignature); } @Test - public void GetArguments_Empty(){ + public void getArguments_Empty(){ var arguments = funNGenerator.getArguments(Arrays.asList()); assertTrue(arguments.isEmpty()); } @Test - public void GetArguments_Int(){ + public void getArguments_Int(){ var arguments = funNGenerator.getArguments(Arrays.asList(integerType)); assertTrue(arguments.isEmpty()); } @Test - public void GetArguments_IntT(){ + public void getArguments_IntT(){ var arguments = funNGenerator.getArguments(Arrays.asList(integerType, genericT)); assertTrue(arguments.size() == 1); assertTrue(arguments.contains(integerType)); } @Test - public void GetArguments_IntTInt(){ + public void getArguments_IntTInt(){ var arguments = funNGenerator.getArguments(Arrays.asList(integerType, genericT, integerType)); assertTrue(arguments.size() == 2); assertTrue(arguments.contains(integerType)); assertTrue(arguments.contains(genericT)); } - //ToDo Etienne: get return Type Test + @Test + public void getReturnType_Empty(){ + var returnType = funNGenerator.getReturnType(Arrays.asList()); + assertNull(returnType); + } - //ToDo Etienne: Super Bytecode Test + @Test + public void getReturnType_Int(){ + var returnType = funNGenerator.getReturnType(Arrays.asList(integerType)); + assertEquals(integerType, returnType); + } - //ToDo Etienne: Specialized Bytecode Test + @Test + public void getReturnType_IntT(){ + var returnType = funNGenerator.getReturnType(Arrays.asList(integerType, genericT)); + assertEquals(genericT, returnType); + } + + @Test + public void superBytecode_0(){ + var superBytecode = funNGenerator.generateSuperBytecode(0); + assertArrayEquals(superBytecodeReference_0(), superBytecode); + } + + @Test + public void superBytecode_1(){ + var superBytecode = funNGenerator.generateSuperBytecode(1); + assertArrayEquals(superBytecodeReference_1(), superBytecode); + } + + @Test + public void superBytecode_2(){ + var superBytecode = funNGenerator.generateSuperBytecode(2); + assertArrayEquals(superBytecodeReference_2(), superBytecode); + } + + @Test + public void specializedBytecode_VoidInt(){ + var specializedBytecode = funNGenerator.generateSpecializedBytecode(Arrays.asList(), integerType); + assertArrayEquals(specializedBytecodeReference_VoidInt(), specializedBytecode); + } + + @Test + public void specializedBytecode_IntInt(){ + var specializedBytecode = funNGenerator.generateSpecializedBytecode(Arrays.asList(integerType), integerType); + assertArrayEquals(specializedBytecodeReference_IntInt(), specializedBytecode); + } + + @Test + public void specializedBytecode_TIntInt(){ + var specializedBytecode = funNGenerator.generateSpecializedBytecode(Arrays.asList(genericT, integerType), integerType); + assertArrayEquals(specializedBytecodeReference_TIntInt(), specializedBytecode); + } + + //super bytecode reference methods + private static byte[] superBytecodeReference_0() { + var classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun0$$", "Ljava/lang/Object;", "java/lang/Object", null); + var methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", "()Ljava/lang/Object;", "()TR;", null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private static byte[] superBytecodeReference_1() { + var classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun1$$", "Ljava/lang/Object;", "java/lang/Object", null); + var methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", "(TT1;)TR;", null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private static byte[] superBytecodeReference_2() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun2$$", "Ljava/lang/Object;", "java/lang/Object", null); + var methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", "(TT1;TT2;)TR;", null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + //specialized bytecode reference methods + private static byte[] specializedBytecodeReference_VoidInt() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun0$$Ljava$lang$Integer$_$", "Ljava/lang/Object;LFun0$$;", "java/lang/Object", new String[]{"Fun0$$"}); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private static byte[] specializedBytecodeReference_IntInt() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$", "Ljava/lang/Object;LFun1$$;", "java/lang/Object", new String[]{"Fun1$$"}); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } + + private static byte[] specializedBytecodeReference_TIntInt() { + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "Fun2$$LT$_$Ljava$lang$Integer$_$Ljava$lang$Integer$_$", "Ljava/lang/Object;LFun2$$;", "java/lang/Object", new String[]{"Fun2$$"}); + classWriter.visitEnd(); + return classWriter.toByteArray(); + } }