langtools/src/jdk.compiler/share/classes/com/sun/tools/classfile/TypeAnnotation.java
changeset 30846 2b3f379840f0
parent 30845 43ddd58a5a56
child 30847 9385b9c8506b
equal deleted inserted replaced
30845:43ddd58a5a56 30846:2b3f379840f0
     1 /*
       
     2  * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.classfile;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.util.ArrayList;
       
    30 import java.util.List;
       
    31 
       
    32 import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry;
       
    33 
       
    34 /**
       
    35  * See JSR 308 specification, Section 3.
       
    36  *
       
    37  *  <p><b>This is NOT part of any supported API.
       
    38  *  If you write code that depends on this, you do so at your own risk.
       
    39  *  This code and its internal interfaces are subject to change or
       
    40  *  deletion without notice.</b>
       
    41  */
       
    42 public class TypeAnnotation {
       
    43     TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
       
    44         constant_pool = cr.getConstantPool();
       
    45         position = read_position(cr);
       
    46         annotation = new Annotation(cr);
       
    47     }
       
    48 
       
    49     public TypeAnnotation(ConstantPool constant_pool,
       
    50             Annotation annotation, Position position) {
       
    51         this.constant_pool = constant_pool;
       
    52         this.position = position;
       
    53         this.annotation = annotation;
       
    54     }
       
    55 
       
    56     public int length() {
       
    57         int n = annotation.length();
       
    58         n += position_length(position);
       
    59         return n;
       
    60     }
       
    61 
       
    62     @Override
       
    63     public String toString() {
       
    64         try {
       
    65             return "@" + constant_pool.getUTF8Value(annotation.type_index).toString().substring(1) +
       
    66                     " pos: " + position.toString();
       
    67         } catch (Exception e) {
       
    68             e.printStackTrace();
       
    69             return e.toString();
       
    70         }
       
    71     }
       
    72 
       
    73     public final ConstantPool constant_pool;
       
    74     public final Position position;
       
    75     public final Annotation annotation;
       
    76 
       
    77     private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
       
    78         // Copied from ClassReader
       
    79         int tag = cr.readUnsignedByte(); // TargetType tag is a byte
       
    80         if (!TargetType.isValidTargetTypeValue(tag))
       
    81             throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag));
       
    82 
       
    83         TargetType type = TargetType.fromTargetTypeValue(tag);
       
    84 
       
    85         Position position = new Position();
       
    86         position.type = type;
       
    87 
       
    88         switch (type) {
       
    89         // instanceof
       
    90         case INSTANCEOF:
       
    91         // new expression
       
    92         case NEW:
       
    93         // constructor/method reference receiver
       
    94         case CONSTRUCTOR_REFERENCE:
       
    95         case METHOD_REFERENCE:
       
    96             position.offset = cr.readUnsignedShort();
       
    97             break;
       
    98         // local variable
       
    99         case LOCAL_VARIABLE:
       
   100         // resource variable
       
   101         case RESOURCE_VARIABLE:
       
   102             int table_length = cr.readUnsignedShort();
       
   103             position.lvarOffset = new int[table_length];
       
   104             position.lvarLength = new int[table_length];
       
   105             position.lvarIndex = new int[table_length];
       
   106             for (int i = 0; i < table_length; ++i) {
       
   107                 position.lvarOffset[i] = cr.readUnsignedShort();
       
   108                 position.lvarLength[i] = cr.readUnsignedShort();
       
   109                 position.lvarIndex[i] = cr.readUnsignedShort();
       
   110             }
       
   111             break;
       
   112         // exception parameter
       
   113         case EXCEPTION_PARAMETER:
       
   114             position.exception_index = cr.readUnsignedShort();
       
   115             break;
       
   116         // method receiver
       
   117         case METHOD_RECEIVER:
       
   118             // Do nothing
       
   119             break;
       
   120         // type parameter
       
   121         case CLASS_TYPE_PARAMETER:
       
   122         case METHOD_TYPE_PARAMETER:
       
   123             position.parameter_index = cr.readUnsignedByte();
       
   124             break;
       
   125         // type parameter bound
       
   126         case CLASS_TYPE_PARAMETER_BOUND:
       
   127         case METHOD_TYPE_PARAMETER_BOUND:
       
   128             position.parameter_index = cr.readUnsignedByte();
       
   129             position.bound_index = cr.readUnsignedByte();
       
   130             break;
       
   131         // class extends or implements clause
       
   132         case CLASS_EXTENDS:
       
   133             int in = cr.readUnsignedShort();
       
   134             if (in == 0xFFFF)
       
   135                 in = -1;
       
   136             position.type_index = in;
       
   137             break;
       
   138         // throws
       
   139         case THROWS:
       
   140             position.type_index = cr.readUnsignedShort();
       
   141             break;
       
   142         // method parameter
       
   143         case METHOD_FORMAL_PARAMETER:
       
   144             position.parameter_index = cr.readUnsignedByte();
       
   145             break;
       
   146         // type cast
       
   147         case CAST:
       
   148         // method/constructor/reference type argument
       
   149         case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
       
   150         case METHOD_INVOCATION_TYPE_ARGUMENT:
       
   151         case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
       
   152         case METHOD_REFERENCE_TYPE_ARGUMENT:
       
   153             position.offset = cr.readUnsignedShort();
       
   154             position.type_index = cr.readUnsignedByte();
       
   155             break;
       
   156         // We don't need to worry about these
       
   157         case METHOD_RETURN:
       
   158         case FIELD:
       
   159             break;
       
   160         case UNKNOWN:
       
   161             throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
       
   162         default:
       
   163             throw new AssertionError("TypeAnnotation: Unknown target type: " + type);
       
   164         }
       
   165 
       
   166         { // Write type path
       
   167             int len = cr.readUnsignedByte();
       
   168             List<Integer> loc = new ArrayList<>(len);
       
   169             for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i)
       
   170                 loc.add(cr.readUnsignedByte());
       
   171             position.location = Position.getTypePathFromBinary(loc);
       
   172         }
       
   173         return position;
       
   174     }
       
   175 
       
   176     private static int position_length(Position pos) {
       
   177         int n = 0;
       
   178         n += 1; // TargetType tag is a byte
       
   179         switch (pos.type) {
       
   180         // instanceof
       
   181         case INSTANCEOF:
       
   182         // new expression
       
   183         case NEW:
       
   184         // constructor/method reference receiver
       
   185         case CONSTRUCTOR_REFERENCE:
       
   186         case METHOD_REFERENCE:
       
   187             n += 2; // offset
       
   188             break;
       
   189         // local variable
       
   190         case LOCAL_VARIABLE:
       
   191         // resource variable
       
   192         case RESOURCE_VARIABLE:
       
   193             n += 2; // table_length;
       
   194             int table_length = pos.lvarOffset.length;
       
   195             n += 2 * table_length; // offset
       
   196             n += 2 * table_length; // length
       
   197             n += 2 * table_length; // index
       
   198             break;
       
   199         // exception parameter
       
   200         case EXCEPTION_PARAMETER:
       
   201             n += 2; // exception_index
       
   202             break;
       
   203         // method receiver
       
   204         case METHOD_RECEIVER:
       
   205             // Do nothing
       
   206             break;
       
   207         // type parameter
       
   208         case CLASS_TYPE_PARAMETER:
       
   209         case METHOD_TYPE_PARAMETER:
       
   210             n += 1; // parameter_index
       
   211             break;
       
   212         // type parameter bound
       
   213         case CLASS_TYPE_PARAMETER_BOUND:
       
   214         case METHOD_TYPE_PARAMETER_BOUND:
       
   215             n += 1; // parameter_index
       
   216             n += 1; // bound_index
       
   217             break;
       
   218         // class extends or implements clause
       
   219         case CLASS_EXTENDS:
       
   220             n += 2; // type_index
       
   221             break;
       
   222         // throws
       
   223         case THROWS:
       
   224             n += 2; // type_index
       
   225             break;
       
   226         // method parameter
       
   227         case METHOD_FORMAL_PARAMETER:
       
   228             n += 1; // parameter_index
       
   229             break;
       
   230         // type cast
       
   231         case CAST:
       
   232         // method/constructor/reference type argument
       
   233         case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
       
   234         case METHOD_INVOCATION_TYPE_ARGUMENT:
       
   235         case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
       
   236         case METHOD_REFERENCE_TYPE_ARGUMENT:
       
   237             n += 2; // offset
       
   238             n += 1; // type index
       
   239             break;
       
   240         // We don't need to worry about these
       
   241         case METHOD_RETURN:
       
   242         case FIELD:
       
   243             break;
       
   244         case UNKNOWN:
       
   245             throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
       
   246         default:
       
   247             throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type);
       
   248         }
       
   249 
       
   250         {
       
   251             n += 1; // length
       
   252             n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array
       
   253         }
       
   254 
       
   255         return n;
       
   256     }
       
   257 
       
   258     // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition
       
   259     public static class Position {
       
   260         public enum TypePathEntryKind {
       
   261             ARRAY(0),
       
   262             INNER_TYPE(1),
       
   263             WILDCARD(2),
       
   264             TYPE_ARGUMENT(3);
       
   265 
       
   266             public final int tag;
       
   267 
       
   268             private TypePathEntryKind(int tag) {
       
   269                 this.tag = tag;
       
   270             }
       
   271         }
       
   272 
       
   273         public static class TypePathEntry {
       
   274             /** The fixed number of bytes per TypePathEntry. */
       
   275             public static final int bytesPerEntry = 2;
       
   276 
       
   277             public final TypePathEntryKind tag;
       
   278             public final int arg;
       
   279 
       
   280             public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY);
       
   281             public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE);
       
   282             public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD);
       
   283 
       
   284             private TypePathEntry(TypePathEntryKind tag) {
       
   285                 if (!(tag == TypePathEntryKind.ARRAY ||
       
   286                         tag == TypePathEntryKind.INNER_TYPE ||
       
   287                         tag == TypePathEntryKind.WILDCARD)) {
       
   288                     throw new AssertionError("Invalid TypePathEntryKind: " + tag);
       
   289                 }
       
   290                 this.tag = tag;
       
   291                 this.arg = 0;
       
   292             }
       
   293 
       
   294             public TypePathEntry(TypePathEntryKind tag, int arg) {
       
   295                 if (tag != TypePathEntryKind.TYPE_ARGUMENT) {
       
   296                     throw new AssertionError("Invalid TypePathEntryKind: " + tag);
       
   297                 }
       
   298                 this.tag = tag;
       
   299                 this.arg = arg;
       
   300             }
       
   301 
       
   302             public static TypePathEntry fromBinary(int tag, int arg) {
       
   303                 if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) {
       
   304                     throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg);
       
   305                 }
       
   306                 switch (tag) {
       
   307                 case 0:
       
   308                     return ARRAY;
       
   309                 case 1:
       
   310                     return INNER_TYPE;
       
   311                 case 2:
       
   312                     return WILDCARD;
       
   313                 case 3:
       
   314                     return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg);
       
   315                 default:
       
   316                     throw new AssertionError("Invalid TypePathEntryKind tag: " + tag);
       
   317                 }
       
   318             }
       
   319 
       
   320             @Override
       
   321             public String toString() {
       
   322                 return tag.toString() +
       
   323                         (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
       
   324             }
       
   325 
       
   326             @Override
       
   327             public boolean equals(Object other) {
       
   328                 if (! (other instanceof TypePathEntry)) {
       
   329                     return false;
       
   330                 }
       
   331                 TypePathEntry tpe = (TypePathEntry) other;
       
   332                 return this.tag == tpe.tag && this.arg == tpe.arg;
       
   333             }
       
   334 
       
   335             @Override
       
   336             public int hashCode() {
       
   337                 return this.tag.hashCode() * 17 + this.arg;
       
   338             }
       
   339         }
       
   340 
       
   341         public TargetType type = TargetType.UNKNOWN;
       
   342 
       
   343         // For generic/array types.
       
   344         // TODO: or should we use null? Noone will use this object.
       
   345         public List<TypePathEntry> location = new ArrayList<>(0);
       
   346 
       
   347         // Tree position.
       
   348         public int pos = -1;
       
   349 
       
   350         // For typecasts, type tests, new (and locals, as start_pc).
       
   351         public boolean isValidOffset = false;
       
   352         public int offset = -1;
       
   353 
       
   354         // For locals. arrays same length
       
   355         public int[] lvarOffset = null;
       
   356         public int[] lvarLength = null;
       
   357         public int[] lvarIndex = null;
       
   358 
       
   359         // For type parameter bound
       
   360         public int bound_index = Integer.MIN_VALUE;
       
   361 
       
   362         // For type parameter and method parameter
       
   363         public int parameter_index = Integer.MIN_VALUE;
       
   364 
       
   365         // For class extends, implements, and throws clauses
       
   366         public int type_index = Integer.MIN_VALUE;
       
   367 
       
   368         // For exception parameters, index into exception table
       
   369         public int exception_index = Integer.MIN_VALUE;
       
   370 
       
   371         public Position() {}
       
   372 
       
   373         @Override
       
   374         public String toString() {
       
   375             StringBuilder sb = new StringBuilder();
       
   376             sb.append('[');
       
   377             sb.append(type);
       
   378 
       
   379             switch (type) {
       
   380             // instanceof
       
   381             case INSTANCEOF:
       
   382             // new expression
       
   383             case NEW:
       
   384             // constructor/method reference receiver
       
   385             case CONSTRUCTOR_REFERENCE:
       
   386             case METHOD_REFERENCE:
       
   387                 sb.append(", offset = ");
       
   388                 sb.append(offset);
       
   389                 break;
       
   390             // local variable
       
   391             case LOCAL_VARIABLE:
       
   392             // resource variable
       
   393             case RESOURCE_VARIABLE:
       
   394                 if (lvarOffset == null) {
       
   395                     sb.append(", lvarOffset is null!");
       
   396                     break;
       
   397                 }
       
   398                 sb.append(", {");
       
   399                 for (int i = 0; i < lvarOffset.length; ++i) {
       
   400                     if (i != 0) sb.append("; ");
       
   401                     sb.append("start_pc = ");
       
   402                     sb.append(lvarOffset[i]);
       
   403                     sb.append(", length = ");
       
   404                     sb.append(lvarLength[i]);
       
   405                     sb.append(", index = ");
       
   406                     sb.append(lvarIndex[i]);
       
   407                 }
       
   408                 sb.append("}");
       
   409                 break;
       
   410             // method receiver
       
   411             case METHOD_RECEIVER:
       
   412                 // Do nothing
       
   413                 break;
       
   414             // type parameter
       
   415             case CLASS_TYPE_PARAMETER:
       
   416             case METHOD_TYPE_PARAMETER:
       
   417                 sb.append(", param_index = ");
       
   418                 sb.append(parameter_index);
       
   419                 break;
       
   420             // type parameter bound
       
   421             case CLASS_TYPE_PARAMETER_BOUND:
       
   422             case METHOD_TYPE_PARAMETER_BOUND:
       
   423                 sb.append(", param_index = ");
       
   424                 sb.append(parameter_index);
       
   425                 sb.append(", bound_index = ");
       
   426                 sb.append(bound_index);
       
   427                 break;
       
   428             // class extends or implements clause
       
   429             case CLASS_EXTENDS:
       
   430                 sb.append(", type_index = ");
       
   431                 sb.append(type_index);
       
   432                 break;
       
   433             // throws
       
   434             case THROWS:
       
   435                 sb.append(", type_index = ");
       
   436                 sb.append(type_index);
       
   437                 break;
       
   438             // exception parameter
       
   439             case EXCEPTION_PARAMETER:
       
   440                 sb.append(", exception_index = ");
       
   441                 sb.append(exception_index);
       
   442                 break;
       
   443             // method parameter
       
   444             case METHOD_FORMAL_PARAMETER:
       
   445                 sb.append(", param_index = ");
       
   446                 sb.append(parameter_index);
       
   447                 break;
       
   448             // type cast
       
   449             case CAST:
       
   450             // method/constructor/reference type argument
       
   451             case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
       
   452             case METHOD_INVOCATION_TYPE_ARGUMENT:
       
   453             case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
       
   454             case METHOD_REFERENCE_TYPE_ARGUMENT:
       
   455                 sb.append(", offset = ");
       
   456                 sb.append(offset);
       
   457                 sb.append(", type_index = ");
       
   458                 sb.append(type_index);
       
   459                 break;
       
   460             // We don't need to worry about these
       
   461             case METHOD_RETURN:
       
   462             case FIELD:
       
   463                 break;
       
   464             case UNKNOWN:
       
   465                 sb.append(", position UNKNOWN!");
       
   466                 break;
       
   467             default:
       
   468                 throw new AssertionError("Unknown target type: " + type);
       
   469             }
       
   470 
       
   471             // Append location data for generics/arrays.
       
   472             if (!location.isEmpty()) {
       
   473                 sb.append(", location = (");
       
   474                 sb.append(location);
       
   475                 sb.append(")");
       
   476             }
       
   477 
       
   478             sb.append(", pos = ");
       
   479             sb.append(pos);
       
   480 
       
   481             sb.append(']');
       
   482             return sb.toString();
       
   483         }
       
   484 
       
   485         /**
       
   486          * Indicates whether the target tree of the annotation has been optimized
       
   487          * away from classfile or not.
       
   488          * @return true if the target has not been optimized away
       
   489          */
       
   490         public boolean emitToClassfile() {
       
   491             return !type.isLocal() || isValidOffset;
       
   492         }
       
   493 
       
   494         /**
       
   495          * Decode the binary representation for a type path and set
       
   496          * the {@code location} field.
       
   497          *
       
   498          * @param list The bytecode representation of the type path.
       
   499          */
       
   500         public static List<TypePathEntry> getTypePathFromBinary(List<Integer> list) {
       
   501             List<TypePathEntry> loc = new ArrayList<>(list.size() / TypePathEntry.bytesPerEntry);
       
   502             int idx = 0;
       
   503             while (idx < list.size()) {
       
   504                 if (idx + 1 == list.size()) {
       
   505                     throw new AssertionError("Could not decode type path: " + list);
       
   506                 }
       
   507                 loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1)));
       
   508                 idx += 2;
       
   509             }
       
   510             return loc;
       
   511         }
       
   512 
       
   513         public static List<Integer> getBinaryFromTypePath(List<TypePathEntry> locs) {
       
   514             List<Integer> loc = new ArrayList<>(locs.size() * TypePathEntry.bytesPerEntry);
       
   515             for (TypePathEntry tpe : locs) {
       
   516                 loc.add(tpe.tag.tag);
       
   517                 loc.add(tpe.arg);
       
   518             }
       
   519             return loc;
       
   520         }
       
   521     }
       
   522 
       
   523     // Code duplicated from com.sun.tools.javac.code.TargetType
       
   524     // The IsLocal flag could be removed here.
       
   525     public enum TargetType {
       
   526         /** For annotations on a class type parameter declaration. */
       
   527         CLASS_TYPE_PARAMETER(0x00),
       
   528 
       
   529         /** For annotations on a method type parameter declaration. */
       
   530         METHOD_TYPE_PARAMETER(0x01),
       
   531 
       
   532         /** For annotations on the type of an "extends" or "implements" clause. */
       
   533         CLASS_EXTENDS(0x10),
       
   534 
       
   535         /** For annotations on a bound of a type parameter of a class. */
       
   536         CLASS_TYPE_PARAMETER_BOUND(0x11),
       
   537 
       
   538         /** For annotations on a bound of a type parameter of a method. */
       
   539         METHOD_TYPE_PARAMETER_BOUND(0x12),
       
   540 
       
   541         /** For annotations on a field. */
       
   542         FIELD(0x13),
       
   543 
       
   544         /** For annotations on a method return type. */
       
   545         METHOD_RETURN(0x14),
       
   546 
       
   547         /** For annotations on the method receiver. */
       
   548         METHOD_RECEIVER(0x15),
       
   549 
       
   550         /** For annotations on a method parameter. */
       
   551         METHOD_FORMAL_PARAMETER(0x16),
       
   552 
       
   553         /** For annotations on a throws clause in a method declaration. */
       
   554         THROWS(0x17),
       
   555 
       
   556         /** For annotations on a local variable. */
       
   557         LOCAL_VARIABLE(0x40, true),
       
   558 
       
   559         /** For annotations on a resource variable. */
       
   560         RESOURCE_VARIABLE(0x41, true),
       
   561 
       
   562         /** For annotations on an exception parameter. */
       
   563         EXCEPTION_PARAMETER(0x42, true),
       
   564 
       
   565         /** For annotations on a type test. */
       
   566         INSTANCEOF(0x43, true),
       
   567 
       
   568         /** For annotations on an object creation expression. */
       
   569         NEW(0x44, true),
       
   570 
       
   571         /** For annotations on a constructor reference receiver. */
       
   572         CONSTRUCTOR_REFERENCE(0x45, true),
       
   573 
       
   574         /** For annotations on a method reference receiver. */
       
   575         METHOD_REFERENCE(0x46, true),
       
   576 
       
   577         /** For annotations on a typecast. */
       
   578         CAST(0x47, true),
       
   579 
       
   580         /** For annotations on a type argument of an object creation expression. */
       
   581         CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true),
       
   582 
       
   583         /** For annotations on a type argument of a method call. */
       
   584         METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true),
       
   585 
       
   586         /** For annotations on a type argument of a constructor reference. */
       
   587         CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true),
       
   588 
       
   589         /** For annotations on a type argument of a method reference. */
       
   590         METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true),
       
   591 
       
   592         /** For annotations with an unknown target. */
       
   593         UNKNOWN(0xFF);
       
   594 
       
   595         private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B;
       
   596 
       
   597         private final int targetTypeValue;
       
   598         private final boolean isLocal;
       
   599 
       
   600         private TargetType(int targetTypeValue) {
       
   601             this(targetTypeValue, false);
       
   602         }
       
   603 
       
   604         private TargetType(int targetTypeValue, boolean isLocal) {
       
   605             if (targetTypeValue < 0
       
   606                     || targetTypeValue > 255)
       
   607                     throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue));
       
   608             this.targetTypeValue = targetTypeValue;
       
   609             this.isLocal = isLocal;
       
   610         }
       
   611 
       
   612         /**
       
   613          * Returns whether or not this TargetType represents an annotation whose
       
   614          * target is exclusively a tree in a method body
       
   615          *
       
   616          * Note: wildcard bound targets could target a local tree and a class
       
   617          * member declaration signature tree
       
   618          */
       
   619         public boolean isLocal() {
       
   620             return isLocal;
       
   621         }
       
   622 
       
   623         public int targetTypeValue() {
       
   624             return this.targetTypeValue;
       
   625         }
       
   626 
       
   627         private static final TargetType[] targets;
       
   628 
       
   629         static {
       
   630             targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1];
       
   631             TargetType[] alltargets = values();
       
   632             for (TargetType target : alltargets) {
       
   633                 if (target.targetTypeValue != UNKNOWN.targetTypeValue)
       
   634                     targets[target.targetTypeValue] = target;
       
   635             }
       
   636             for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) {
       
   637                 if (targets[i] == null)
       
   638                     targets[i] = UNKNOWN;
       
   639             }
       
   640         }
       
   641 
       
   642         public static boolean isValidTargetTypeValue(int tag) {
       
   643             if (tag == UNKNOWN.targetTypeValue)
       
   644                 return true;
       
   645             return (tag >= 0 && tag < targets.length);
       
   646         }
       
   647 
       
   648         public static TargetType fromTargetTypeValue(int tag) {
       
   649             if (tag == UNKNOWN.targetTypeValue)
       
   650                 return UNKNOWN;
       
   651 
       
   652             if (tag < 0 || tag >= targets.length)
       
   653                 throw new AssertionError("Unknown TargetType: " + tag);
       
   654             return targets[tag];
       
   655         }
       
   656     }
       
   657 }