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 }