All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.external.asm.JavaType Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
/*
 * ASM: a very small and fast Java bytecode manipulation framework
 * Copyright (c) 2000-2011 INRIA, France Telecom
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
package mockit.external.asm;

import java.lang.reflect.*;
import javax.annotation.*;

/**
 * A Java field or method type. This class can be used to make it easier to manipulate type and method descriptors.
 */
public abstract class JavaType
{
   /**
    * See {@link #getSort()}.
    */
   public interface Sort
   {
      /**
       * The sort of the void type.
       */
      int VOID = 0;

      /**
       * The sort of the boolean type.
       */
      int BOOLEAN = 1;

      /**
       * The sort of the char type.
       */
      int CHAR = 2;

      /**
       * The sort of the byte type.
       */
      int BYTE = 3;

      /**
       * The sort of the short type.
       */
      int SHORT = 4;

      /**
       * The sort of the int type.
       */
      int INT = 5;

      /**
       * The sort of the float type.
       */
      int FLOAT = 6;

      /**
       * The sort of the long type.
       */
      int LONG = 7;

      /**
       * The sort of the double type.
       */
      int DOUBLE = 8;

      /**
       * The sort of array reference types.
       */
      int ARRAY = 9;

      /**
       * The sort of object reference types.
       */
      int OBJECT = 10;

      /**
       * The sort of method types.
       */
      int METHOD = 11;
   }

   /**
    * The sort of this Java type.
    */
   final int sort;

   /**
    * The length of the internal name of this Java type.
    */
   @Nonnegative final int len;

   /**
    * Maps a {@link Sort} to the corresponding {@link ArrayElementType}.
    */
   public static int getArrayElementType(int elementSort) {
      switch (elementSort) {
         case Sort.BOOLEAN: return ArrayElementType.BOOLEAN;
         case Sort.CHAR:    return ArrayElementType.CHAR;
         case Sort.BYTE:    return ArrayElementType.BYTE;
         case Sort.SHORT:   return ArrayElementType.SHORT;
         case Sort.INT:     return ArrayElementType.INT;
         case Sort.FLOAT:   return ArrayElementType.FLOAT;
         case Sort.LONG:    return ArrayElementType.LONG;
         default:           return ArrayElementType.DOUBLE;
      }
   }

   // ------------------------------------------------------------------------
   // Constructors and static factory methods
   // ------------------------------------------------------------------------

   /**
    * Constructs a Java type.
    *
    * @param sort the sort of the reference type to be constructed.
    * @param len  the length of this descriptor.
    */
   JavaType(int sort, @Nonnegative int len) {
      this.sort = sort;
      this.len = len;
   }

   /**
    * Returns the Java type corresponding to the given type descriptor.
    *
    * @param typeDescriptor a field or method type descriptor.
    */
   @Nonnull
   public static JavaType getType(@Nonnull String typeDescriptor) {
      return getType(typeDescriptor.toCharArray(), 0);
   }

   /**
    * Returns the Java type corresponding to the given internal name.
    */
   @Nonnull
   public static JavaType getObjectType(@Nonnull String internalName) {
      char[] buf = internalName.toCharArray();
      return buf[0] == '[' ? new ArrayType(buf, 0, buf.length) : new ObjectType(buf, 0, buf.length);
   }

   /**
    * Returns the Java type corresponding to the given method descriptor.
    */
   @Nonnull
   public static JavaType getMethodType(@Nonnull String methodDescriptor) {
      return MethodType.create(methodDescriptor);
   }

   /**
    * Returns the Java type corresponding to the given class.
    */
   @Nonnull
   public static JavaType getType(@Nonnull Class aClass) {
      if (aClass.isPrimitive()) {
         return PrimitiveType.getPrimitiveType(aClass);
      }

      String typeDesc = getDescriptor(aClass);
      return getType(typeDesc);
   }

   /**
    * Returns the Java method type corresponding to the given constructor.
    */
   @Nonnull
   public static JavaType getType(@Nonnull Constructor constructor) {
      String constructorDesc = getConstructorDescriptor(constructor);
      return getType(constructorDesc);
   }

   /**
    * Returns the Java method type corresponding to the given method.
    */
   @Nonnull
   public static JavaType getType(@Nonnull Method method) {
      String methodDesc = getMethodDescriptor(method);
      return getType(methodDesc);
   }

   /**
    * Returns the Java types corresponding to the argument types of the given method descriptor.
    */
   @Nonnull
   public static JavaType[] getArgumentTypes(@Nonnull String methodDescriptor) {
      char[] buf = methodDescriptor.toCharArray();
      int off = 1;
      int size = 0;

      while (true) {
         char c = buf[off++];

         if (c == ')') {
            break;
         }
         else if (c == 'L') {
            while (buf[off++] != ';') {}
            size++;
         }
         else if (c != '[') {
            size++;
         }
      }

      JavaType[] argTypes = new JavaType[size];
      off = 1;
      size = 0;

      while (buf[off] != ')') {
         JavaType argType = getType(buf, off);
         argTypes[size] = argType;
         off += argType.len + (argType.sort == Sort.OBJECT ? 2 : 0);
         size++;
      }

      return argTypes;
   }

   /**
    * Returns the Java type corresponding to the return type of the given method descriptor.
    */
   @Nonnull
   public static JavaType getReturnType(@Nonnull String methodDescriptor) {
      char[] buf = methodDescriptor.toCharArray();
      return getType(buf, methodDescriptor.indexOf(')') + 1);
   }

   /**
    * Computes the size of the arguments and of the return value of a method.
    *
    * @param desc the descriptor of a method.
    * @return the size of the arguments of the method (plus one for the implicit this argument),
    * argSize, and the size of its return value, retSize, packed into a single
    * int i = (argSize << 2) | retSize (argSize is therefore equal to i >> 2, and
    * retSize to i & 0x03).
    */
   public static int getArgumentsAndReturnSizes(@Nonnull String desc) {
      int argSize = 1;
      int i = 1;

      while (true) {
         char c = desc.charAt(i++);

         if (c == ')') {
            c = desc.charAt(i);
            return argSize << 2 | (c == 'V' ? 0 : c == 'D' || c == 'J' ? 2 : 1);
         }
         else if (c == 'L') {
            while (desc.charAt(i++) != ';') {}
            argSize++;
         }
         else if (c == '[') {
            while ((c = desc.charAt(i)) == '[') {
               i++;
            }

            if (c == 'D' || c == 'J') {
               argSize--;
            }
         }
         else if (c == 'D' || c == 'J') {
            argSize += 2;
         }
         else {
            argSize++;
         }
      }
   }

   /**
    * Returns the Java type corresponding to the given type descriptor. For method descriptors, buf is supposed
    * to contain nothing more than the descriptor itself.
    *
    * @param buf a buffer containing a type descriptor.
    * @param off the offset of this descriptor in the previous buffer.
    */
   @Nonnull
   static JavaType getType(@Nonnull char[] buf, @Nonnegative int off) {
      char typeCode = buf[off];
      JavaType type = PrimitiveType.getPrimitiveType(typeCode);

      if (type != null) {
         return type;
      }

      switch (typeCode) {
         case '[': return ArrayType.create(buf, off);
         case 'L': return ObjectType.create(buf, off);
         // case '(':
         default: return new MethodType(buf, off, buf.length - off);
      }
   }

   // ------------------------------------------------------------------------
   // Accessors
   // ------------------------------------------------------------------------

   /**
    * Returns the {@link Sort} of this Java type.
    */
   public int getSort() { return sort; }

   /**
    * Returns the binary name of the class corresponding to this type. This method must not be used on method types.
    */
   @Nonnull
   public abstract String getClassName();

   /**
    * Returns the internal name of the class corresponding to this object or array type. The internal name of a class is
    * its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'.
    * This method should only be used for an object or array type.
    *
    * @return the internal name of the class corresponding to this object type.
    */
   @Nonnull
   public String getInternalName() { throw new UnsupportedOperationException("Not a ReferenceType"); }

   // ------------------------------------------------------------------------
   // Conversion to type descriptors
   // ------------------------------------------------------------------------

   /**
    * Returns the descriptor corresponding to this Java type.
    */
   @Nonnull
   public final String getDescriptor() {
      StringBuffer buf = new StringBuffer();
      getDescriptor(buf);
      return buf.toString();
   }

   /**
    * Appends the descriptor corresponding to this Java type to the given string buffer.
    *
    * @param buf the string buffer to which the descriptor must be appended.
    */
   abstract void getDescriptor(@Nonnull StringBuffer buf);

   // -------------------------------------------------------------------------------------------------------
   // Direct conversion from classes to type descriptors, and vice-versa, without intermediate JavaType objects
   // -------------------------------------------------------------------------------------------------------

   /**
    * Returns the internal name of the given class. The internal name of a class is its fully qualified name, as
    * returned by Class.getName(), where '.' are replaced by '/'.
    *
    * @param aClass an object or array class.
    */
   @Nonnull
   public static String getInternalName(@Nonnull Class aClass) {
      return aClass.getName().replace('.', '/');
   }

   /**
    * Returns the descriptor corresponding to the given Java type.
    *
    * @param aClass an object class, a primitive class or an array class.
    */
   @Nonnull
   public static String getDescriptor(@Nonnull Class aClass) {
      StringBuffer buf = new StringBuffer();
      getDescriptor(buf, aClass);
      return buf.toString();
   }

   /**
    * Returns the descriptor corresponding to the given constructor.
    *
    * @param constructor a {@link Constructor} object.
    */
   @Nonnull
   public static String getConstructorDescriptor(@Nonnull Constructor constructor) {
      Class[] parameters = constructor.getParameterTypes();
      StringBuffer buf = new StringBuffer();
      buf.append('(');

      for (Class parameter : parameters) {
         getDescriptor(buf, parameter);
      }

      return buf.append(")V").toString();
   }

   /**
    * Returns the descriptor corresponding to the given method.
    */
   @Nonnull
   public static String getMethodDescriptor(@Nonnull Method method) {
      Class[] parameters = method.getParameterTypes();
      StringBuffer buf = new StringBuffer();
      buf.append('(');

      for (Class parameter : parameters) {
         getDescriptor(buf, parameter);
      }

      buf.append(')');
      getDescriptor(buf, method.getReturnType());
      return buf.toString();
   }

   /**
    * Appends the descriptor of the given class to the given string buffer.
    *
    * @param buf the string buffer to which the descriptor must be appended.
    * @param aClass   the class whose descriptor must be computed.
    */
   private static void getDescriptor(@Nonnull StringBuffer buf, @Nonnull Class aClass) {
      Class d = aClass;

      while (true) {
         if (d.isPrimitive()) {
            char typeCode = PrimitiveType.getTypeCode(d);
            buf.append(typeCode);
            return;
         }
         else if (d.isArray()) {
            buf.append('[');
            d = d.getComponentType();
         }
         else {
            ReferenceType.getDescriptor(buf, d);
            return;
         }
      }
   }

   // ------------------------------------------------------------------------
   // Corresponding size and opcodes
   // ------------------------------------------------------------------------

   /**
    * Returns the size of values of this type. This method must not be used for method types.
    *
    * @return the size of values of this type, i.e., 2 for long and double, 0 for void and 1
    * otherwise.
    */
   public abstract int getSize();

   /**
    * Returns a JVM instruction opcode adapted to this Java type. This method must not be used for method types.
    *
    * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, IASTORE, IADD, ISUB,
    *               IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
    * @return an opcode that is similar to the given opcode, but adapted to this Java type. For example, if this type is
    * float and opcode is IRETURN, this method returns FRETURN.
    */
   public abstract int getOpcode(int opcode);

   // ------------------------------------------------------------------------
   // Equals, hashCode and toString
   // ------------------------------------------------------------------------

   /**
    * Returns a string representation of this type.
    *
    * @return the descriptor of this type.
    */
   @Override
   public final String toString() {
      return getDescriptor();
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy