View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.bcel.generic;
18  
19  import static org.junit.jupiter.api.Assertions.fail;
20  import static org.junit.jupiter.api.Assumptions.assumeFalse;
21  
22  import org.apache.bcel.classfile.Code;
23  import org.apache.bcel.classfile.JavaClass;
24  import org.apache.bcel.classfile.Method;
25  import org.apache.bcel.util.SyntheticRepository;
26  import org.apache.commons.lang3.JavaVersion;
27  import org.apache.commons.lang3.SystemUtils;
28  import org.junit.jupiter.params.ParameterizedTest;
29  import org.junit.jupiter.params.provider.ValueSource;
30  
31  final class EmptyVisitorTestCase {
32  
33      /*
34       * https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.2
35       */
36      private static final String RESERVED_OPCODE = "Reserved opcode";
37  
38      @ParameterizedTest
39      @ValueSource(strings = {
40      // @formatter:off
41          "java.math.BigInteger",                          // contains instructions [AALOAD, AASTORE, ACONST_NULL, ALOAD, ANEWARRAY, ARETURN, ARRAYLENGTH,
42                                                           //   ASTORE, ATHROW, BALOAD, BASTORE, BIPUSH, CALOAD, CHECKCAST, D2I, DADD, DALOAD, DASTORE, DCONST
43                                                           //   DDIV, DMUL, DRETURN, DSUB, DUP, DUP2, DUP_X2, FCONST, FRETURN, GETFIELD, GETSTATIC, GOTO, I2B,
44                                                           //   I2D, I2L, IADD, IALOAD, IAND, IASTORE, ICONST, IDIV, IFEQ, IFGE, IFGT, IFLE, IFLT, IFNE,
45                                                           //   IFNONNULL, IFNULL, IF_ACMPNE, IF_ICMPEQ, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ICMPLT, IF_ICMPNE,
46                                                           //   IINC, ILOAD, IMUL, INEG, INSTANCEOF, INVOKESPECIAL, INVOKESTATIC, INVOKEVIRTUAL, IOR, IREM,
47                                                           //   IRETURN, ISHL, ISHR, ISTORE, ISUB, IUSHR, IXOR, L2D, L2F, L2I, LADD, LALOAD, LAND, LASTORE, LCMP,
48                                                           //   LCONST, LDC, LDC2_W, LDC_W, LDIV, LLOAD, LMUL, LNEG, LOOKUPSWITCH, LOR, LREM, LRETURN, LSHL, LSHR,
49                                                           //   LSTORE, LSUB, LUSHR, NEW, NEWARRAY, POP, PUTFIELD, PUTSTATIC, RETURN, SIPUSH]
50          "java.math.BigDecimal",                          // contains instructions [CASTORE, D2L, DLOAD, FALOAD, FASTORE, FDIV, FMUL, I2S, IF_ACMPEQ, LXOR,
51                                                           //   MONITORENTER, MONITOREXIT, TABLESWITCH]
52          "java.awt.Color",                                // contains instructions [D2F, DCMPG, DCMPL, F2D, F2I, FADD, FCMPG, FCMPL, FLOAD, FSTORE, FSUB, I2F,
53                                                           //   INVOKEDYNAMIC]
54          "java.util.Map",                                 // contains instruction INVOKEINTERFACE
55          "java.io.Bits",                                  // contains instruction I2C
56          "java.io.BufferedInputStream",                   // contains instruction DUP_X1
57          "java.io.StreamTokenizer",                       // contains instruction DNEG, DSTORE
58          "java.lang.Float",                               // contains instruction F2L
59          "java.lang.invoke.LambdaForm",                   // contains instruction MULTIANEWARRAY,
60          "java.nio.Bits",                                 // contains instruction POP2,
61          "java.nio.HeapShortBuffer",                      // contains instruction SALOAD, SASTORE
62          "Java8Example2",                                 // contains instruction FREM
63          "java.awt.GradientPaintContext",                 // contains instruction DREM
64          "java.util.concurrent.atomic.DoubleAccumulator", // contains instruction DUP2_X1
65          "java.util.Hashtable",                           // contains instruction FNEG
66          "javax.swing.text.html.CSS",                     // contains instruction DUP2_X2
67          "org.apache.bcel.generic.LargeJump",             // contains instruction GOTO_W
68          "org.apache.commons.lang.SerializationUtils"     // contains instruction JSR
69      // @formatter:on
70      })
71      public void test(final String className) throws ClassNotFoundException {
72          // "java.io.Bits" is not in Java 21.
73          assumeFalse(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21) && className.equals("java.io.Bits"));
74          final JavaClass javaClass = SyntheticRepository.getInstance().loadClass(className);
75          for (final Method method : javaClass.getMethods()) {
76              final Code code = method.getCode();
77              if (code != null) {
78                  final InstructionList instructionList = new InstructionList(code.getCode());
79                  for (final InstructionHandle instructionHandle : instructionList) {
80                      instructionHandle.accept(new EmptyVisitor() {
81                          @Override
82                          public void visitBREAKPOINT(final BREAKPOINT obj) {
83                              fail(RESERVED_OPCODE);
84                          }
85  
86                          @Override
87                          public void visitIMPDEP1(final IMPDEP1 obj) {
88                              fail(RESERVED_OPCODE);
89                          }
90  
91                          @Override
92                          public void visitIMPDEP2(final IMPDEP2 obj) {
93                              fail(RESERVED_OPCODE);
94                          }
95                      });
96                  }
97              }
98          }
99      }
100 }