jjg@309: /* jjg@1521: * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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 ohair@554: * published by the Free Software Foundation. Oracle designates this jjg@309: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle 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: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. jjg@309: */ jjg@309: jjg@309: package com.sun.tools.javac.code; jjg@309: jjg@1521: import java.util.Iterator; jjg@1521: jjg@309: import com.sun.tools.javac.util.*; jjg@309: jjg@309: /** A type annotation position. jjg@309: * jjg@581: *

This is NOT part of any supported API. jjg@581: * If 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@1521: // Code duplicated in com.sun.tools.classfile.TypeAnnotation.Position jjg@309: public class TypeAnnotationPosition { jjg@309: jjg@1521: public enum TypePathEntryKind { jjg@1521: ARRAY(0), jjg@1521: INNER_TYPE(1), jjg@1521: WILDCARD(2), jjg@1521: TYPE_ARGUMENT(3); jjg@1521: jjg@1521: public final int tag; jjg@1521: jjg@1521: private TypePathEntryKind(int tag) { jjg@1521: this.tag = tag; jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: public static class TypePathEntry { jjg@1521: /** The fixed number of bytes per TypePathEntry. */ jjg@1521: public static final int bytesPerEntry = 2; jjg@1521: jjg@1521: public final TypePathEntryKind tag; jjg@1521: public final int arg; jjg@1521: jjg@1521: public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY); jjg@1521: public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE); jjg@1521: public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD); jjg@1521: jjg@1521: private TypePathEntry(TypePathEntryKind tag) { jjg@1521: Assert.check(tag == TypePathEntryKind.ARRAY || jjg@1521: tag == TypePathEntryKind.INNER_TYPE || jjg@1521: tag == TypePathEntryKind.WILDCARD, jjg@1521: "Invalid TypePathEntryKind: " + tag); jjg@1521: this.tag = tag; jjg@1521: this.arg = 0; jjg@1521: } jjg@1521: jjg@1521: public TypePathEntry(TypePathEntryKind tag, int arg) { jjg@1521: Assert.check(tag == TypePathEntryKind.TYPE_ARGUMENT, jjg@1521: "Invalid TypePathEntryKind: " + tag); jjg@1521: this.tag = tag; jjg@1521: this.arg = arg; jjg@1521: } jjg@1521: jjg@1521: public static TypePathEntry fromBinary(int tag, int arg) { jjg@1521: Assert.check(arg == 0 || tag == TypePathEntryKind.TYPE_ARGUMENT.tag, jjg@1521: "Invalid TypePathEntry tag/arg: " + tag + "/" + arg); jjg@1521: switch (tag) { jjg@1521: case 0: jjg@1521: return ARRAY; jjg@1521: case 1: jjg@1521: return INNER_TYPE; jjg@1521: case 2: jjg@1521: return WILDCARD; jjg@1521: case 3: jjg@1521: return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg); jjg@1521: default: jjg@1521: Assert.error("Invalid TypePathEntryKind tag: " + tag); jjg@1521: return null; jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public String toString() { jjg@1521: return tag.toString() + jjg@1521: (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : ""); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public boolean equals(Object other) { jjg@1521: if (! (other instanceof TypePathEntry)) { jjg@1521: return false; jjg@1521: } jjg@1521: TypePathEntry tpe = (TypePathEntry) other; jjg@1521: return this.tag == tpe.tag && this.arg == tpe.arg; jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public int hashCode() { jjg@1521: return this.tag.hashCode() * 17 + this.arg; jjg@1521: } jjg@1521: } jjg@1521: jjg@309: public TargetType type = TargetType.UNKNOWN; jjg@309: jjg@309: // For generic/array types. jjg@1521: public List location = List.nil(); 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@310: public boolean isValidOffset = false; jjg@309: public int offset = -1; jjg@309: jjg@309: // For locals. arrays same length jjg@478: public int[] lvarOffset = null; jjg@478: public int[] lvarLength = null; jjg@478: public int[] lvarIndex = null; jjg@309: jjg@309: // For type parameter bound jjg@478: public int bound_index = Integer.MIN_VALUE; jjg@309: jjg@309: // For type parameter and method parameter jjg@478: public int parameter_index = Integer.MIN_VALUE; jjg@309: jjg@1521: // For class extends, implements, and throws clauses jjg@478: public int type_index = Integer.MIN_VALUE; jjg@309: jjg@1521: // For exception parameters, index into exception table jjg@1521: public int exception_index = Integer.MIN_VALUE; jjg@1521: jjg@1521: public TypeAnnotationPosition() {} 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@1521: // type cast jjg@1521: case CAST: jjg@1521: // instanceof jjg@309: case INSTANCEOF: jjg@1521: // new expression jjg@309: case NEW: jjg@309: sb.append(", offset = "); jjg@309: sb.append(offset); jjg@309: break; jjg@1521: // local variable jjg@309: case LOCAL_VARIABLE: jjg@1521: // resource variable jjg@1521: case RESOURCE_VARIABLE: jjg@1521: if (lvarOffset == null) { jjg@1521: sb.append(", lvarOffset is null!"); jjg@1521: break; jjg@1521: } jjg@309: sb.append(", {"); jjg@309: for (int i = 0; i < lvarOffset.length; ++i) { jjg@309: if (i != 0) sb.append("; "); jjg@1521: 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@1521: // method receiver jjg@309: case METHOD_RECEIVER: jjg@309: // Do nothing jjg@309: break; jjg@1521: // type parameter 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@1521: // type parameter bound jjg@309: case CLASS_TYPE_PARAMETER_BOUND: jjg@309: case METHOD_TYPE_PARAMETER_BOUND: 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@1521: // class extends or implements clause jjg@309: case CLASS_EXTENDS: jjg@309: sb.append(", type_index = "); jjg@309: sb.append(type_index); jjg@309: break; jjg@1521: // throws jjg@309: case THROWS: jjg@309: sb.append(", type_index = "); jjg@309: sb.append(type_index); jjg@309: break; jjg@1521: // exception parameter jjg@1521: case EXCEPTION_PARAMETER: jjg@1521: sb.append(", exception_index = "); jjg@1521: sb.append(exception_index); jjg@309: break; jjg@1521: // method parameter jjg@1521: case METHOD_FORMAL_PARAMETER: jjg@309: sb.append(", param_index = "); jjg@309: sb.append(parameter_index); jjg@309: break; jjg@1521: // method/constructor/reference type argument jjg@1521: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: jjg@1521: case METHOD_INVOCATION_TYPE_ARGUMENT: jjg@1521: case METHOD_REFERENCE_TYPE_ARGUMENT: 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@1521: // We don't need to worry about these jjg@1521: case METHOD_RETURN: jjg@1521: case FIELD: jjg@1521: break; jjg@1521: // lambda formal parameter jjg@1521: case LAMBDA_FORMAL_PARAMETER: jjg@1521: // TODO: also needs an offset? jjg@1521: sb.append(", param_index = "); jjg@1521: sb.append(parameter_index); jjg@309: break; jjg@309: case UNKNOWN: jjg@1521: sb.append(", position UNKNOWN!"); jjg@309: break; jjg@309: default: jjg@1521: Assert.error("Unknown target type: " + type); jjg@309: } jjg@309: jjg@309: // Append location data for generics/arrays. jjg@1521: if (!location.isEmpty()) { 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@310: jjg@310: /** jjg@310: * Indicates whether the target tree of the annotation has been optimized jjg@310: * away from classfile or not. jjg@310: * @return true if the target has not been optimized away jjg@310: */ jjg@310: public boolean emitToClassfile() { jjg@1521: return !type.isLocal() || isValidOffset; jjg@1521: } jjg@1521: jjg@1521: /** jjg@1521: * Decode the binary representation for a type path and set jjg@1521: * the {@code location} field. jjg@1521: * jjg@1521: * @param list The bytecode representation of the type path. jjg@1521: */ jjg@1521: public static List getTypePathFromBinary(java.util.List list) { jjg@1521: ListBuffer loc = ListBuffer.lb(); jjg@1521: Iterator iter = list.iterator(); jjg@1521: while (iter.hasNext()) { jjg@1521: Integer fst = iter.next(); jjg@1521: Assert.check(iter.hasNext(), "Could not decode type path: " + list); jjg@1521: Integer snd = iter.next(); jjg@1521: loc = loc.append(TypePathEntry.fromBinary(fst, snd)); jjg@1521: } jjg@1521: return loc.toList(); jjg@1521: } jjg@1521: jjg@1521: public static List getBinaryFromTypePath(java.util.List locs) { jjg@1521: ListBuffer loc = ListBuffer.lb(); jjg@1521: for (TypePathEntry tpe : locs) { jjg@1521: loc = loc.append(tpe.tag.tag); jjg@1521: loc = loc.append(tpe.arg); jjg@1521: } jjg@1521: return loc.toList(); jjg@310: } jjg@309: }