src/share/classes/com/sun/tools/classfile/TypeAnnotation.java

Tue, 12 Feb 2013 17:15:29 -0800

author
jjg
date
Tue, 12 Feb 2013 17:15:29 -0800
changeset 1563
bc456436c613
parent 1521
71f35e4b93a5
child 1755
ddb4a2bfcd82
permissions
-rw-r--r--

8008077: update reference impl for type-annotations
Reviewed-by: jjg
Contributed-by: wmdietl@cs.washington.edu

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

mercurial