jjg@1521: /*
jjg@1521: * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
jjg@1521: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@1521: *
jjg@1521: * This code is free software; you can redistribute it and/or modify it
jjg@1521: * under the terms of the GNU General Public License version 2 only, as
jjg@1521: * published by the Free Software Foundation. Oracle designates this
jjg@1521: * particular file as subject to the "Classpath" exception as provided
jjg@1521: * by Oracle in the LICENSE file that accompanied this code.
jjg@1521: *
jjg@1521: * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@1521: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@1521: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@1521: * version 2 for more details (a copy is included in the LICENSE file that
jjg@1521: * accompanied this code).
jjg@1521: *
jjg@1521: * You should have received a copy of the GNU General Public License version
jjg@1521: * 2 along with this work; if not, write to the Free Software Foundation,
jjg@1521: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@1521: *
jjg@1521: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jjg@1521: * or visit www.oracle.com if you need additional information or have any
jjg@1521: * questions.
jjg@1521: */
jjg@1521:
jjg@1521: package com.sun.tools.classfile;
jjg@1521:
jjg@1521: import java.io.IOException;
jjg@1521: import java.util.ArrayList;
jjg@1521: import java.util.List;
jjg@1521:
jjg@1521: import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry;
jjg@1521:
jjg@1521: /**
jjg@1521: * See JSR 308 specification, Section 3.
jjg@1521: *
jjg@1521: *
This is NOT part of any supported API.
jjg@1521: * If you write code that depends on this, you do so at your own risk.
jjg@1521: * This code and its internal interfaces are subject to change or
jjg@1521: * deletion without notice.
jjg@1521: */
jjg@1521: public class TypeAnnotation {
jjg@1521: TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
jjg@1521: constant_pool = cr.getConstantPool();
jjg@1521: position = read_position(cr);
jjg@1521: annotation = new Annotation(cr);
jjg@1521: }
jjg@1521:
jjg@1521: public TypeAnnotation(ConstantPool constant_pool,
jjg@1521: Annotation annotation, Position position) {
jjg@1521: this.constant_pool = constant_pool;
jjg@1521: this.position = position;
jjg@1521: this.annotation = annotation;
jjg@1521: }
jjg@1521:
jjg@1521: public int length() {
jjg@1521: int n = annotation.length();
jjg@1521: n += position_length(position);
jjg@1521: return n;
jjg@1521: }
jjg@1521:
jjg@1521: @Override
jjg@1521: public String toString() {
jjg@1521: try {
jjg@1521: return "@" + constant_pool.getUTF8Value(annotation.type_index).toString().substring(1) +
jjg@1521: " pos: " + position.toString();
jjg@1521: } catch (Exception e) {
jjg@1521: e.printStackTrace();
jjg@1521: return e.toString();
jjg@1521: }
jjg@1521: }
jjg@1521:
jjg@1521: public final ConstantPool constant_pool;
jjg@1521: public final Position position;
jjg@1521: public final Annotation annotation;
jjg@1521:
jjg@1521: private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
jjg@1521: // Copied from ClassReader
jjg@1521: int tag = cr.readUnsignedByte(); // TargetType tag is a byte
jjg@1521: if (!TargetType.isValidTargetTypeValue(tag))
jjg@1521: throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag));
jjg@1521:
jjg@1521: TargetType type = TargetType.fromTargetTypeValue(tag);
jjg@1521:
jjg@1521: Position position = new Position();
jjg@1521: position.type = type;
jjg@1521:
jjg@1521: switch (type) {
jjg@1521: // instanceof
jjg@1521: case INSTANCEOF:
jjg@1521: // new expression
jjg@1521: case NEW:
jjg@1563: // constructor/method reference receiver
jjg@1563: case CONSTRUCTOR_REFERENCE:
jjg@1563: case METHOD_REFERENCE:
jjg@1521: position.offset = cr.readUnsignedShort();
jjg@1521: break;
jjg@1521: // local variable
jjg@1521: case LOCAL_VARIABLE:
jjg@1521: // resource variable
jjg@1521: case RESOURCE_VARIABLE:
jjg@1521: int table_length = cr.readUnsignedShort();
jjg@1521: position.lvarOffset = new int[table_length];
jjg@1521: position.lvarLength = new int[table_length];
jjg@1521: position.lvarIndex = new int[table_length];
jjg@1521: for (int i = 0; i < table_length; ++i) {
jjg@1521: position.lvarOffset[i] = cr.readUnsignedShort();
jjg@1521: position.lvarLength[i] = cr.readUnsignedShort();
jjg@1521: position.lvarIndex[i] = cr.readUnsignedShort();
jjg@1521: }
jjg@1521: break;
jjg@1521: // exception parameter
jjg@1521: case EXCEPTION_PARAMETER:
jjg@1755: position.exception_index = cr.readUnsignedShort();
jjg@1521: break;
jjg@1521: // method receiver
jjg@1521: case METHOD_RECEIVER:
jjg@1521: // Do nothing
jjg@1521: break;
jjg@1521: // type parameter
jjg@1521: case CLASS_TYPE_PARAMETER:
jjg@1521: case METHOD_TYPE_PARAMETER:
jjg@1521: position.parameter_index = cr.readUnsignedByte();
jjg@1521: break;
jjg@1521: // type parameter bound
jjg@1521: case CLASS_TYPE_PARAMETER_BOUND:
jjg@1521: case METHOD_TYPE_PARAMETER_BOUND:
jjg@1521: position.parameter_index = cr.readUnsignedByte();
jjg@1521: position.bound_index = cr.readUnsignedByte();
jjg@1521: break;
jjg@1521: // class extends or implements clause
jjg@1521: case CLASS_EXTENDS:
jjg@1521: int in = cr.readUnsignedShort();
jjg@1521: if (in == 0xFFFF)
jjg@1521: in = -1;
jjg@1521: position.type_index = in;
jjg@1521: break;
jjg@1521: // throws
jjg@1521: case THROWS:
jjg@1521: position.type_index = cr.readUnsignedShort();
jjg@1521: break;
jjg@1521: // method parameter
jjg@1521: case METHOD_FORMAL_PARAMETER:
jjg@1521: position.parameter_index = cr.readUnsignedByte();
jjg@1521: break;
jjg@1563: // type cast
jjg@1563: case CAST:
jjg@1521: // method/constructor/reference type argument
jjg@1521: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
jjg@1521: case METHOD_INVOCATION_TYPE_ARGUMENT:
jjg@1563: case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
jjg@1521: case METHOD_REFERENCE_TYPE_ARGUMENT:
jjg@1521: position.offset = cr.readUnsignedShort();
jjg@1521: position.type_index = cr.readUnsignedByte();
jjg@1521: break;
jjg@1521: // We don't need to worry about these
jjg@1521: case METHOD_RETURN:
jjg@1521: case FIELD:
jjg@1521: break;
jjg@1521: case UNKNOWN:
jjg@1521: throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
jjg@1521: default:
jjg@1521: throw new AssertionError("TypeAnnotation: Unknown target type: " + type);
jjg@1521: }
jjg@1521:
jjg@1521: { // Write type path
jjg@1521: int len = cr.readUnsignedByte();
jjg@1521: List loc = new ArrayList(len);
jjg@1521: for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i)
jjg@1521: loc.add(cr.readUnsignedByte());
jjg@1521: position.location = Position.getTypePathFromBinary(loc);
jjg@1521: }
jjg@1521: return position;
jjg@1521: }
jjg@1521:
jjg@1521: private static int position_length(Position pos) {
jjg@1521: int n = 0;
jjg@1521: n += 1; // TargetType tag is a byte
jjg@1521: switch (pos.type) {
jjg@1521: // instanceof
jjg@1521: case INSTANCEOF:
jjg@1521: // new expression
jjg@1521: case NEW:
jjg@1563: // constructor/method reference receiver
jjg@1563: case CONSTRUCTOR_REFERENCE:
jjg@1563: case METHOD_REFERENCE:
jjg@1563: n += 2; // offset
jjg@1521: break;
jjg@1521: // local variable
jjg@1521: case LOCAL_VARIABLE:
jjg@1521: // resource variable
jjg@1521: case RESOURCE_VARIABLE:
jjg@1521: n += 2; // table_length;
jjg@1521: int table_length = pos.lvarOffset.length;
jjg@1521: n += 2 * table_length; // offset
jjg@1563: n += 2 * table_length; // length
jjg@1521: n += 2 * table_length; // index
jjg@1521: break;
jjg@1521: // exception parameter
jjg@1521: case EXCEPTION_PARAMETER:
jjg@1755: n += 2; // exception_index
jjg@1521: break;
jjg@1521: // method receiver
jjg@1521: case METHOD_RECEIVER:
jjg@1521: // Do nothing
jjg@1521: break;
jjg@1521: // type parameter
jjg@1521: case CLASS_TYPE_PARAMETER:
jjg@1521: case METHOD_TYPE_PARAMETER:
jjg@1563: n += 1; // parameter_index
jjg@1521: break;
jjg@1521: // type parameter bound
jjg@1521: case CLASS_TYPE_PARAMETER_BOUND:
jjg@1521: case METHOD_TYPE_PARAMETER_BOUND:
jjg@1521: n += 1; // parameter_index
jjg@1521: n += 1; // bound_index
jjg@1521: break;
jjg@1521: // class extends or implements clause
jjg@1521: case CLASS_EXTENDS:
jjg@1521: n += 2; // type_index
jjg@1521: break;
jjg@1521: // throws
jjg@1521: case THROWS:
jjg@1521: n += 2; // type_index
jjg@1521: break;
jjg@1521: // method parameter
jjg@1521: case METHOD_FORMAL_PARAMETER:
jjg@1521: n += 1; // parameter_index
jjg@1521: break;
jjg@1563: // type cast
jjg@1563: case CAST:
jjg@1521: // method/constructor/reference type argument
jjg@1521: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
jjg@1521: case METHOD_INVOCATION_TYPE_ARGUMENT:
jjg@1563: case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
jjg@1521: case METHOD_REFERENCE_TYPE_ARGUMENT:
jjg@1521: n += 2; // offset
jjg@1521: n += 1; // type index
jjg@1521: break;
jjg@1521: // We don't need to worry about these
jjg@1521: case METHOD_RETURN:
jjg@1521: case FIELD:
jjg@1521: break;
jjg@1521: case UNKNOWN:
jjg@1521: throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
jjg@1521: default:
jjg@1521: throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type);
jjg@1521: }
jjg@1521:
jjg@1521: {
jjg@1521: n += 1; // length
jjg@1521: n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array
jjg@1521: }
jjg@1521:
jjg@1521: return n;
jjg@1521: }
jjg@1521:
jjg@1521: // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition
jjg@1521: public static class Position {
jjg@1521: public enum TypePathEntryKind {
jjg@1521: ARRAY(0),
jjg@1521: INNER_TYPE(1),
jjg@1521: WILDCARD(2),
jjg@1521: TYPE_ARGUMENT(3);
jjg@1521:
jjg@1521: public final int tag;
jjg@1521:
jjg@1521: private TypePathEntryKind(int tag) {
jjg@1521: this.tag = tag;
jjg@1521: }
jjg@1521: }
jjg@1521:
jjg@1521: public static class TypePathEntry {
jjg@1521: /** The fixed number of bytes per TypePathEntry. */
jjg@1521: public static final int bytesPerEntry = 2;
jjg@1521:
jjg@1521: public final TypePathEntryKind tag;
jjg@1521: public final int arg;
jjg@1521:
jjg@1521: public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY);
jjg@1521: public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE);
jjg@1521: public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD);
jjg@1521:
jjg@1521: private TypePathEntry(TypePathEntryKind tag) {
jjg@1521: if (!(tag == TypePathEntryKind.ARRAY ||
jjg@1521: tag == TypePathEntryKind.INNER_TYPE ||
jjg@1521: tag == TypePathEntryKind.WILDCARD)) {
jjg@1521: throw new AssertionError("Invalid TypePathEntryKind: " + tag);
jjg@1521: }
jjg@1521: this.tag = tag;
jjg@1521: this.arg = 0;
jjg@1521: }
jjg@1521:
jjg@1521: public TypePathEntry(TypePathEntryKind tag, int arg) {
jjg@1521: if (tag != TypePathEntryKind.TYPE_ARGUMENT) {
jjg@1521: throw new AssertionError("Invalid TypePathEntryKind: " + tag);
jjg@1521: }
jjg@1521: this.tag = tag;
jjg@1521: this.arg = arg;
jjg@1521: }
jjg@1521:
jjg@1521: public static TypePathEntry fromBinary(int tag, int arg) {
jjg@1521: if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) {
jjg@1521: throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg);
jjg@1521: }
jjg@1521: switch (tag) {
jjg@1521: case 0:
jjg@1521: return ARRAY;
jjg@1521: case 1:
jjg@1521: return INNER_TYPE;
jjg@1521: case 2:
jjg@1521: return WILDCARD;
jjg@1521: case 3:
jjg@1521: return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg);
jjg@1521: default:
jjg@1521: throw new AssertionError("Invalid TypePathEntryKind tag: " + tag);
jjg@1521: }
jjg@1521: }
jjg@1521:
jjg@1521: @Override
jjg@1521: public String toString() {
jjg@1521: return tag.toString() +
jjg@1521: (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
jjg@1521: }
jjg@1521:
jjg@1521: @Override
jjg@1521: public boolean equals(Object other) {
jjg@1521: if (! (other instanceof TypePathEntry)) {
jjg@1521: return false;
jjg@1521: }
jjg@1521: TypePathEntry tpe = (TypePathEntry) other;
jjg@1521: return this.tag == tpe.tag && this.arg == tpe.arg;
jjg@1521: }
jjg@1521:
jjg@1521: @Override
jjg@1521: public int hashCode() {
jjg@1521: return this.tag.hashCode() * 17 + this.arg;
jjg@1521: }
jjg@1521: }
jjg@1521:
jjg@1521: public TargetType type = TargetType.UNKNOWN;
jjg@1521:
jjg@1521: // For generic/array types.
jjg@1521: // TODO: or should we use null? Noone will use this object.
jjg@1521: public List location = new ArrayList(0);
jjg@1521:
jjg@1521: // Tree position.
jjg@1521: public int pos = -1;
jjg@1521:
jjg@1521: // For typecasts, type tests, new (and locals, as start_pc).
jjg@1521: public boolean isValidOffset = false;
jjg@1521: public int offset = -1;
jjg@1521:
jjg@1521: // For locals. arrays same length
jjg@1521: public int[] lvarOffset = null;
jjg@1521: public int[] lvarLength = null;
jjg@1521: public int[] lvarIndex = null;
jjg@1521:
jjg@1521: // For type parameter bound
jjg@1521: public int bound_index = Integer.MIN_VALUE;
jjg@1521:
jjg@1521: // For type parameter and method parameter
jjg@1521: public int parameter_index = Integer.MIN_VALUE;
jjg@1521:
jjg@1521: // For class extends, implements, and throws clauses
jjg@1521: public int type_index = Integer.MIN_VALUE;
jjg@1521:
jjg@1521: // For exception parameters, index into exception table
jjg@1521: public int exception_index = Integer.MIN_VALUE;
jjg@1521:
jjg@1521: public Position() {}
jjg@1521:
jjg@1521: @Override
jjg@1521: public String toString() {
jjg@1521: StringBuilder sb = new StringBuilder();
jjg@1521: sb.append('[');
jjg@1521: sb.append(type);
jjg@1521:
jjg@1521: switch (type) {
jjg@1521: // instanceof
jjg@1521: case INSTANCEOF:
jjg@1521: // new expression
jjg@1521: case NEW:
jjg@1563: // constructor/method reference receiver
jjg@1563: case CONSTRUCTOR_REFERENCE:
jjg@1563: case METHOD_REFERENCE:
jjg@1521: sb.append(", offset = ");
jjg@1521: sb.append(offset);
jjg@1521: break;
jjg@1521: // local variable
jjg@1521: case LOCAL_VARIABLE:
jjg@1521: // resource variable
jjg@1521: case RESOURCE_VARIABLE:
jjg@1521: if (lvarOffset == null) {
jjg@1521: sb.append(", lvarOffset is null!");
jjg@1521: break;
jjg@1521: }
jjg@1521: sb.append(", {");
jjg@1521: for (int i = 0; i < lvarOffset.length; ++i) {
jjg@1521: if (i != 0) sb.append("; ");
jjg@1521: sb.append("start_pc = ");
jjg@1521: sb.append(lvarOffset[i]);
jjg@1521: sb.append(", length = ");
jjg@1521: sb.append(lvarLength[i]);
jjg@1521: sb.append(", index = ");
jjg@1521: sb.append(lvarIndex[i]);
jjg@1521: }
jjg@1521: sb.append("}");
jjg@1521: break;
jjg@1521: // method receiver
jjg@1521: case METHOD_RECEIVER:
jjg@1521: // Do nothing
jjg@1521: break;
jjg@1521: // type parameter
jjg@1521: case CLASS_TYPE_PARAMETER:
jjg@1521: case METHOD_TYPE_PARAMETER:
jjg@1521: sb.append(", param_index = ");
jjg@1521: sb.append(parameter_index);
jjg@1521: break;
jjg@1521: // type parameter bound
jjg@1521: case CLASS_TYPE_PARAMETER_BOUND:
jjg@1521: case METHOD_TYPE_PARAMETER_BOUND:
jjg@1521: sb.append(", param_index = ");
jjg@1521: sb.append(parameter_index);
jjg@1521: sb.append(", bound_index = ");
jjg@1521: sb.append(bound_index);
jjg@1521: break;
jjg@1521: // class extends or implements clause
jjg@1521: case CLASS_EXTENDS:
jjg@1521: sb.append(", type_index = ");
jjg@1521: sb.append(type_index);
jjg@1521: break;
jjg@1521: // throws
jjg@1521: case THROWS:
jjg@1521: sb.append(", type_index = ");
jjg@1521: sb.append(type_index);
jjg@1521: break;
jjg@1521: // exception parameter
jjg@1521: case EXCEPTION_PARAMETER:
jjg@1521: sb.append(", exception_index = ");
jjg@1521: sb.append(exception_index);
jjg@1521: break;
jjg@1521: // method parameter
jjg@1521: case METHOD_FORMAL_PARAMETER:
jjg@1521: sb.append(", param_index = ");
jjg@1521: sb.append(parameter_index);
jjg@1521: break;
jjg@1563: // type cast
jjg@1563: case CAST:
jjg@1521: // method/constructor/reference type argument
jjg@1521: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
jjg@1521: case METHOD_INVOCATION_TYPE_ARGUMENT:
jjg@1563: case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
jjg@1521: case METHOD_REFERENCE_TYPE_ARGUMENT:
jjg@1521: sb.append(", offset = ");
jjg@1521: sb.append(offset);
jjg@1521: sb.append(", type_index = ");
jjg@1521: sb.append(type_index);
jjg@1521: break;
jjg@1521: // We don't need to worry about these
jjg@1521: case METHOD_RETURN:
jjg@1521: case FIELD:
jjg@1521: break;
jjg@1521: case UNKNOWN:
jjg@1521: sb.append(", position UNKNOWN!");
jjg@1521: break;
jjg@1521: default:
jjg@1521: throw new AssertionError("Unknown target type: " + type);
jjg@1521: }
jjg@1521:
jjg@1521: // Append location data for generics/arrays.
jjg@1521: if (!location.isEmpty()) {
jjg@1521: sb.append(", location = (");
jjg@1521: sb.append(location);
jjg@1521: sb.append(")");
jjg@1521: }
jjg@1521:
jjg@1521: sb.append(", pos = ");
jjg@1521: sb.append(pos);
jjg@1521:
jjg@1521: sb.append(']');
jjg@1521: return sb.toString();
jjg@1521: }
jjg@1521:
jjg@1521: /**
jjg@1521: * Indicates whether the target tree of the annotation has been optimized
jjg@1521: * away from classfile or not.
jjg@1521: * @return true if the target has not been optimized away
jjg@1521: */
jjg@1521: public boolean emitToClassfile() {
jjg@1521: return !type.isLocal() || isValidOffset;
jjg@1521: }
jjg@1521:
jjg@1521: /**
jjg@1521: * Decode the binary representation for a type path and set
jjg@1521: * the {@code location} field.
jjg@1521: *
jjg@1521: * @param list The bytecode representation of the type path.
jjg@1521: */
jjg@1521: public static List getTypePathFromBinary(List list) {
jjg@1521: List loc = new ArrayList(list.size() / TypePathEntry.bytesPerEntry);
jjg@1521: int idx = 0;
jjg@1521: while (idx < list.size()) {
jjg@1521: if (idx + 1 == list.size()) {
jjg@1521: throw new AssertionError("Could not decode type path: " + list);
jjg@1521: }
jjg@1521: loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1)));
jjg@1521: idx += 2;
jjg@1521: }
jjg@1521: return loc;
jjg@1521: }
jjg@1521:
jjg@1521: public static List getBinaryFromTypePath(List locs) {
jjg@1521: List loc = new ArrayList(locs.size() * TypePathEntry.bytesPerEntry);
jjg@1521: for (TypePathEntry tpe : locs) {
jjg@1521: loc.add(tpe.tag.tag);
jjg@1521: loc.add(tpe.arg);
jjg@1521: }
jjg@1521: return loc;
jjg@1521: }
jjg@1521: }
jjg@1521:
jjg@1521: // Code duplicated from com.sun.tools.javac.code.TargetType
jjg@1521: // The IsLocal flag could be removed here.
jjg@1521: public enum TargetType {
jjg@1521: /** For annotations on a class type parameter declaration. */
jjg@1521: CLASS_TYPE_PARAMETER(0x00),
jjg@1521:
jjg@1521: /** For annotations on a method type parameter declaration. */
jjg@1521: METHOD_TYPE_PARAMETER(0x01),
jjg@1521:
jjg@1521: /** For annotations on the type of an "extends" or "implements" clause. */
jjg@1521: CLASS_EXTENDS(0x10),
jjg@1521:
jjg@1521: /** For annotations on a bound of a type parameter of a class. */
jjg@1521: CLASS_TYPE_PARAMETER_BOUND(0x11),
jjg@1521:
jjg@1521: /** For annotations on a bound of a type parameter of a method. */
jjg@1521: METHOD_TYPE_PARAMETER_BOUND(0x12),
jjg@1521:
jjg@1521: /** For annotations on a field. */
jjg@1521: FIELD(0x13),
jjg@1521:
jjg@1521: /** For annotations on a method return type. */
jjg@1521: METHOD_RETURN(0x14),
jjg@1521:
jjg@1521: /** For annotations on the method receiver. */
jjg@1521: METHOD_RECEIVER(0x15),
jjg@1521:
jjg@1521: /** For annotations on a method parameter. */
jjg@1521: METHOD_FORMAL_PARAMETER(0x16),
jjg@1521:
jjg@1521: /** For annotations on a throws clause in a method declaration. */
jjg@1521: THROWS(0x17),
jjg@1521:
jjg@1521: /** For annotations on a local variable. */
jjg@1521: LOCAL_VARIABLE(0x40, true),
jjg@1521:
jjg@1521: /** For annotations on a resource variable. */
jjg@1521: RESOURCE_VARIABLE(0x41, true),
jjg@1521:
jjg@1521: /** For annotations on an exception parameter. */
jjg@1521: EXCEPTION_PARAMETER(0x42, true),
jjg@1521:
jjg@1521: /** For annotations on a type test. */
jjg@1563: INSTANCEOF(0x43, true),
jjg@1521:
jjg@1521: /** For annotations on an object creation expression. */
jjg@1563: NEW(0x44, true),
jjg@1563:
jjg@1563: /** For annotations on a constructor reference receiver. */
jjg@1563: CONSTRUCTOR_REFERENCE(0x45, true),
jjg@1563:
jjg@1563: /** For annotations on a method reference receiver. */
jjg@1563: METHOD_REFERENCE(0x46, true),
jjg@1563:
jjg@1563: /** For annotations on a typecast. */
jjg@1563: CAST(0x47, true),
jjg@1521:
jjg@1521: /** For annotations on a type argument of an object creation expression. */
jjg@1563: CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true),
jjg@1521:
jjg@1521: /** For annotations on a type argument of a method call. */
jjg@1563: METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true),
jjg@1521:
jjg@1563: /** For annotations on a type argument of a constructor reference. */
jjg@1563: CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true),
jjg@1521:
jjg@1521: /** For annotations on a type argument of a method reference. */
jjg@1563: METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true),
jjg@1521:
jjg@1521: /** For annotations with an unknown target. */
jjg@1521: UNKNOWN(0xFF);
jjg@1521:
jjg@1563: private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B;
jjg@1521:
jjg@1521: private final int targetTypeValue;
jjg@1521: private final boolean isLocal;
jjg@1521:
jjg@1521: private TargetType(int targetTypeValue) {
jjg@1521: this(targetTypeValue, false);
jjg@1521: }
jjg@1521:
jjg@1521: private TargetType(int targetTypeValue, boolean isLocal) {
jjg@1521: if (targetTypeValue < 0
jjg@1521: || targetTypeValue > 255)
jjg@1521: throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue));
jjg@1521: this.targetTypeValue = targetTypeValue;
jjg@1521: this.isLocal = isLocal;
jjg@1521: }
jjg@1521:
jjg@1521: /**
jjg@1521: * Returns whether or not this TargetType represents an annotation whose
jjg@1521: * target is exclusively a tree in a method body
jjg@1521: *
jjg@1521: * Note: wildcard bound targets could target a local tree and a class
jjg@1521: * member declaration signature tree
jjg@1521: */
jjg@1521: public boolean isLocal() {
jjg@1521: return isLocal;
jjg@1521: }
jjg@1521:
jjg@1521: public int targetTypeValue() {
jjg@1521: return this.targetTypeValue;
jjg@1521: }
jjg@1521:
jjg@1521: private static final TargetType[] targets;
jjg@1521:
jjg@1521: static {
jjg@1521: targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1];
jjg@1521: TargetType[] alltargets = values();
jjg@1521: for (TargetType target : alltargets) {
jjg@1521: if (target.targetTypeValue != UNKNOWN.targetTypeValue)
jjg@1521: targets[target.targetTypeValue] = target;
jjg@1521: }
jjg@1521: for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) {
jjg@1521: if (targets[i] == null)
jjg@1521: targets[i] = UNKNOWN;
jjg@1521: }
jjg@1521: }
jjg@1521:
jjg@1521: public static boolean isValidTargetTypeValue(int tag) {
jjg@1521: if (tag == UNKNOWN.targetTypeValue)
jjg@1521: return true;
jjg@1521: return (tag >= 0 && tag < targets.length);
jjg@1521: }
jjg@1521:
jjg@1521: public static TargetType fromTargetTypeValue(int tag) {
jjg@1521: if (tag == UNKNOWN.targetTypeValue)
jjg@1521: return UNKNOWN;
jjg@1521:
jjg@1521: if (tag < 0 || tag >= targets.length)
jjg@1521: throw new AssertionError("Unknown TargetType: " + tag);
jjg@1521: return targets[tag];
jjg@1521: }
jjg@1521: }
jjg@1521: }