jjg@309: /* jjg@309: * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. jjg@309: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jjg@309: * jjg@309: * This code is free software; you can redistribute it and/or modify it jjg@309: * under the terms of the GNU General Public License version 2 only, as jjg@309: * published by the Free Software Foundation. Sun designates this jjg@309: * particular file as subject to the "Classpath" exception as provided jjg@309: * by Sun in the LICENSE file that accompanied this code. jjg@309: * jjg@309: * This code is distributed in the hope that it will be useful, but WITHOUT jjg@309: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jjg@309: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jjg@309: * version 2 for more details (a copy is included in the LICENSE file that jjg@309: * accompanied this code). jjg@309: * jjg@309: * You should have received a copy of the GNU General Public License version jjg@309: * 2 along with this work; if not, write to the Free Software Foundation, jjg@309: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jjg@309: * jjg@309: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, jjg@309: * CA 95054 USA or visit www.sun.com if you need additional information or jjg@309: * have any questions. jjg@309: */ jjg@309: jjg@309: package com.sun.tools.classfile; jjg@309: jjg@309: import java.io.IOException; jjg@309: import java.util.ArrayList; jjg@309: import java.util.EnumSet; jjg@309: import java.util.List; jjg@309: import java.util.Set; jjg@309: jjg@309: import static com.sun.tools.classfile.ExtendedAnnotation.TargetAttribute.*; jjg@309: jjg@309: /** jjg@309: * See JSR 308 specification, section 4.1 jjg@309: * jjg@309: *

This is NOT part of any API supported by Sun Microsystems. If jjg@309: * you write code that depends on this, you do so at your own risk. jjg@309: * This code and its internal interfaces are subject to change or jjg@309: * deletion without notice. jjg@309: */ jjg@309: public class ExtendedAnnotation { jjg@309: ExtendedAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { jjg@309: annotation = new Annotation(cr); jjg@309: position = read_position(cr); jjg@309: } jjg@309: jjg@309: public ExtendedAnnotation(ConstantPool constant_pool, jjg@309: Annotation annotation, Position position) { jjg@309: this.annotation = annotation; jjg@309: this.position = position; jjg@309: } jjg@309: jjg@309: public int length() { jjg@309: int n = annotation.length(); jjg@309: n += position_length(position); jjg@309: return n; jjg@309: } jjg@309: jjg@309: public final Annotation annotation; jjg@309: public final Position position; jjg@309: jjg@309: private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { jjg@309: // Copied from ClassReader jjg@309: int tag = (byte)cr.readUnsignedByte(); // cast to introduce signedness jjg@309: if (!TargetType.isValidTargetTypeValue(tag)) jjg@309: throw new Annotation.InvalidAnnotation("invalid type annotation target type value: " + tag); jjg@309: jjg@309: TargetType type = TargetType.fromTargetTypeValue(tag); jjg@309: jjg@309: Position position = new Position(); jjg@309: position.type = type; jjg@309: jjg@309: switch (type) { jjg@309: // type case jjg@309: case TYPECAST: jjg@309: case TYPECAST_GENERIC_OR_ARRAY: jjg@309: // object creation jjg@309: case INSTANCEOF: jjg@309: case INSTANCEOF_GENERIC_OR_ARRAY: jjg@309: // new expression jjg@309: case NEW: jjg@309: case NEW_GENERIC_OR_ARRAY: jjg@309: position.offset = cr.readUnsignedShort(); jjg@309: break; jjg@309: // local variable jjg@309: case LOCAL_VARIABLE: jjg@309: case LOCAL_VARIABLE_GENERIC_OR_ARRAY: jjg@309: int table_length = cr.readUnsignedShort(); jjg@309: position.lvarOffset = new int[table_length]; jjg@309: position.lvarLength = new int[table_length]; jjg@309: position.lvarIndex = new int[table_length]; jjg@309: for (int i = 0; i < table_length; ++i) { jjg@309: position.lvarOffset[i] = cr.readUnsignedShort(); jjg@309: position.lvarLength[i] = cr.readUnsignedShort(); jjg@309: position.lvarIndex[i] = cr.readUnsignedShort(); jjg@309: } jjg@309: break; jjg@309: // method receiver jjg@309: case METHOD_RECEIVER: jjg@309: // Do nothing jjg@309: break; jjg@309: // type parameters jjg@309: case CLASS_TYPE_PARAMETER: jjg@309: case METHOD_TYPE_PARAMETER: jjg@309: position.parameter_index = cr.readUnsignedByte(); jjg@309: break; jjg@309: // type parameter bounds jjg@309: case CLASS_TYPE_PARAMETER_BOUND: jjg@309: case CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: jjg@309: case METHOD_TYPE_PARAMETER_BOUND: jjg@309: case METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: jjg@309: position.parameter_index = cr.readUnsignedByte(); jjg@309: position.bound_index = cr.readUnsignedByte(); jjg@309: break; jjg@309: // wildcards jjg@309: case WILDCARD_BOUND: jjg@309: case WILDCARD_BOUND_GENERIC_OR_ARRAY: jjg@309: position.wildcard_position = read_position(cr); jjg@309: break; jjg@309: // Class extends and implements clauses jjg@309: case CLASS_EXTENDS: jjg@309: case CLASS_EXTENDS_GENERIC_OR_ARRAY: jjg@309: position.type_index = cr.readUnsignedByte(); jjg@309: break; jjg@309: // throws jjg@309: case THROWS: jjg@309: position.type_index = cr.readUnsignedByte(); jjg@309: break; jjg@309: case CLASS_LITERAL: jjg@309: case CLASS_LITERAL_GENERIC_OR_ARRAY: jjg@309: position.offset = cr.readUnsignedShort(); jjg@309: break; jjg@309: // method parameter: not specified jjg@309: case METHOD_PARAMETER_GENERIC_OR_ARRAY: jjg@309: position.parameter_index = cr.readUnsignedByte(); jjg@309: break; jjg@309: // method type argument: wasn't specified jjg@309: case NEW_TYPE_ARGUMENT: jjg@309: case NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY: jjg@309: case METHOD_TYPE_ARGUMENT: jjg@309: case METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY: jjg@309: position.offset = cr.readUnsignedShort(); jjg@309: position.type_index = cr.readUnsignedByte(); jjg@309: break; jjg@309: // We don't need to worry abut these jjg@309: case METHOD_RETURN_GENERIC_OR_ARRAY: jjg@309: case FIELD_GENERIC_OR_ARRAY: jjg@309: break; jjg@309: case UNKNOWN: jjg@309: break; jjg@309: default: jjg@309: throw new AssertionError("Cannot be here"); jjg@309: } jjg@309: jjg@309: if (type.hasLocation()) { jjg@309: int len = cr.readUnsignedShort(); jjg@309: List loc = new ArrayList(len); jjg@309: for (int i = 0; i < len; i++) jjg@309: loc.add(cr.readUnsignedByte()); jjg@309: position.location = loc; jjg@309: } jjg@309: return position; jjg@309: } jjg@309: jjg@309: private static int position_length(Position pos) { jjg@309: int n = 0; jjg@309: n += 1; // target_type jjg@309: switch (pos.type) { jjg@309: // type case jjg@309: case TYPECAST: jjg@309: case TYPECAST_GENERIC_OR_ARRAY: jjg@309: // object creation jjg@309: case INSTANCEOF: jjg@309: case INSTANCEOF_GENERIC_OR_ARRAY: jjg@309: // new expression jjg@309: case NEW: jjg@309: case NEW_GENERIC_OR_ARRAY: jjg@309: n += 2; jjg@309: break; jjg@309: // local variable jjg@309: case LOCAL_VARIABLE: jjg@309: case LOCAL_VARIABLE_GENERIC_OR_ARRAY: jjg@309: n += 2; // table_length; jjg@309: int table_length = pos.lvarOffset.length; jjg@309: n += 2 * table_length; // offset jjg@309: n += 2 * table_length; // length; jjg@309: n += 2 * table_length; // index jjg@309: break; jjg@309: // method receiver jjg@309: case METHOD_RECEIVER: jjg@309: // Do nothing jjg@309: break; jjg@309: // type parameters jjg@309: case CLASS_TYPE_PARAMETER: jjg@309: case METHOD_TYPE_PARAMETER: jjg@309: n += 1; // parameter_index; jjg@309: break; jjg@309: // type parameter bounds jjg@309: case CLASS_TYPE_PARAMETER_BOUND: jjg@309: case CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: jjg@309: case METHOD_TYPE_PARAMETER_BOUND: jjg@309: case METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: jjg@309: n += 1; // parameter_index jjg@309: n += 1; // bound_index jjg@309: break; jjg@309: case WILDCARD_BOUND: jjg@309: case WILDCARD_BOUND_GENERIC_OR_ARRAY: jjg@309: n += position_length(pos.wildcard_position); jjg@309: break; jjg@309: // Class extends and implements clauses jjg@309: case CLASS_EXTENDS: jjg@309: case CLASS_EXTENDS_GENERIC_OR_ARRAY: jjg@309: n += 1; // type_index jjg@309: break; jjg@309: // throws jjg@309: case THROWS: jjg@309: n += 1; // type_index jjg@309: break; jjg@309: case CLASS_LITERAL: jjg@309: case CLASS_LITERAL_GENERIC_OR_ARRAY: jjg@309: n += 1; // offset jjg@309: break; jjg@309: // method parameter: not specified jjg@309: case METHOD_PARAMETER_GENERIC_OR_ARRAY: jjg@309: n += 1; // parameter_index jjg@309: break; jjg@309: // method type argument: wasn't specified jjg@309: case NEW_TYPE_ARGUMENT: jjg@309: case NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY: jjg@309: case METHOD_TYPE_ARGUMENT: jjg@309: case METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY: jjg@309: n += 2; // offset jjg@309: n += 1; // type index jjg@309: break; jjg@309: // We don't need to worry abut these jjg@309: case METHOD_RETURN_GENERIC_OR_ARRAY: jjg@309: case FIELD_GENERIC_OR_ARRAY: jjg@309: break; jjg@309: case UNKNOWN: jjg@309: break; jjg@309: default: jjg@309: } jjg@309: jjg@309: if (pos.type.hasLocation()) { jjg@309: n += 2; // length jjg@309: n += 1 * pos.location.size(); // actual array size jjg@309: } jjg@309: jjg@309: return n; jjg@309: } jjg@309: jjg@309: // Code duplicated from com.sun.tools.javac.code.TypeAnnotations.Position jjg@309: public static class Position { jjg@309: jjg@309: public TargetType type = TargetType.UNKNOWN; jjg@309: jjg@309: // For generic/array types. jjg@309: public List location = new ArrayList(); jjg@309: jjg@309: // Tree position. jjg@309: public int pos = -1; jjg@309: jjg@309: // For typecasts, type tests, new (and locals, as start_pc). jjg@309: public int offset = -1; jjg@309: jjg@309: // For locals. jjg@309: public int[] lvarOffset = new int[] { -1 }; jjg@309: public int[] lvarLength = new int[] { -1 }; jjg@309: public int[] lvarIndex = new int[] { -1 }; jjg@309: jjg@309: // For type parameter bound jjg@309: public int bound_index = -1; jjg@309: jjg@309: // For type parameter and method parameter jjg@309: public int parameter_index = -1; jjg@309: jjg@309: // For class extends, implements, and throws classes jjg@309: public int type_index = -2; jjg@309: jjg@309: // For wildcards jjg@309: public Position wildcard_position = null; jjg@309: jjg@309: @Override jjg@309: public String toString() { jjg@309: StringBuilder sb = new StringBuilder(); jjg@309: sb.append('['); jjg@309: sb.append(type); jjg@309: jjg@309: switch (type) { jjg@309: // type case jjg@309: case TYPECAST: jjg@309: case TYPECAST_GENERIC_OR_ARRAY: jjg@309: // object creation jjg@309: case INSTANCEOF: jjg@309: case INSTANCEOF_GENERIC_OR_ARRAY: jjg@309: // new expression jjg@309: case NEW: jjg@309: case NEW_GENERIC_OR_ARRAY: jjg@309: case NEW_TYPE_ARGUMENT: jjg@309: case NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY: jjg@309: sb.append(", offset = "); jjg@309: sb.append(offset); jjg@309: break; jjg@309: // local variable jjg@309: case LOCAL_VARIABLE: jjg@309: case LOCAL_VARIABLE_GENERIC_OR_ARRAY: jjg@309: sb.append(", {"); jjg@309: for (int i = 0; i < lvarOffset.length; ++i) { jjg@309: if (i != 0) sb.append("; "); jjg@309: sb.append(", start_pc = "); jjg@309: sb.append(lvarOffset[i]); jjg@309: sb.append(", length = "); jjg@309: sb.append(lvarLength[i]); jjg@309: sb.append(", index = "); jjg@309: sb.append(lvarIndex[i]); jjg@309: } jjg@309: sb.append("}"); jjg@309: break; jjg@309: // method receiver jjg@309: case METHOD_RECEIVER: jjg@309: // Do nothing jjg@309: break; jjg@309: // type parameters jjg@309: case CLASS_TYPE_PARAMETER: jjg@309: case METHOD_TYPE_PARAMETER: jjg@309: sb.append(", param_index = "); jjg@309: sb.append(parameter_index); jjg@309: break; jjg@309: // type parameters bound jjg@309: case CLASS_TYPE_PARAMETER_BOUND: jjg@309: case CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: jjg@309: case METHOD_TYPE_PARAMETER_BOUND: jjg@309: case METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: jjg@309: sb.append(", param_index = "); jjg@309: sb.append(parameter_index); jjg@309: sb.append(", bound_index = "); jjg@309: sb.append(bound_index); jjg@309: break; jjg@309: // wildcard jjg@309: case WILDCARD_BOUND: jjg@309: case WILDCARD_BOUND_GENERIC_OR_ARRAY: jjg@309: sb.append(", wild_card = "); jjg@309: sb.append(wildcard_position); jjg@309: break; jjg@309: // Class extends and implements clauses jjg@309: case CLASS_EXTENDS: jjg@309: case CLASS_EXTENDS_GENERIC_OR_ARRAY: jjg@309: sb.append(", type_index = "); jjg@309: sb.append(type_index); jjg@309: break; jjg@309: // throws jjg@309: case THROWS: jjg@309: sb.append(", type_index = "); jjg@309: sb.append(type_index); jjg@309: break; jjg@309: case CLASS_LITERAL: jjg@309: sb.append(", offset = "); jjg@309: sb.append(offset); jjg@309: break; jjg@309: // method parameter: not specified jjg@309: case METHOD_PARAMETER_GENERIC_OR_ARRAY: jjg@309: sb.append(", param_index = "); jjg@309: sb.append(parameter_index); jjg@309: break; jjg@309: // method type argument: wasn't specified jjg@309: case METHOD_TYPE_ARGUMENT: jjg@309: case METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY: jjg@309: sb.append(", offset = "); jjg@309: sb.append(offset); jjg@309: sb.append(", type_index = "); jjg@309: sb.append(type_index); jjg@309: break; jjg@309: // We don't need to worry abut these jjg@309: case METHOD_RETURN_GENERIC_OR_ARRAY: jjg@309: case FIELD_GENERIC_OR_ARRAY: jjg@309: break; jjg@309: case UNKNOWN: jjg@309: break; jjg@309: default: jjg@309: throw new AssertionError("unknown type: " + type); jjg@309: } jjg@309: jjg@309: // Append location data for generics/arrays. jjg@309: if (type.hasLocation()) { jjg@309: sb.append(", location = ("); jjg@309: sb.append(location); jjg@309: sb.append(")"); jjg@309: } jjg@309: jjg@309: sb.append(", pos = "); jjg@309: sb.append(pos); jjg@309: jjg@309: sb.append(']'); jjg@309: return sb.toString(); jjg@309: } jjg@309: } jjg@309: jjg@309: // Code duplicated from com.sun.tools.javac.comp.TargetType jjg@309: public enum TargetType { jjg@309: jjg@309: /** For annotations on typecasts. */ jjg@309: TYPECAST(0x00), jjg@309: jjg@309: /** For annotations on a type argument or nested array of a typecast. */ jjg@309: TYPECAST_GENERIC_OR_ARRAY(0x01, HasLocation), jjg@309: jjg@309: /** For annotations on type tests. */ jjg@309: INSTANCEOF(0x02), jjg@309: jjg@309: /** For annotations on a type argument or nested array of a type test. */ jjg@309: INSTANCEOF_GENERIC_OR_ARRAY(0x03, HasLocation), jjg@309: jjg@309: /** For annotations on object creation expressions. */ jjg@309: NEW(0x04), jjg@309: jjg@309: /** jjg@309: * For annotations on a type argument or nested array of an object creation jjg@309: * expression. jjg@309: */ jjg@309: NEW_GENERIC_OR_ARRAY(0x05, HasLocation), jjg@309: jjg@309: jjg@309: /** For annotations on the method receiver. */ jjg@309: METHOD_RECEIVER(0x06), jjg@309: jjg@309: // invalid location jjg@309: // METHOD_RECEIVER_GENERIC_OR_ARRAY(0x07, HasLocation), jjg@309: jjg@309: /** For annotations on local variables. */ jjg@309: LOCAL_VARIABLE(0x08), jjg@309: jjg@309: /** For annotations on a type argument or nested array of a local. */ jjg@309: LOCAL_VARIABLE_GENERIC_OR_ARRAY(0x09, HasLocation), jjg@309: jjg@309: // already handled by regular annotations jjg@309: // METHOD_RETURN(0x0A), jjg@309: jjg@309: /** jjg@309: * For annotations on a type argument or nested array of a method return jjg@309: * type. jjg@309: */ jjg@309: METHOD_RETURN_GENERIC_OR_ARRAY(0x0B, HasLocation), jjg@309: jjg@309: // already handled by regular annotations jjg@309: // METHOD_PARAMETER(0x0C), jjg@309: jjg@309: /** For annotations on a type argument or nested array of a method parameter. */ jjg@309: METHOD_PARAMETER_GENERIC_OR_ARRAY(0x0D, HasLocation), jjg@309: jjg@309: // already handled by regular annotations jjg@309: // FIELD(0x0E), jjg@309: jjg@309: /** For annotations on a type argument or nested array of a field. */ jjg@309: FIELD_GENERIC_OR_ARRAY(0x0F, HasLocation), jjg@309: jjg@309: /** For annotations on a bound of a type parameter of a class. */ jjg@309: CLASS_TYPE_PARAMETER_BOUND(0x10, HasBound, HasParameter), jjg@309: jjg@309: /** jjg@309: * For annotations on a type argument or nested array of a bound of a type jjg@309: * parameter of a class. jjg@309: */ jjg@309: CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY(0x11, HasBound, HasLocation, HasParameter), jjg@309: jjg@309: /** For annotations on a bound of a type parameter of a method. */ jjg@309: METHOD_TYPE_PARAMETER_BOUND(0x12, HasBound, HasParameter), jjg@309: jjg@309: /** jjg@309: * For annotations on a type argument or nested array of a bound of a type jjg@309: * parameter of a method. jjg@309: */ jjg@309: METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY(0x13, HasBound, HasLocation, HasParameter), jjg@309: jjg@309: /** For annotations on the type of an "extends" or "implements" clause. */ jjg@309: CLASS_EXTENDS(0x14), jjg@309: jjg@309: /** For annotations on the inner type of an "extends" or "implements" clause. */ jjg@309: CLASS_EXTENDS_GENERIC_OR_ARRAY(0x15, HasLocation), jjg@309: jjg@309: /** For annotations on a throws clause in a method declaration. */ jjg@309: THROWS(0x16), jjg@309: jjg@309: // invalid location jjg@309: // THROWS_GENERIC_OR_ARRAY(0x17, HasLocation), jjg@309: jjg@309: /** For annotations in type arguments of object creation expressions. */ jjg@309: NEW_TYPE_ARGUMENT(0x18), jjg@309: NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY(0x19, HasLocation), jjg@309: jjg@309: METHOD_TYPE_ARGUMENT(0x1A), jjg@309: METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY(0x1B, HasLocation), jjg@309: jjg@309: WILDCARD_BOUND(0x1C, HasBound), jjg@309: WILDCARD_BOUND_GENERIC_OR_ARRAY(0x1D, HasBound, HasLocation), jjg@309: jjg@309: CLASS_LITERAL(0x1E), jjg@309: CLASS_LITERAL_GENERIC_OR_ARRAY(0x1F, HasLocation), jjg@309: jjg@309: METHOD_TYPE_PARAMETER(0x20, HasParameter), jjg@309: jjg@309: // invalid location jjg@309: // METHOD_TYPE_PARAMETER_GENERIC_OR_ARRAY(0x21, HasLocation, HasParameter), jjg@309: jjg@309: CLASS_TYPE_PARAMETER(0x22, HasParameter), jjg@309: jjg@309: // invalid location jjg@309: // CLASS_TYPE_PARAMETER_GENERIC_OR_ARRAY(0x23, HasLocation, HasParameter), jjg@309: jjg@309: /** For annotations with an unknown target. */ jjg@309: UNKNOWN(-1); jjg@309: jjg@309: static final int MAXIMUM_TARGET_TYPE_VALUE = 0x22; jjg@309: jjg@309: private final int targetTypeValue; jjg@309: private Set flags; jjg@309: jjg@309: TargetType(int targetTypeValue, TargetAttribute... attrs) { jjg@309: if (targetTypeValue < Byte.MIN_VALUE jjg@309: || targetTypeValue > Byte.MAX_VALUE) jjg@309: throw new AssertionError("attribute type value needs to be a byte: " + targetTypeValue); jjg@309: this.targetTypeValue = (byte)targetTypeValue; jjg@309: this.flags = EnumSet.noneOf(TargetAttribute.class); jjg@309: for (TargetAttribute attr : attrs) jjg@309: this.flags.add(attr); jjg@309: } jjg@309: jjg@309: /** jjg@309: * Returns whether or not this TargetType represents an annotation whose jjg@309: * target is an inner type of a generic or array type. jjg@309: * jjg@309: * @return true if this TargetType represents an annotation on an inner jjg@309: * type, false otherwise jjg@309: */ jjg@309: public boolean hasLocation() { jjg@309: return flags.contains(HasLocation); jjg@309: } jjg@309: jjg@309: public TargetType getGenericComplement() { jjg@309: if (hasLocation()) jjg@309: return this; jjg@309: else jjg@309: return fromTargetTypeValue(targetTypeValue() + 1); jjg@309: } jjg@309: jjg@309: /** jjg@309: * Returns whether or not this TargetType represents an annotation whose jjg@309: * target has a parameter index. jjg@309: * jjg@309: * @return true if this TargetType has a parameter index, jjg@309: * false otherwise jjg@309: */ jjg@309: public boolean hasParameter() { jjg@309: return flags.contains(HasParameter); jjg@309: } jjg@309: jjg@309: /** jjg@309: * Returns whether or not this TargetType represents an annotation whose jjg@309: * target is a type parameter bound. jjg@309: * jjg@309: * @return true if this TargetType represents an type parameter bound jjg@309: * annotation, false otherwise jjg@309: */ jjg@309: public boolean hasBound() { jjg@309: return flags.contains(HasBound); jjg@309: } jjg@309: jjg@309: public int targetTypeValue() { jjg@309: return this.targetTypeValue; jjg@309: } jjg@309: jjg@309: private static TargetType[] targets = null; jjg@309: jjg@309: private static TargetType[] buildTargets() { jjg@309: TargetType[] targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1]; jjg@309: TargetType[] alltargets = values(); jjg@309: for (TargetType target : alltargets) jjg@309: if (target.targetTypeValue >= 0) jjg@309: targets[target.targetTypeValue] = target; jjg@309: for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) jjg@309: if (targets[i] == null) jjg@309: targets[i] = UNKNOWN; jjg@309: return targets; jjg@309: } jjg@309: jjg@309: public static boolean isValidTargetTypeValue(int tag) { jjg@309: if (targets == null) jjg@309: targets = buildTargets(); jjg@309: jjg@309: if (((byte)tag) == ((byte)UNKNOWN.targetTypeValue)) jjg@309: return true; jjg@309: jjg@309: return (tag >= 0 && tag < targets.length); jjg@309: } jjg@309: jjg@309: public static TargetType fromTargetTypeValue(int tag) { jjg@309: if (targets == null) jjg@309: targets = buildTargets(); jjg@309: jjg@309: if (((byte)tag) == ((byte)UNKNOWN.targetTypeValue)) jjg@309: return UNKNOWN; jjg@309: jjg@309: if (tag < 0 || tag >= targets.length) jjg@309: throw new IllegalArgumentException("Unknown TargetType: " + tag); jjg@309: return targets[tag]; jjg@309: } jjg@309: } jjg@309: jjg@309: static enum TargetAttribute { jjg@309: HasLocation, HasParameter, HasBound; jjg@309: } jjg@309: }