blob: 45e5928a3ec53e126463ac6ccdb7f6ac08990348 [file] [log] [blame]
/* *******************************************************************
* Copyright (c) 2013 VMware
*
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andy Clement initial implementation
* ******************************************************************/
package org.aspectj.apache.bcel.classfile.annotation;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.aspectj.apache.bcel.classfile.ConstantPool;
public class TypeAnnotationGen {
public static final TypeAnnotationGen[] NO_TYPE_ANNOTATIONS = new TypeAnnotationGen[0];
public static final int[] NO_TYPE_PATH = new int[0];
private ConstantPool cpool;
private TypeAnnotationGen(ConstantPool cpool) {
this.cpool = cpool;
}
private int targetType;
private int[] typePath;
private AnnotationGen annotation;
private int info; // meaning varies depending on target type
private int info2; // meaning varies depending on target type
private int[] localVarTarget;
// target type constants
public final static int CLASS_TYPE_PARAMETER = 0x00;
public final static int METHOD_TYPE_PARAMETER = 0x01;
public final static int CLASS_EXTENDS = 0x10;
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
public final static int FIELD = 0x13;
public final static int METHOD_RETURN = 0x14;
public final static int METHOD_RECEIVER = 0x15;
public final static int METHOD_FORMAL_PARAMETER = 0x16;
public final static int THROWS = 0x17;
public final static int LOCAL_VARIABLE = 0x40;
public final static int RESOURCE_VARIABLE = 0x41;
public final static int EXCEPTION_PARAMETER = 0x42;
public final static int INSTANCEOF = 0x43;
public final static int NEW = 0x44;
public final static int CONSTRUCTOR_REFERENCE = 0x45;
public final static int METHOD_REFERENCE = 0x46;
public final static int CAST = 0x47;
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
// type path entry kinds
public final static int TYPE_PATH_ENTRY_KIND_ARRAY = 0;
public final static int TYPE_PATH_ENTRY_KIND_INNER_TYPE = 1;
public final static int TYPE_PATH_ENTRY_KIND_WILDCARD = 2;
public final static int TYPE_PATH_ENTRY_KIND_TYPE_ARGUMENT = 3;
public static TypeAnnotationGen read(DataInputStream dis, ConstantPool cpool, boolean isVisible) throws IOException {
TypeAnnotationGen typeAnno = new TypeAnnotationGen(cpool);
typeAnno.targetType = dis.readUnsignedByte();
// read target_info
switch (typeAnno.targetType) {
case CLASS_TYPE_PARAMETER:
typeAnno.info = dis.readUnsignedByte();// type_parameter_index
break;
case METHOD_TYPE_PARAMETER:
typeAnno.info = dis.readUnsignedByte(); // type_parameter_index
break;
case CLASS_EXTENDS:
int superTypeIndex = dis.readUnsignedShort();
if (superTypeIndex == 65535) {
typeAnno.info = -1;
} else {
typeAnno.info = superTypeIndex;
}
break;
case CLASS_TYPE_PARAMETER_BOUND:
case METHOD_TYPE_PARAMETER_BOUND:
typeAnno.info = dis.readUnsignedByte(); // type_parameter_index
typeAnno.info2 = dis.readUnsignedByte(); // bound_index;
break;
case FIELD:
case METHOD_RETURN:
case METHOD_RECEIVER:
break;
case METHOD_FORMAL_PARAMETER:
typeAnno.info = dis.readUnsignedByte(); // method_formal_parameter_index
break;
case THROWS:
typeAnno.info = dis.readUnsignedShort(); // throws_type_index
break;
case LOCAL_VARIABLE:
case RESOURCE_VARIABLE:
typeAnno.localVarTarget = readLocalVarTarget(dis);
break;
case EXCEPTION_PARAMETER:
// TODO should be a SHORT according to the spec but byte for now because of javac (b90)
typeAnno.info = dis.readUnsignedByte(); // exception_table_index
break;
case INSTANCEOF:
case NEW:
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
typeAnno.info = dis.readUnsignedShort(); // offset
break;
case CAST:
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT:
typeAnno.info = dis.readUnsignedShort(); // offset
typeAnno.info2 = dis.readUnsignedByte(); // type_argument_index
break;
default:
throw new IllegalStateException("nyi "+typeAnno.targetType);
}
int typepathlength = dis.readUnsignedByte();
if (typepathlength==0) {
typeAnno.typePath = NO_TYPE_PATH;
} else {
typeAnno.typePath = new int[typepathlength*2];
for (int i=0, max = typepathlength*2; i<max; i++) {
typeAnno.typePath[i] = dis.readUnsignedByte();
}
}
typeAnno.annotation = AnnotationGen.read(dis, cpool, isVisible);
return typeAnno;
}
public static int[] readLocalVarTarget(DataInputStream dis) throws IOException {
int tableLength = dis.readUnsignedShort();
int[] table = new int[tableLength*3];
int count = 0;
for (int i=0;i<tableLength;i++) {
table[count++]=dis.readUnsignedShort(); // start_pc
table[count++]=dis.readUnsignedShort(); // length
table[count++]=dis.readUnsignedShort(); // index
}
return table;
}
public void dump(DataOutputStream dos) throws IOException {
dos.writeByte(targetType);
switch (targetType) {
case CLASS_TYPE_PARAMETER:
dos.writeByte(this.info); // type_parameter_index
break;
case METHOD_TYPE_PARAMETER:
dos.writeByte(info); // type_parameter_index
break;
case CLASS_EXTENDS:
dos.writeShort(info); // supertype_index
break;
case CLASS_TYPE_PARAMETER_BOUND:
case METHOD_TYPE_PARAMETER_BOUND:
dos.writeByte(info); // type_parameter_index
dos.writeByte(info2); // bound_index;
break;
case FIELD:
case METHOD_RETURN:
case METHOD_RECEIVER:
break;
case METHOD_FORMAL_PARAMETER:
dos.writeByte(info); // method_formal_parameter_index
break;
case THROWS:
dos.writeShort(info); // throws_type_index
break;
case LOCAL_VARIABLE:
case RESOURCE_VARIABLE:
dos.writeShort(localVarTarget.length/3);
for (int i=0;i<localVarTarget.length;i++) {
dos.writeShort(localVarTarget[i]);
}
break;
case EXCEPTION_PARAMETER:
// TODO should be a SHORT according to the spec but byte for now because of javac (b90)
dos.writeByte(info); // exception_table_index
break;
case INSTANCEOF:
case NEW:
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
dos.writeShort(info); // offset
break;
case CAST:
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT:
dos.writeShort(info); // offset
dos.writeByte(info); // type_argument_index
break;
default:
throw new IllegalStateException("nyi "+targetType);
}
dos.writeByte(typePath.length);
for (int i=0;i<typePath.length;i++) {
dos.writeByte(typePath[i]);
}
annotation.dump(dos);
}
public int getSupertypeIndex() {
assert (targetType==CLASS_EXTENDS);
return info;
}
public int getOffset() {
assert (targetType==INSTANCEOF || targetType==NEW || targetType==CONSTRUCTOR_REFERENCE || targetType==METHOD_REFERENCE ||
targetType==CAST || targetType==CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ||
targetType==METHOD_INVOCATION_TYPE_ARGUMENT || targetType==CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ||
targetType==METHOD_REFERENCE_TYPE_ARGUMENT);
return info;
}
public int getTypeParameterIndex() {
assert (targetType==CLASS_TYPE_PARAMETER || targetType==METHOD_TYPE_PARAMETER ||
targetType==CLASS_TYPE_PARAMETER_BOUND || targetType==METHOD_TYPE_PARAMETER_BOUND);
return info;
}
public int getTypeArgumentIndex() {
assert (targetType==CAST || targetType==CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ||
targetType==METHOD_INVOCATION_TYPE_ARGUMENT || targetType==CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT || targetType==METHOD_REFERENCE_TYPE_ARGUMENT);
return info2;
}
public int getBoundIndex() {
assert (targetType==CLASS_TYPE_PARAMETER_BOUND || targetType==METHOD_TYPE_PARAMETER_BOUND);
return info2;
}
public int getMethodFormalParameterIndex() {
assert (targetType==METHOD_FORMAL_PARAMETER);
return info;
}
public int getThrowsTypeIndex() {
assert (targetType==THROWS);
return info;
}
public int[] getLocalVarTarget() {
assert (targetType==LOCAL_VARIABLE||targetType==RESOURCE_VARIABLE);
return localVarTarget;
}
public int getExceptionTableIndex() {
assert (targetType==EXCEPTION_PARAMETER);
return info;
}
public int getTargetType() {
return targetType;
}
public AnnotationGen getAnnotation() {
return annotation;
}
// @Override
// public String toString() {
// StringBuffer s = new StringBuffer();
// s.append("AnnotationGen:[" + getTypeName() + " #" + pairs.size() + " {");
// for (int i = 0; i < pairs.size(); i++) {
// s.append(pairs.get(i));
// if (i + 1 < pairs.size())
// s.append(",");
// }
// s.append("}]");
// return s.toString();
// }
//
// public String toShortString() {
// StringBuffer s = new StringBuffer();
// s.append("@" + getTypeName() + "(");
// for (int i = 0; i < pairs.size(); i++) {
// s.append(pairs.get(i));
// if (i + 1 < pairs.size())
// s.append(",");
// }
// s.append(")");
// return s.toString();
// }
//
// private void isRuntimeVisible(boolean b) {
// isRuntimeVisible = b;
// }
//
// public boolean isRuntimeVisible() {
// return isRuntimeVisible;
// }
//
// /**
// * @return true if the annotation has a value with the specified name and (toString'd) value
// */
// public boolean hasNameValuePair(String name, String value) {
// for (NameValuePair pair : pairs) {
// if (pair.getNameString().equals(name)) {
// if (pair.getValue().stringifyValue().equals(value)) {
// return true;
// }
// }
// }
// return false;
// }
//
// /**
// * @return true if the annotation has a value with the specified name
// */
// public boolean hasNamedValue(String name) {
// for (NameValuePair pair : pairs) {
// if (pair.getNameString().equals(name)) {
// return true;
// }
// }
// return false;
// }
// public TypeAnnotationGen(TypeAnnotationGen a, ConstantPool cpool, boolean copyPoolEntries) {
// this.cpool = cpool;
// if (copyPoolEntries) {
// typeIndex = cpool.addUtf8(a.getTypeSignature());
// } else {
// typeIndex = a.getTypeIndex();
// }
// isRuntimeVisible = a.isRuntimeVisible();
// pairs = copyValues(a.getValues(), cpool, copyPoolEntries);
// }
//
// private List<NameValuePair> copyValues(List<NameValuePair> in, ConstantPool cpool, boolean copyPoolEntries) {
// List<NameValuePair> out = new ArrayList<NameValuePair>();
// for (NameValuePair nvp : in) {
// out.add(new NameValuePair(nvp, cpool, copyPoolEntries));
// }
// return out;
// }
//
//
// /**
// * Retrieve an immutable version of this AnnotationGen
// */
// public TypeAnnotationGen(ObjectType type, List<NameValuePair> pairs, boolean runtimeVisible, ConstantPool cpool) {
// this.cpool = cpool;
// if (type != null) {
// this.typeIndex = cpool.addUtf8(type.getSignature()); // Only null for funky *temporary* FakeAnnotation objects
// }
// this.pairs = pairs;
// isRuntimeVisible = runtimeVisible;
// }
//
public int[] getTypePath() {
return typePath;
}
public String getTypePathString() {
return toTypePathString(typePath);
}
public static String toTypePathString(int[] typepath) {
StringBuilder sb = new StringBuilder();
int count = 0;
sb.append("[");
while (count < typepath.length) {
if (count>0) sb.append(",");
switch (typepath[count++]) {
case TYPE_PATH_ENTRY_KIND_ARRAY:
sb.append("ARRAY");
count++;
break;
case TYPE_PATH_ENTRY_KIND_INNER_TYPE:
sb.append("INNER_TYPE");
count++;
break;
case TYPE_PATH_ENTRY_KIND_WILDCARD:
sb.append("WILDCARD");
count++;
break;
case TYPE_PATH_ENTRY_KIND_TYPE_ARGUMENT:
sb.append("TYPE_ARGUMENT(").append(typepath[count++]).append(")");
break;
}
}
sb.append("]");
return sb.toString();
}
}