From a4b16ab323945c83e1d705997f00c95340e1bc2e Mon Sep 17 00:00:00 2001 From: Eric Bruneton Date: Sun, 25 Feb 2018 12:13:20 +0100 Subject: [PATCH] Add unit tests for GeneratorAdapter. Also exclude the deprecated Remapping* classes from code coverage stats. --- .../asm/commons/GeneratorAdapter.java | 34 +- .../asm/commons/GeneratorAdapterTest.java | 792 +++++++++++++++++- build.gradle | 13 +- 3 files changed, 807 insertions(+), 32 deletions(-) diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java b/asm-commons/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java index 87f68ca6..872c071f 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java @@ -173,6 +173,9 @@ public class GeneratorAdapter extends LocalVariablesSorter { /** Access flags of the method visited by this adapter. */ private final int access; + /** The name of the method visited by this adapter. */ + private final String name; + /** Return type of the method visited by this adapter. */ private final Type returnType; @@ -219,6 +222,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { final String desc) { super(api, access, desc, mv); this.access = access; + this.name = name; this.returnType = Type.getReturnType(desc); this.argumentTypes = Type.getArgumentTypes(desc); } @@ -233,7 +237,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { * @param mv the method visitor to which this adapter delegates calls. */ public GeneratorAdapter(final int access, final Method method, final MethodVisitor mv) { - this(mv, access, null, method.getDescriptor()); + this(mv, access, method.getName(), method.getDescriptor()); } /** @@ -281,6 +285,22 @@ public class GeneratorAdapter extends LocalVariablesSorter { return names; } + public int getAccess() { + return access; + } + + public String getName() { + return name; + } + + public Type getReturnType() { + return returnType; + } + + public Type[] getArgumentTypes() { + return argumentTypes.clone(); + } + // ------------------------------------------------------------------------ // Instructions to push constants on the stack // ------------------------------------------------------------------------ @@ -411,7 +431,11 @@ public class GeneratorAdapter extends LocalVariablesSorter { * @param handle the handle to be pushed on the stack. */ public void push(final Handle handle) { - mv.visitLdcInsn(handle); + if (handle == null) { + mv.visitInsn(Opcodes.ACONST_NULL); + } else { + mv.visitLdcInsn(handle); + } } // ------------------------------------------------------------------------ @@ -753,7 +777,9 @@ public class GeneratorAdapter extends LocalVariablesSorter { mv.visitInsn(Opcodes.I2L); } else if (to == Type.SHORT_TYPE) { mv.visitInsn(Opcodes.I2S); - } + } else { + throw new IllegalArgumentException(); + } } } } @@ -957,6 +983,8 @@ public class GeneratorAdapter extends LocalVariablesSorter { case GT: intOp = Opcodes.IF_ICMPGT; break; + default: + throw new IllegalArgumentException("Bad comparison mode " + mode); } mv.visitJumpInsn(intOp, label); return; diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java index 3923ff63..c90b79d7 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java @@ -27,10 +27,17 @@ // THE POSSIBILITY OF SUCH DAMAGE. package org.objectweb.asm.commons; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.objectweb.asm.commons.GeneratorAdapter.EQ; import static org.objectweb.asm.commons.GeneratorAdapter.GE; +import static org.objectweb.asm.commons.GeneratorAdapter.GT; import static org.objectweb.asm.commons.GeneratorAdapter.LE; +import static org.objectweb.asm.commons.GeneratorAdapter.LT; +import static org.objectweb.asm.commons.GeneratorAdapter.NE; +import java.util.Arrays; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; @@ -38,27 +45,756 @@ import org.objectweb.asm.Handle; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; /** - * GeneratorAdapter tests. TODO: add unit tests for all methods. + * GeneratorAdapter tests. * * @author Eric Bruneton */ public class GeneratorAdapterTest { + @Test + public void testConstructor1() { + GeneratorAdapter generatorAdapter = + new GeneratorAdapter(new MethodNode(), Opcodes.ACC_PUBLIC, "name", "()V"); + assertEquals(Opcodes.ACC_PUBLIC, generatorAdapter.getAccess()); + assertEquals("name", generatorAdapter.getName()); + assertEquals(Type.VOID_TYPE, generatorAdapter.getReturnType()); + assertArrayEquals(new Type[0], generatorAdapter.getArgumentTypes()); + } + + @Test + public void testConstructor2() { + assertThrows( + IllegalStateException.class, + () -> new GeneratorAdapter(new MethodNode(), Opcodes.ACC_PUBLIC, "name", "()V") {}); + } + + @Test + public void testConstructor3() { + GeneratorAdapter generatorAdapter = + new GeneratorAdapter(new MethodNode(), Opcodes.ACC_PRIVATE, "m", "(I)F"); + assertEquals(Opcodes.ACC_PRIVATE, generatorAdapter.getAccess()); + assertEquals("m", generatorAdapter.getName()); + assertEquals(Type.FLOAT_TYPE, generatorAdapter.getReturnType()); + assertArrayEquals(new Type[] {Type.INT_TYPE}, generatorAdapter.getArgumentTypes()); + } + + @Test + public void testConstructor4() { + new GeneratorAdapter(Opcodes.ACC_PUBLIC, new Method("name", "()V"), new MethodNode()); + ClassNode classNode = new ClassNode(); + GeneratorAdapter generatorAdapter = + new GeneratorAdapter( + Opcodes.ACC_PUBLIC, + new Method("name", "()V"), + "()V", + new Type[] {Type.getObjectType("java/lang/Exception")}, + classNode); + assertEquals(Opcodes.ACC_PUBLIC, generatorAdapter.getAccess()); + assertEquals("name", generatorAdapter.getName()); + assertEquals(Type.VOID_TYPE, generatorAdapter.getReturnType()); + assertArrayEquals(new Type[0], generatorAdapter.getArgumentTypes()); + + MethodNode methodNode = classNode.methods.get(0); + assertEquals(Opcodes.ACC_PUBLIC, methodNode.access); + assertEquals("name", methodNode.name); + assertEquals("()V", methodNode.desc); + assertEquals(Arrays.asList("java/lang/Exception"), methodNode.exceptions); + } + + @Test + public void testConstructor4WithoutExceptions() { + new GeneratorAdapter(Opcodes.ACC_PUBLIC, new Method("name", "()V"), new MethodNode()); + ClassNode classNode = new ClassNode(); + GeneratorAdapter generatorAdapter = + new GeneratorAdapter(Opcodes.ACC_PUBLIC, new Method("name", "()V"), "()V", null, classNode); + assertEquals(Opcodes.ACC_PUBLIC, generatorAdapter.getAccess()); + assertEquals("name", generatorAdapter.getName()); + assertEquals(Type.VOID_TYPE, generatorAdapter.getReturnType()); + assertArrayEquals(new Type[0], generatorAdapter.getArgumentTypes()); + + MethodNode methodNode = classNode.methods.get(0); + assertEquals(Opcodes.ACC_PUBLIC, methodNode.access); + assertEquals("name", methodNode.name); + assertEquals("()V", methodNode.desc); + assertEquals(Arrays.asList(), methodNode.exceptions); + } + + @Test + public void testPushBoolean() { + assertEquals("ICONST_0", new Generator().push(false)); + assertEquals("ICONST_1", new Generator().push(true)); + } + + @Test + public void testPushInt() { + assertEquals("LDC -32769", new Generator().push(-32769)); + assertEquals("SIPUSH -32768", new Generator().push(-32768)); + assertEquals("BIPUSH -128", new Generator().push(-128)); + assertEquals("ICONST_M1", new Generator().push(-1)); + assertEquals("ICONST_0", new Generator().push(0)); + assertEquals("ICONST_1", new Generator().push(1)); + assertEquals("ICONST_2", new Generator().push(2)); + assertEquals("ICONST_3", new Generator().push(3)); + assertEquals("ICONST_4", new Generator().push(4)); + assertEquals("ICONST_5", new Generator().push(5)); + assertEquals("BIPUSH 6", new Generator().push(6)); + assertEquals("BIPUSH 127", new Generator().push(127)); + assertEquals("SIPUSH 128", new Generator().push(128)); + assertEquals("SIPUSH 32767", new Generator().push(32767)); + assertEquals("LDC 32768", new Generator().push(32768)); + } + + @Test + public void testPushLong() { + assertEquals("LCONST_0", new Generator().push(0L)); + assertEquals("LCONST_1", new Generator().push(1L)); + assertEquals("LDC 2", new Generator().push(2L)); + } + + @Test + public void testPushFloat() { + assertEquals("FCONST_0", new Generator().push(0.0f)); + assertEquals("FCONST_1", new Generator().push(1.0f)); + assertEquals("FCONST_2", new Generator().push(2.0f)); + assertEquals("LDC 3.0", new Generator().push(3.0f)); + } + + @Test + public void testPushDouble() { + assertEquals("DCONST_0", new Generator().push(0.0)); + assertEquals("DCONST_1", new Generator().push(1.0)); + assertEquals("LDC 2.0", new Generator().push(2.0)); + } + + @Test + public void testPushString() { + assertEquals("ACONST_NULL", new Generator().push((String) null)); + assertEquals("LDC \"string\"", new Generator().push("string")); + } + + @Test + public void testPushType() { + assertEquals("ACONST_NULL", new Generator().push((Type) null)); + assertEquals( + "GETSTATIC java/lang/Boolean.TYPE : Ljava/lang/Class;", + new Generator().push(Type.BOOLEAN_TYPE)); + assertEquals( + "GETSTATIC java/lang/Character.TYPE : Ljava/lang/Class;", + new Generator().push(Type.CHAR_TYPE)); + assertEquals( + "GETSTATIC java/lang/Byte.TYPE : Ljava/lang/Class;", new Generator().push(Type.BYTE_TYPE)); + assertEquals( + "GETSTATIC java/lang/Short.TYPE : Ljava/lang/Class;", + new Generator().push(Type.SHORT_TYPE)); + assertEquals( + "GETSTATIC java/lang/Integer.TYPE : Ljava/lang/Class;", + new Generator().push(Type.INT_TYPE)); + assertEquals( + "GETSTATIC java/lang/Float.TYPE : Ljava/lang/Class;", + new Generator().push(Type.FLOAT_TYPE)); + assertEquals( + "GETSTATIC java/lang/Long.TYPE : Ljava/lang/Class;", new Generator().push(Type.LONG_TYPE)); + assertEquals( + "GETSTATIC java/lang/Double.TYPE : Ljava/lang/Class;", + new Generator().push(Type.DOUBLE_TYPE)); + assertEquals( + "LDC Ljava/lang/Object;.class", + new Generator().push(Type.getObjectType("java/lang/Object"))); + assertEquals("LDC [I.class", new Generator().push(Type.getObjectType("[I"))); + } + + @Test + public void testPushHandle() { + assertEquals("ACONST_NULL", new Generator().push((Handle) null)); + assertEquals( + "LDC pkg/Owner.nameI (2)", + new Generator().push(new Handle(Opcodes.H_GETSTATIC, "pkg/Owner", "name", "I", false))); + } + + @Test + public void testLoadThis() { + assertEquals("ALOAD 0", new Generator().loadThis()); + assertThrows( + IllegalStateException.class, + () -> new Generator(Opcodes.ACC_STATIC, "m", "()V").loadThis()); + } + + @Test + public void testLoadArg() { + assertEquals("ILOAD 1", new Generator(Opcodes.ACC_PUBLIC, "m", "(I)V").loadArg(0)); + assertEquals("LLOAD 0", new Generator(Opcodes.ACC_STATIC, "m", "(J)V").loadArg(0)); + assertEquals("FLOAD 2", new Generator(Opcodes.ACC_STATIC, "m", "(JF)V").loadArg(1)); + } + + @Test + public void testLoadArgs() { + assertEquals("LLOAD 2", new Generator(Opcodes.ACC_PUBLIC, "m", "(IJFD)V").loadArgs(1, 1)); + assertEquals( + "ILOAD 0 LLOAD 1 FLOAD 3 DLOAD 4", + new Generator(Opcodes.ACC_STATIC, "m", "(IJFD)V").loadArgs()); + } + + @Test + public void testLoadArgArray() { + assertEquals( + "BIPUSH 9 ANEWARRAY java/lang/Object " + + "DUP ICONST_0 ILOAD 1 NEW java/lang/Boolean DUP_X1 SWAP" + + " INVOKESPECIAL java/lang/Boolean. (Z)V AASTORE " + + "DUP ICONST_1 ILOAD 2 NEW java/lang/Byte DUP_X1 SWAP" + + " INVOKESPECIAL java/lang/Byte. (B)V AASTORE " + + "DUP ICONST_2 ILOAD 3 NEW java/lang/Character DUP_X1 SWAP" + + " INVOKESPECIAL java/lang/Character. (C)V AASTORE " + + "DUP ICONST_3 ILOAD 4 NEW java/lang/Short DUP_X1 SWAP" + + " INVOKESPECIAL java/lang/Short. (S)V AASTORE " + + "DUP ICONST_4 ILOAD 5 NEW java/lang/Integer DUP_X1 SWAP" + + " INVOKESPECIAL java/lang/Integer. (I)V AASTORE " + + "DUP ICONST_5 LLOAD 6 NEW java/lang/Long DUP_X2 DUP_X2 POP" + + " INVOKESPECIAL java/lang/Long. (J)V AASTORE " + + "DUP BIPUSH 6 FLOAD 8 NEW java/lang/Float DUP_X1 SWAP" + + " INVOKESPECIAL java/lang/Float. (F)V AASTORE " + + "DUP BIPUSH 7 DLOAD 9 NEW java/lang/Double DUP_X2 DUP_X2 POP" + + " INVOKESPECIAL java/lang/Double. (D)V AASTORE " + + "DUP BIPUSH 8 ALOAD 11 AASTORE", + new Generator(Opcodes.ACC_PUBLIC, "m", "(ZBCSIJFDLjava/lang/Object;)V").loadArgArray()); + } + + @Test + public void testStoreArg() { + assertEquals("ISTORE 1", new Generator(Opcodes.ACC_PUBLIC, "m", "(I)V").storeArg(0)); + assertEquals("LSTORE 0", new Generator(Opcodes.ACC_STATIC, "m", "(J)V").storeArg(0)); + assertEquals("FSTORE 2", new Generator(Opcodes.ACC_STATIC, "m", "(JF)V").storeArg(1)); + } + + @Test + public void testLoadLocal() { + Generator generator = new Generator(); + int local = generator.newLocal(Type.FLOAT_TYPE); + assertEquals(Type.FLOAT_TYPE, generator.getLocalType(local)); + assertEquals("FLOAD 1", generator.loadLocal(local)); + assertEquals("ILOAD 1", generator.loadLocal(local, Type.INT_TYPE)); + assertEquals(Type.INT_TYPE, generator.getLocalType(local)); + assertEquals("ILOAD 1", generator.loadLocal(local)); + } + + @Test + public void testStoreLocal() { + Generator generator = new Generator(); + int local = generator.newLocal(Type.FLOAT_TYPE); + assertEquals(Type.FLOAT_TYPE, generator.getLocalType(local)); + assertEquals("FSTORE 1", generator.storeLocal(local)); + assertEquals("ISTORE 1", generator.storeLocal(local, Type.INT_TYPE)); + assertEquals(Type.INT_TYPE, generator.getLocalType(local)); + assertEquals("ISTORE 1", generator.storeLocal(local)); + } + + @Test + public void testArrayLoad() { + assertEquals("IALOAD", new Generator().arrayLoad(Type.INT_TYPE)); + assertEquals("LALOAD", new Generator().arrayLoad(Type.LONG_TYPE)); + } + + @Test + public void testArrayStore() { + assertEquals("IASTORE", new Generator().arrayStore(Type.INT_TYPE)); + assertEquals("LASTORE", new Generator().arrayStore(Type.LONG_TYPE)); + } + + @Test + public void testPop() { + assertEquals("POP", new Generator().pop()); + } + + @Test + public void testPop2() { + assertEquals("POP2", new Generator().pop2()); + } + + @Test + public void testDup() { + assertEquals("DUP", new Generator().dup()); + } + + @Test + public void testDup2() { + assertEquals("DUP2", new Generator().dup2()); + } + + @Test + public void testDupX1() { + assertEquals("DUP_X1", new Generator().dupX1()); + } + + @Test + public void testDupX2() { + assertEquals("DUP_X2", new Generator().dupX2()); + } + + @Test + public void testDup2X1() { + assertEquals("DUP2_X1", new Generator().dup2X1()); + } + + @Test + public void testDup2X2() { + assertEquals("DUP2_X2", new Generator().dup2X2()); + } + + @Test + public void testSwap() { + assertEquals("SWAP", new Generator().swap()); + assertEquals("SWAP", new Generator().swap(Type.INT_TYPE, Type.INT_TYPE)); + assertEquals("DUP_X2 POP", new Generator().swap(Type.LONG_TYPE, Type.INT_TYPE)); + assertEquals("DUP2_X1 POP2", new Generator().swap(Type.INT_TYPE, Type.LONG_TYPE)); + assertEquals("DUP2_X2 POP2", new Generator().swap(Type.LONG_TYPE, Type.LONG_TYPE)); + } + + @Test + public void testMath() { + assertEquals("IADD", new Generator().math(GeneratorAdapter.ADD, Type.INT_TYPE)); + assertEquals("FSUB", new Generator().math(GeneratorAdapter.SUB, Type.FLOAT_TYPE)); + assertEquals("LMUL", new Generator().math(GeneratorAdapter.MUL, Type.LONG_TYPE)); + assertEquals("DDIV", new Generator().math(GeneratorAdapter.DIV, Type.DOUBLE_TYPE)); + assertEquals("IREM", new Generator().math(GeneratorAdapter.REM, Type.INT_TYPE)); + assertEquals("LNEG", new Generator().math(GeneratorAdapter.NEG, Type.LONG_TYPE)); + assertEquals("ISHL", new Generator().math(GeneratorAdapter.SHL, Type.INT_TYPE)); + assertEquals("LSHR", new Generator().math(GeneratorAdapter.SHR, Type.LONG_TYPE)); + assertEquals("IUSHR", new Generator().math(GeneratorAdapter.USHR, Type.INT_TYPE)); + assertEquals("LAND", new Generator().math(GeneratorAdapter.AND, Type.LONG_TYPE)); + assertEquals("IOR", new Generator().math(GeneratorAdapter.OR, Type.INT_TYPE)); + assertEquals("LXOR", new Generator().math(GeneratorAdapter.XOR, Type.LONG_TYPE)); + } + + @Test + public void testNot() { + assertEquals("ICONST_1 IXOR", new Generator().not()); + } + + @Test + public void testIinc() { + assertEquals("IINC 3 5", new Generator().iinc(3, 5)); + } + + @Test + public void testCast() { + assertEquals("", new Generator().cast(Type.DOUBLE_TYPE, Type.DOUBLE_TYPE)); + assertEquals("D2F", new Generator().cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE)); + assertEquals("D2L", new Generator().cast(Type.DOUBLE_TYPE, Type.LONG_TYPE)); + assertEquals("D2I", new Generator().cast(Type.DOUBLE_TYPE, Type.INT_TYPE)); + assertEquals("D2I I2B", new Generator().cast(Type.DOUBLE_TYPE, Type.BYTE_TYPE)); + + assertEquals("F2D", new Generator().cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE)); + assertEquals("", new Generator().cast(Type.FLOAT_TYPE, Type.FLOAT_TYPE)); + assertEquals("F2L", new Generator().cast(Type.FLOAT_TYPE, Type.LONG_TYPE)); + assertEquals("F2I", new Generator().cast(Type.FLOAT_TYPE, Type.INT_TYPE)); + assertEquals("F2I I2B", new Generator().cast(Type.FLOAT_TYPE, Type.BYTE_TYPE)); + + assertEquals("L2D", new Generator().cast(Type.LONG_TYPE, Type.DOUBLE_TYPE)); + assertEquals("L2F", new Generator().cast(Type.LONG_TYPE, Type.FLOAT_TYPE)); + assertEquals("", new Generator().cast(Type.LONG_TYPE, Type.LONG_TYPE)); + assertEquals("L2I", new Generator().cast(Type.LONG_TYPE, Type.INT_TYPE)); + assertEquals("L2I I2B", new Generator().cast(Type.LONG_TYPE, Type.BYTE_TYPE)); + + assertEquals("I2D", new Generator().cast(Type.INT_TYPE, Type.DOUBLE_TYPE)); + assertEquals("I2F", new Generator().cast(Type.INT_TYPE, Type.FLOAT_TYPE)); + assertEquals("I2L", new Generator().cast(Type.INT_TYPE, Type.LONG_TYPE)); + assertEquals("", new Generator().cast(Type.INT_TYPE, Type.INT_TYPE)); + assertEquals("I2B", new Generator().cast(Type.INT_TYPE, Type.BYTE_TYPE)); + assertEquals("I2C", new Generator().cast(Type.INT_TYPE, Type.CHAR_TYPE)); + assertEquals("I2S", new Generator().cast(Type.INT_TYPE, Type.SHORT_TYPE)); + + assertThrows( + IllegalArgumentException.class, () -> new Generator().cast(Type.INT_TYPE, Type.VOID_TYPE)); + } + + @Test + public void testBox() { + assertEquals("", new Generator().box(Type.getObjectType("java/lang/Object"))); + assertEquals("", new Generator().box(Type.getObjectType("[I"))); + assertEquals("ACONST_NULL", new Generator().box(Type.VOID_TYPE)); + + assertEquals( + "NEW java/lang/Boolean DUP_X1 SWAP INVOKESPECIAL java/lang/Boolean. (Z)V", + new Generator().box(Type.BOOLEAN_TYPE)); + assertEquals( + "NEW java/lang/Byte DUP_X1 SWAP INVOKESPECIAL java/lang/Byte. (B)V", + new Generator().box(Type.BYTE_TYPE)); + assertEquals( + "NEW java/lang/Character DUP_X1 SWAP INVOKESPECIAL java/lang/Character. (C)V", + new Generator().box(Type.CHAR_TYPE)); + assertEquals( + "NEW java/lang/Short DUP_X1 SWAP INVOKESPECIAL java/lang/Short. (S)V", + new Generator().box(Type.SHORT_TYPE)); + assertEquals( + "NEW java/lang/Integer DUP_X1 SWAP INVOKESPECIAL java/lang/Integer. (I)V", + new Generator().box(Type.INT_TYPE)); + assertEquals( + "NEW java/lang/Long DUP_X2 DUP_X2 POP INVOKESPECIAL java/lang/Long. (J)V", + new Generator().box(Type.LONG_TYPE)); + assertEquals( + "NEW java/lang/Float DUP_X1 SWAP INVOKESPECIAL java/lang/Float. (F)V", + new Generator().box(Type.FLOAT_TYPE)); + assertEquals( + "NEW java/lang/Double DUP_X2 DUP_X2 POP INVOKESPECIAL java/lang/Double. (D)V", + new Generator().box(Type.DOUBLE_TYPE)); + } + + @Test + public void testValueOf() { + assertEquals("", new Generator().valueOf(Type.getObjectType("java/lang/Object"))); + assertEquals("", new Generator().valueOf(Type.getType("[I"))); + assertEquals("ACONST_NULL", new Generator().valueOf(Type.VOID_TYPE)); + + assertEquals( + "INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;", + new Generator().valueOf(Type.BOOLEAN_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Byte.valueOf (B)Ljava/lang/Byte;", + new Generator().valueOf(Type.BYTE_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Character.valueOf (C)Ljava/lang/Character;", + new Generator().valueOf(Type.CHAR_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Short.valueOf (S)Ljava/lang/Short;", + new Generator().valueOf(Type.SHORT_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;", + new Generator().valueOf(Type.INT_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;", + new Generator().valueOf(Type.LONG_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Float.valueOf (F)Ljava/lang/Float;", + new Generator().valueOf(Type.FLOAT_TYPE)); + assertEquals( + "INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;", + new Generator().valueOf(Type.DOUBLE_TYPE)); + } + + @Test + public void testUnbox() { + assertEquals("", new Generator().unbox(Type.VOID_TYPE)); + assertEquals( + "CHECKCAST java/lang/Boolean INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z", + new Generator().unbox(Type.BOOLEAN_TYPE)); + assertEquals( + "CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.intValue ()I", + new Generator().unbox(Type.BYTE_TYPE)); + assertEquals( + "CHECKCAST java/lang/Character INVOKEVIRTUAL java/lang/Character.charValue ()C", + new Generator().unbox(Type.CHAR_TYPE)); + assertEquals( + "CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.intValue ()I", + new Generator().unbox(Type.SHORT_TYPE)); + assertEquals( + "CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.intValue ()I", + new Generator().unbox(Type.INT_TYPE)); + assertEquals( + "CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.longValue ()J", + new Generator().unbox(Type.LONG_TYPE)); + assertEquals( + "CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.floatValue ()F", + new Generator().unbox(Type.FLOAT_TYPE)); + assertEquals( + "CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.doubleValue ()D", + new Generator().unbox(Type.DOUBLE_TYPE)); + assertEquals("", new Generator().unbox(Type.getObjectType("java/lang/Object"))); + assertEquals( + "CHECKCAST java/lang/Number", + new Generator().unbox(Type.getObjectType("java/lang/Number"))); + assertEquals("CHECKCAST [I", new Generator().unbox(Type.getType("[I"))); + } + @Test public void testIfCmp() { - assertEquals("IF_ICMPGE L0", new Generator().ifCmp(Type.INT_TYPE, GE, new Label())); - assertEquals("LCMP IFGE L0", new Generator().ifCmp(Type.LONG_TYPE, GE, new Label())); - assertEquals("FCMPL IFGE L0", new Generator().ifCmp(Type.FLOAT_TYPE, GE, new Label())); - assertEquals("FCMPG IFLE L0", new Generator().ifCmp(Type.FLOAT_TYPE, LE, new Label())); - assertEquals("DCMPL IFGE L0", new Generator().ifCmp(Type.DOUBLE_TYPE, GE, new Label())); - assertEquals("DCMPG IFLE L0", new Generator().ifCmp(Type.DOUBLE_TYPE, LE, new Label())); + Generator generator = new Generator(); + Label label = generator.newLabel(); + assertEquals("IF_ICMPEQ L0", generator.ifCmp(Type.INT_TYPE, EQ, label)); + assertEquals("IF_ICMPNE L0", generator.ifCmp(Type.INT_TYPE, NE, label)); + assertEquals("IF_ICMPGE L0", generator.ifCmp(Type.INT_TYPE, GE, label)); + assertEquals("IF_ICMPGT L0", generator.ifCmp(Type.INT_TYPE, GT, label)); + assertEquals("IF_ICMPLE L0", generator.ifCmp(Type.INT_TYPE, LE, label)); + assertEquals("IF_ICMPLT L0", generator.ifCmp(Type.INT_TYPE, LT, label)); + assertEquals("LCMP IFGE L0", generator.ifCmp(Type.LONG_TYPE, GE, label)); + assertEquals("FCMPL IFGE L0", generator.ifCmp(Type.FLOAT_TYPE, GE, label)); + assertEquals("FCMPL IFGT L0", generator.ifCmp(Type.FLOAT_TYPE, GT, label)); + assertEquals("FCMPG IFLE L0", generator.ifCmp(Type.FLOAT_TYPE, LE, label)); + assertEquals("FCMPG IFLT L0", generator.ifCmp(Type.FLOAT_TYPE, LT, label)); + assertEquals("DCMPL IFGE L0", generator.ifCmp(Type.DOUBLE_TYPE, GE, label)); + assertEquals("DCMPL IFGT L0", generator.ifCmp(Type.DOUBLE_TYPE, GT, label)); + assertEquals("DCMPG IFLE L0", generator.ifCmp(Type.DOUBLE_TYPE, LE, label)); + assertEquals("DCMPG IFLT L0", generator.ifCmp(Type.DOUBLE_TYPE, LT, label)); + + assertEquals( + "IF_ACMPEQ L0", generator.ifCmp(Type.getObjectType("java/lang/Object"), EQ, label)); + assertEquals( + "IF_ACMPNE L0", generator.ifCmp(Type.getObjectType("java/lang/Object"), NE, label)); + assertThrows( + IllegalArgumentException.class, + () -> generator.ifCmp(Type.getObjectType("java/lang/Object"), GE, label)); + + assertEquals("IF_ACMPEQ L0", generator.ifCmp(Type.getType("[I"), EQ, label)); + assertEquals("IF_ACMPNE L0", generator.ifCmp(Type.getType("[I"), NE, label)); + assertThrows( + IllegalArgumentException.class, () -> generator.ifCmp(Type.getType("[I"), GE, label)); + + assertThrows(IllegalArgumentException.class, () -> generator.ifCmp(Type.INT_TYPE, 0, label)); + } + + @Test + public void testMark() { + assertEquals("L0", new Generator().mark(new Label())); + } + + @Test + public void testIfICmp() { + Generator generator = new Generator(); + Label label = generator.newLabel(); + assertEquals("IF_ICMPEQ L0", generator.ifICmp(EQ, label)); + assertEquals("IF_ICMPNE L0", generator.ifICmp(NE, label)); + assertEquals("IF_ICMPGE L0", generator.ifICmp(GE, label)); + assertEquals("IF_ICMPGT L0", generator.ifICmp(GT, label)); + assertEquals("IF_ICMPLE L0", generator.ifICmp(LE, label)); + assertEquals("IF_ICMPLT L0", generator.ifICmp(LT, label)); + assertThrows(IllegalArgumentException.class, () -> generator.ifICmp(0, label)); + } + + @Test + public void testIfZCmp() { + Generator generator = new Generator(); + Label label = generator.newLabel(); + assertEquals("IFEQ L0", generator.ifZCmp(EQ, label)); + assertEquals("IFNE L0", generator.ifZCmp(NE, label)); + assertEquals("IFGE L0", generator.ifZCmp(GE, label)); + assertEquals("IFGT L0", generator.ifZCmp(GT, label)); + assertEquals("IFLE L0", generator.ifZCmp(LE, label)); + assertEquals("IFLT L0", generator.ifZCmp(LT, label)); + } + + @Test + public void testIfNull() { + assertEquals("IFNULL L0", new Generator().ifNull(new Label())); + } + + @Test + public void testIfNonNull() { + assertEquals("IFNONNULL L0", new Generator().ifNonNull(new Label())); + } + + @Test + public void testGoto() { + assertEquals("GOTO L0", new Generator().goTo(new Label())); + } + + @Test + public void testTableSwitch() { + assertEquals("L0 ICONST_M1 L1", new Generator().tableSwitch(new int[0])); + assertEquals( + "TABLESWITCH\n" + + " 0: L0\n" + + " 1: L1\n" + + " default: L2 L0 ICONST_0 L1 ICONST_1 L2 ICONST_M1 L3", + new Generator().tableSwitch(new int[] {0, 1})); + assertEquals( + "LOOKUPSWITCH\n" + + " 0: L0\n" + + " 1: L1\n" + + " default: L2 L0 ICONST_0 L1 ICONST_1 L2 ICONST_M1 L3", + new Generator().tableSwitch(new int[] {0, 1}, false)); + assertEquals( + "LOOKUPSWITCH\n" + + " 0: L0\n" + + " 4: L1\n" + + " default: L2 L0 ICONST_0 L1 ICONST_4 L2 ICONST_M1 L3", + new Generator().tableSwitch(new int[] {0, 4})); + assertEquals( + "TABLESWITCH\n" + + " 0: L0\n" + + " 1: L1\n" + + " 2: L1\n" + + " 3: L1\n" + + " 4: L2\n" + + " default: L1 L0 ICONST_0 L2 ICONST_4 L1 ICONST_M1 L3", + new Generator().tableSwitch(new int[] {0, 4}, true)); + assertThrows( + IllegalArgumentException.class, () -> new Generator().tableSwitch(new int[] {1, 0})); + } + + @Test + public void testRet() { + assertEquals("RET 5", new Generator().ret(5)); + } + + @Test + public void testReturnValue() { + assertEquals("RETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()V").returnValue()); + assertEquals("IRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()Z").returnValue()); + assertEquals("IRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()B").returnValue()); + assertEquals("IRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()C").returnValue()); + assertEquals("IRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()S").returnValue()); + assertEquals("IRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()I").returnValue()); + assertEquals("LRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()J").returnValue()); + assertEquals("FRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()F").returnValue()); + assertEquals("DRETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()D").returnValue()); + assertEquals("ARETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()[I").returnValue()); + assertEquals("ARETURN", new Generator(Opcodes.ACC_PUBLIC, "m", "()Lpkg/Class").returnValue()); + } + + @Test + public void testGetStatic() { + assertEquals( + "GETSTATIC pkg/Class.f : I", + new Generator().getStatic(Type.getObjectType("pkg/Class"), "f", Type.INT_TYPE)); + } + + @Test + public void testPutStatic() { + assertEquals( + "PUTSTATIC pkg/Class.f : I", + new Generator().putStatic(Type.getObjectType("pkg/Class"), "f", Type.INT_TYPE)); + } + + @Test + public void testGetField() { + assertEquals( + "GETFIELD pkg/Class.f : I", + new Generator().getField(Type.getObjectType("pkg/Class"), "f", Type.INT_TYPE)); + } + + @Test + public void testPutField() { + assertEquals( + "PUTFIELD pkg/Class.f : I", + new Generator().putField(Type.getObjectType("pkg/Class"), "f", Type.INT_TYPE)); + } + + @Test + public void testInvokeVirtual() { + assertEquals( + "INVOKEVIRTUAL pkg/Class.m (I)J", + new Generator().invokeVirtual(Type.getObjectType("pkg/Class"), new Method("m", "(I)J"))); } - private static class Generator { + @Test + public void testInvokeConstructor() { + assertEquals( + "INVOKESPECIAL pkg/Class. (I)J", + new Generator() + .invokeConstructor(Type.getObjectType("pkg/Class"), new Method("", "(I)J"))); + } + + @Test + public void testInvokeStatic() { + assertEquals( + "INVOKESTATIC pkg/Class.m (I)J", + new Generator().invokeStatic(Type.getObjectType("pkg/Class"), new Method("m", "(I)J"))); + } + + @Test + public void testInvokeInterface() { + assertEquals( + "INVOKEINTERFACE pkg/Class.m (I)J (itf)", + new Generator().invokeInterface(Type.getObjectType("pkg/Class"), new Method("m", "(I)J"))); + } + + @Test + public void testInvokeDynamic() { + assertEquals( + "INVOKEDYNAMIC m(I)J [\n" + + " // handle kind 0x2 : GETSTATIC\n" + + " pkg/Owner.name(I)\n" + + " // arguments:\n" + + " 1, \n" + + " 2, \n" + + " 3\n" + + " ]", + new Generator() + .invokeDynamic( + "m", + "(I)J", + new Handle(Opcodes.H_GETSTATIC, "pkg/Owner", "name", "I", false), + 1, + 2, + 3)); + } + + @Test + public void testNewInstance() { + assertEquals("NEW pkg/Class", new Generator().newInstance(Type.getObjectType("pkg/Class"))); + } + + @Test + public void testNewArray() { + assertEquals("NEWARRAY T_BOOLEAN", new Generator().newArray(Type.BOOLEAN_TYPE)); + assertEquals("NEWARRAY T_BYTE", new Generator().newArray(Type.BYTE_TYPE)); + assertEquals("NEWARRAY T_CHAR", new Generator().newArray(Type.CHAR_TYPE)); + assertEquals("NEWARRAY T_SHORT", new Generator().newArray(Type.SHORT_TYPE)); + assertEquals("NEWARRAY T_INT", new Generator().newArray(Type.INT_TYPE)); + assertEquals("NEWARRAY T_FLOAT", new Generator().newArray(Type.FLOAT_TYPE)); + assertEquals("NEWARRAY T_LONG", new Generator().newArray(Type.LONG_TYPE)); + assertEquals("NEWARRAY T_DOUBLE", new Generator().newArray(Type.DOUBLE_TYPE)); + assertEquals("ANEWARRAY pkg/Class", new Generator().newArray(Type.getObjectType("pkg/Class"))); + assertEquals("ANEWARRAY [I", new Generator().newArray(Type.getType("[I"))); + } + + @Test + public void testArrayLength() { + assertEquals("ARRAYLENGTH", new Generator().arrayLength()); + } + + @Test + public void testThrowException() { + assertEquals("ATHROW", new Generator().throwException()); + assertEquals( + "NEW pkg/Exception DUP LDC \"msg\" " + + "INVOKESPECIAL pkg/Exception. (Ljava/lang/String;)V ATHROW", + new Generator().throwException(Type.getObjectType("pkg/Exception"), "msg")); + } + + @Test + public void testCheckcast() { + assertEquals("", new Generator().checkCast(Type.getObjectType("java/lang/Object"))); + assertEquals("CHECKCAST pkg/Class", new Generator().checkCast(Type.getObjectType("pkg/Class"))); + } + + @Test + public void testInstanceOf() { + assertEquals("INSTANCEOF pkg/Class", new Generator().instanceOf(Type.getType("Lpkg/Class;"))); + } + + @Test + public void testMonitorEnter() { + assertEquals("MONITORENTER", new Generator().monitorEnter()); + } + + @Test + public void testMonitorExit() { + assertEquals("MONITOREXIT", new Generator().monitorExit()); + } + + @Test + public void testEndMethod() { + assertEquals("MAXSTACK = 0 MAXLOCALS = 0", new Generator().endMethod()); + assertEquals("", new Generator(Opcodes.ACC_ABSTRACT, "m", "()V").endMethod()); + } + + @Test + public void testCatchException() { + assertEquals( + "TRYCATCHBLOCK L0 L1 L2 null L2", + new Generator().catchException(new Label(), new Label(), null)); + assertEquals( + "TRYCATCHBLOCK L0 L1 L2 pkg/Exception L2", + new Generator() + .catchException(new Label(), new Label(), Type.getObjectType("pkg/Exception"))); + } + + private static class Generator implements TableSwitchGenerator { private final Textifier textifier; private final GeneratorAdapter generatorAdapter; @@ -144,6 +880,10 @@ public class GeneratorAdapterTest { return toString(); } + public int newLocal(final Type type) { + return generatorAdapter.newLocal(type); + } + public Type getLocalType(final int local) { return generatorAdapter.getLocalType(local); } @@ -272,10 +1012,6 @@ public class GeneratorAdapterTest { return toString(); } - public Label mark() { - return generatorAdapter.mark(); - } - public String ifCmp(final Type type, final int mode, final Label label) { generatorAdapter.ifCmp(type, mode, label); return toString(); @@ -311,17 +1047,26 @@ public class GeneratorAdapterTest { return toString(); } - public String tableSwitch(final int[] keys, final TableSwitchGenerator generator) { - generatorAdapter.tableSwitch(keys, generator); + public String tableSwitch(final int[] keys) { + generatorAdapter.tableSwitch(keys, this); return toString(); } - public String tableSwitch( - final int[] keys, final TableSwitchGenerator generator, final boolean useTable) { - generatorAdapter.tableSwitch(keys, generator, useTable); + public String tableSwitch(final int[] keys, final boolean useTable) { + generatorAdapter.tableSwitch(keys, this, useTable); return toString(); } + @Override + public void generateCase(int key, Label end) { + generatorAdapter.push(key); + } + + @Override + public void generateDefault() { + generatorAdapter.push(-1); + } + public String returnValue() { generatorAdapter.returnValue(); return toString(); @@ -430,11 +1175,14 @@ public class GeneratorAdapterTest { @Override public String toString() { - return textifier - .text - .stream() - .map(text -> text.toString().trim()) - .collect(Collectors.joining(" ")); + String result = + textifier + .text + .stream() + .map(text -> text.toString().trim()) + .collect(Collectors.joining(" ")); + textifier.text.clear(); + return result; } } } diff --git a/build.gradle b/build.gradle index 5bc3d288..df7eedee 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,7 @@ project(':asm-commons') { provides = ['org.objectweb.asm.commons'] requires = [':asm', ':asm-tree', ':asm-analysis'] dependencies { testCompile project(':asm-util') } - minCodeCoverage = 0.5 // TODO: improve the code coverage of this project. + minCodeCoverage = 0.85 // TODO: improve the code coverage of this project. } project(':asm-test') { @@ -190,22 +190,21 @@ configure(subprojects.findAll { it.provides }) { apply plugin: 'jacoco' jacoco { applyTo junitPlatformTest } afterEvaluate { + def classes = files(project.sourceSets.main.output.collect { fileTree( + dir: it, include: 'org/objectweb/asm/**', exclude: '**/Remapping*' + )}) task jacocoTestReport(type: JacocoReport, overwrite: true) { executionData junitPlatformTest sourceSets sourceSets.main sourceDirectories = files(project.sourceSets.main.allSource.srcDirs) - classDirectories = files(project.sourceSets.main.output.collect { - fileTree(dir: it, include: 'org/objectweb/asm/**') - }) + classDirectories = classes } task jacocoTestCoverageVerification( type: JacocoCoverageVerification, overwrite: true) { executionData junitPlatformTest sourceSets sourceSets.main sourceDirectories = files(project.sourceSets.main.allSource.srcDirs) - classDirectories = files(project.sourceSets.main.output.collect { - fileTree(dir: it, include: 'org/objectweb/asm/**') - }) + classDirectories = classes violationRules.rule { limit { counter = 'INSTRUCTION' -- GitLab