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

com.ibm.wala.shrike.shrikeCT.AnnotationsReader Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2002,2006 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 */
package com.ibm.wala.shrike.shrikeCT;

import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
import java.util.Arrays;
import java.util.Map;

/**
 * This class reads Annotations attributes, e.g., RuntimeInvisibleAnnotations.
 *
 * @author sjfink
 */
public class AnnotationsReader extends AttributeReader {

  /** offset in class file where this attribute begins */
  protected final int beginOffset;

  public AnnotationsReader(ClassReader.AttrIterator iter, String label)
      throws InvalidClassFileException {
    super(iter, label);
    beginOffset = attr;
  }

  /**
   * @return number of annotations in this attribute
   */
  public int getAnnotationCount() throws InvalidClassFileException {
    int offset = beginOffset + 6;
    checkSize(offset, 2);
    return cr.getUShort(offset);
  }

  /**
   * @return total length of this attribute in bytes, including the first 6 bytes
   */
  public int getAttributeSize() throws InvalidClassFileException {
    int offset = beginOffset + 2;
    checkSize(offset, 4);
    return cr.getInt(offset) + 6;
  }

  /**
   * get the Utf8 constant pool value, where the constant pool offset is given in the class
   *
   * @param offset offset in the class file at which the constant pool offset is given
   */
  protected String getUtf8ConstantPoolValue(int offset) throws InvalidClassFileException {
    checkSize(offset, 2);
    int cpOffset = cr.getUShort(offset);
    return cr.getCP().getCPUtf8(cpOffset);
  }

  /**
   * Marker interface for possible element values in an annotation attribute.
   *
   * @see AnnotationsReader#readElementValueAndSize(int)
   */
  public interface ElementValue {}

  /**
   * Represents a constant argument to an annotation. Class arguments (e.g., {@code Foo.class}) are
   * also represented with this type, with the value being the String class name.
   */
  public static class ConstantElementValue implements ElementValue {

    /** the constant value */
    public final Object val;

    public ConstantElementValue(Object val) {
      this.val = val;
    }

    @Override
    public String toString() {
      return String.valueOf(val);
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((val == null) ? 0 : val.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      ConstantElementValue other = (ConstantElementValue) obj;
      if (val == null) {
        if (other.val != null) return false;
      } else if (!val.equals(other.val)) return false;
      return true;
    }
  }

  /** Represents enum constant annotation arguments. */
  public static class EnumElementValue implements ElementValue {

    /** the name of the enum type */
    public final String enumType;

    /** the enum value */
    public final String enumVal;

    public EnumElementValue(String enumType, String enumVal) {
      super();
      this.enumType = enumType;
      this.enumVal = enumVal;
    }

    @Override
    public String toString() {
      return "EnumElementValue [type=" + enumType + ", val=" + enumVal + ']';
    }
  }

  /** represents an annotation argument that itself is an array of arguments */
  public static class ArrayElementValue implements ElementValue {

    /** the values contained in the array */
    public final ElementValue[] vals;

    public ArrayElementValue(ElementValue[] vals) {
      super();
      this.vals = vals;
    }

    @Override
    public String toString() {
      return "ArrayElementValue [vals=" + Arrays.toString(vals) + ']';
    }
  }

  /**
   * get all the annotations declared in this attribute.
   *
   * 
   * RuntimeVisibleAnnotations_attribute {
   *   u2         attribute_name_index;
   *   u4         attribute_length;
   *   u2         num_annotations;
   *   annotation annotations[num_annotations];
   * }
   * 
* * @see JLS * (SE8), 4.7.16 */ public AnnotationAttribute[] getAllAnnotations() throws InvalidClassFileException { AnnotationAttribute[] result = new AnnotationAttribute[getAnnotationCount()]; int offset = beginOffset + 8; // skip attribute_name_index, // attribute_length, and num_annotations for (int i = 0; i < result.length; i++) { Pair attributeAndSize = getAttributeAndSize(offset); result[i] = attributeAndSize.fst; offset += attributeAndSize.snd; } return result; } /** * * *
   * param_annotations {
   *   u2 attribute_name_index;
   *   u4 attribute_length;
   *   u1 num_parameters;
   *   {
   *     u2 num_annotations;
   *     annotation annotations[num_annotations];
   *   } parameter_annotations[num_parameters];
   * 
*/ public AnnotationAttribute[][] getAllParameterAnnotations() throws InvalidClassFileException { int numParamOffset = beginOffset + 6; checkSize(numParamOffset, 1); int paramCount = cr.getByte(numParamOffset); AnnotationAttribute[][] result = new AnnotationAttribute[paramCount][]; // skip attribute_name_index, attribute_length, and num_parameters int offset = beginOffset + 7; for (int i = 0; i < result.length; i++) { checkSize(offset, 2); result[i] = new AnnotationAttribute[cr.getUShort(offset)]; offset += 2; for (int j = 0; j < result[i].length; j++) { Pair attributeAndSize = getAttributeAndSize(offset); result[i][j] = attributeAndSize.fst; offset += attributeAndSize.snd; } } return result; } /** * * *
   * annotation {
   *   u2 type_index;
   *   u2 num_element_value_pairs;
   *   { u2 element_name_index;
   *     element_value value;
   *   } element_value_pairs[num_element_value_pairs]
   * 
*/ protected Pair getAttributeAndSize(int begin) throws InvalidClassFileException { String type = getUtf8ConstantPoolValue(begin); int numElementValuePairs = cr.getUShort(begin + 2); int size = 4; int offset = begin + 4; Map elementName2Val = HashMapFactory.make(); for (int i = 0; i < numElementValuePairs; i++) { String elementName = getUtf8ConstantPoolValue(offset); offset += 2; Pair elementValAndSize = readElementValueAndSize(offset); offset += elementValAndSize.snd; size += elementValAndSize.snd + 2; elementName2Val.put(elementName, elementValAndSize.fst); } return Pair.make(new AnnotationAttribute(type, elementName2Val), size); } /** * Representation of an annotation attribute. An annotation has the following format in the * bytecode: * *
   * annotation {
   *   u2 type_index;
   *   u2 num_element_value_pairs;
   *   {  u2 element_name_index;
   *      element_value value;
   * } element_value_pairs[num_element_value_pairs];
   * 
* * See the JVM specification section 4.7.16 for details. * *

This class implements {@link ElementValue} to handle nested annotations. */ public static class AnnotationAttribute implements ElementValue { /** the type of the annotation */ public final String type; /** the arguments to the annotation */ public final Map elementValues; public AnnotationAttribute(String type, Map elementValues) { super(); this.type = type; this.elementValues = elementValues; } @Override public String toString() { return "AnnotationElementValue [type=" + type + ", elementValues=" + elementValues + ']'; } } /** * * *

   * element_value {
   *   u1 tag;
   *   union {
   *     u2 const_value_index;
   *     {  u2 type_name_index;
   *        u2 const_name_index;
   *     } enum_const_value;
   *     u2 class_info_index;
   *     annotation annotation_value;
   *     {  u2 num_values;
   *        element_value values[num_values];
   *     } array_value;
   *   } value;
   * 
* * A constant value (including class info) is represented by a {@link ConstantElementValue}. An * enum constant value is represented by an {@link EnumElementValue}. An array value is * represented by an {@link ArrayElementValue}. Finally, a nested annotation is represented by an * {@link AnnotationAttribute}. */ protected Pair readElementValueAndSize(int offset) throws IllegalArgumentException, InvalidClassFileException { char tag = (char) cr.getByte(offset); // meaning of this short depends on the tag int nextShort = cr.getUShort(offset + 1); switch (tag) { case 'B': case 'C': case 'I': case 'S': case 'Z': return Pair.make( new ConstantElementValue(cr.getCP().getCPInt(nextShort)), 3); case 'J': return Pair.make( new ConstantElementValue(cr.getCP().getCPLong(nextShort)), 3); case 'D': return Pair.make( new ConstantElementValue(cr.getCP().getCPDouble(nextShort)), 3); case 'F': return Pair.make( new ConstantElementValue(cr.getCP().getCPFloat(nextShort)), 3); case 's': // string case 'c': // class; just represent as a constant element with the type name return Pair.make( new ConstantElementValue(cr.getCP().getCPUtf8(nextShort)), 3); case 'e': // enum return Pair.make( new EnumElementValue( cr.getCP().getCPUtf8(nextShort), cr.getCP().getCPUtf8(cr.getUShort(offset + 3))), 5); case '[': // array int numValues = nextShort; int numArrayBytes = 3; // start with 3 for the tag and num_values bytes ElementValue[] vals = new ElementValue[numValues]; // start curOffset at beginning of array values int curArrayOffset = offset + 3; for (int i = 0; i < numValues; i++) { Pair arrayElemValueAndSize = readElementValueAndSize(curArrayOffset); vals[i] = arrayElemValueAndSize.fst; curArrayOffset += arrayElemValueAndSize.snd; numArrayBytes += arrayElemValueAndSize.snd; } return Pair.make(new ArrayElementValue(vals), numArrayBytes); case '@': // annotation Pair attributeAndSize = getAttributeAndSize(offset + 1); // add 1 to size for the tag return Pair.make(attributeAndSize.fst, attributeAndSize.snd + 1); default: assert false; return null; } } // ////////////// // utility methods for reading well-known annotation types // ////////////// public enum AnnotationType { RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations } public static boolean isKnownAnnotation(String name) { for (AnnotationType t : AnnotationType.values()) { if (t.name().equals(name)) { return true; } } return false; } public static AnnotationsReader getReaderForAnnotation( AnnotationType type, ClassReader.AttrIterator iter) { // search for the desired attribute final String attrName = type.toString(); try { for (; iter.isValid(); iter.advance()) { if (iter.getName().equals(attrName)) { return new AnnotationsReader(iter, attrName); } } } catch (InvalidClassFileException e) { Assertions.UNREACHABLE(); } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy