blob: 85e80f0b06e399d6510f950e70836a2f62372b6c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2013 IBM Corporation and others.
* 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
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
* Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator
* Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation
*******************************************************************************/
package org.eclipse.jdt.internal.core.util;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.core.util.IAnnotationComponent;
import org.eclipse.jdt.core.util.IConstantPool;
import org.eclipse.jdt.core.util.IConstantPoolConstant;
import org.eclipse.jdt.core.util.IConstantPoolEntry;
import org.eclipse.jdt.core.util.IExtendedAnnotation;
import org.eclipse.jdt.core.util.IExtendedAnnotationConstants;
import org.eclipse.jdt.core.util.ILocalVariableReferenceInfo;
/* http://types.cs.washington.edu/jsr308/specification/java-annotation-design.pdf
type_annotation {
// New fields in JSR 308:
u1 target_type; // the type of the targeted program element, see Section 3.2
union {
type_parameter_target;
supertype_target;
type_parameter_bound_target;
empty_target;
method_formal_parameter_target;
throws_target;
localvar_target;
catch_target;
offset_target;
type_argument_target;
method_reference_target;
} target_info; // identifies the targeted program element, see Section 3.3
type_path target_path; // identifies targeted type in a compound type (array, generic, etc.), see Section 3.4
// Original fields from "annotation" structure:
u2 type_index;
u2 num_element_value_pairs;
{
u2 element_name_index;
element_value value;
} element_value_pairs[num_element_value_pairs];
*/
/**
* @since 3.9 BETA_JAVA8
*/
public class ExtendedAnnotation extends ClassFileStruct implements IExtendedAnnotation {
private static final IAnnotationComponent[] NO_ENTRIES = new IAnnotationComponent[0];
private final static int[][] NO_TYPEPATH = new int[0][0];
private final static ILocalVariableReferenceInfo[] NO_LOCAL_VARIABLE_TABLE_ENTRIES = new ILocalVariableReferenceInfo[0];
private int targetType;
private int annotationTypeIndex;
private int[][] typePath;
private int typeIndex;
private char[] typeName;
private int componentsNumber;
private IAnnotationComponent[] components;
private int readOffset;
private int offset;
private int typeParameterIndex;
private int typeParameterBoundIndex;
private int parameterIndex;
private int exceptionTableIndex;
private ILocalVariableReferenceInfo[] localVariableTable = NO_LOCAL_VARIABLE_TABLE_ENTRIES;
/**
* Constructor for ExtendedAnnotation, builds an annotation from the supplied bytestream.
*
* @param classFileBytes
* @param constantPool
* @param offset
* @throws ClassFormatException
*/
public ExtendedAnnotation(
byte[] classFileBytes,
IConstantPool constantPool,
int offset) throws ClassFormatException {
// Read target_type
int index = u1At(classFileBytes,0,offset);
this.targetType = index;
this.readOffset = 1;
readTargetInfo(index, classFileBytes, constantPool, offset);
// Read type_path
index = u1At(classFileBytes, this.readOffset, offset);
this.readOffset++;
int typePathEntryCount = index;
if (typePathEntryCount == 0) {
this.typePath = NO_TYPEPATH;
} else {
this.typePath = new int[typePathEntryCount][];
for (int i = 0; i < typePathEntryCount; i++) {
int[] typePathEntry = (this.typePath[i] = new int[2]);
typePathEntry[0] = u1At(classFileBytes, this.readOffset++, offset);
typePathEntry[1] = u1At(classFileBytes, this.readOffset++, offset);
}
}
// Read annotation
index = u2At(classFileBytes, this.readOffset, offset);
this.typeIndex = index;
this.readOffset+=2;
if (index != 0) {
IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(index);
if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_Utf8) {
throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
}
this.typeName = constantPoolEntry.getUtf8Value();
} else {
throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
}
final int length = u2At(classFileBytes, this.readOffset, offset);
this.componentsNumber = length;
this.readOffset+=2;
if (length != 0) {
this.components = new IAnnotationComponent[length];
for (int i = 0; i < length; i++) {
AnnotationComponent component = new AnnotationComponent(classFileBytes, constantPool, offset + this.readOffset);
this.components[i] = component;
this.readOffset += component.sizeInBytes();
}
} else {
this.components = NO_ENTRIES;
}
if (this.annotationTypeIndex == 0xFFFF) {
this.annotationTypeIndex = -1;
}
}
private void readTargetInfo(
int localTargetType,
byte[] classFileBytes,
IConstantPool constantPool,
int localOffset) throws ClassFormatException {
switch(localTargetType) {
case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER :
case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER :
this.typeParameterIndex = u1At(classFileBytes, this.readOffset, localOffset);
this.readOffset++;
break;
case IExtendedAnnotationConstants.CLASS_EXTENDS :
this.annotationTypeIndex = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset+=2;
break;
case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER_BOUND :
case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER_BOUND :
this.typeParameterIndex = u1At(classFileBytes, this.readOffset, localOffset);
this.readOffset++;
this.typeParameterBoundIndex = u1At(classFileBytes, this.readOffset, localOffset);
this.readOffset++;
break;
case IExtendedAnnotationConstants.FIELD :
case IExtendedAnnotationConstants.METHOD_RETURN :
case IExtendedAnnotationConstants.METHOD_RECEIVER :
// nothing to do, target_info is empty_target
break;
case IExtendedAnnotationConstants.METHOD_FORMAL_PARAMETER :
this.parameterIndex = u1At(classFileBytes, this.readOffset, localOffset);
this.readOffset++;
break;
case IExtendedAnnotationConstants.THROWS :
this.annotationTypeIndex = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset+=2;
break;
case IExtendedAnnotationConstants.LOCAL_VARIABLE :
case IExtendedAnnotationConstants.RESOURCE_VARIABLE :
int tableLength = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset += 2;
this.localVariableTable = new LocalVariableReferenceInfo[tableLength];
for (int i = 0; i < tableLength; i++) {
this.localVariableTable[i] = new LocalVariableReferenceInfo(classFileBytes, constantPool, this.readOffset + localOffset);
this.readOffset += 6;
}
break;
case IExtendedAnnotationConstants.EXCEPTION_PARAMETER :
this.exceptionTableIndex = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset += 2;
break;
case IExtendedAnnotationConstants.NEW :
case IExtendedAnnotationConstants.INSTANCEOF :
case IExtendedAnnotationConstants.METHOD_REFERENCE :
case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE :
this.offset = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset += 2;
break;
case IExtendedAnnotationConstants.CAST :
this.offset = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset += 2;
// read type_argument_index
this.annotationTypeIndex = u1At(classFileBytes, this.readOffset, localOffset);
this.readOffset++;
break;
case IExtendedAnnotationConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT :
case IExtendedAnnotationConstants.METHOD_INVOCATION_TYPE_ARGUMENT :
case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT :
case IExtendedAnnotationConstants.METHOD_REFERENCE_TYPE_ARGUMENT :
this.offset = u2At(classFileBytes, this.readOffset, localOffset);
this.readOffset += 2;
// read type_argument_index
this.annotationTypeIndex = u1At(classFileBytes, this.readOffset, localOffset);
this.readOffset++;
break;
}
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.util.IAnnotation#getTypeIndex()
*/
public int getTypeIndex() {
return this.typeIndex;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.util.IAnnotation#getComponentsNumber()
*/
public int getComponentsNumber() {
return this.componentsNumber;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.util.IAnnotation#getComponents()
*/
public IAnnotationComponent[] getComponents() {
return this.components;
}
int sizeInBytes() {
return this.readOffset;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.util.IAnnotation#getTypeName()
*/
public char[] getTypeName() {
return this.typeName;
}
public int getTargetType() {
return this.targetType;
}
public int getExceptionTableIndex() {
return this.exceptionTableIndex;
}
public int getOffset() {
return this.offset;
}
public int getLocalVariableRefenceInfoLength() {
return this.localVariableTable.length;
}
public ILocalVariableReferenceInfo[] getLocalVariableTable() {
return this.localVariableTable;
}
public int getParameterIndex() {
return this.parameterIndex;
}
public int getTypeParameterIndex() {
return this.typeParameterIndex;
}
public int getTypeParameterBoundIndex() {
return this.typeParameterBoundIndex;
}
public int[][] getTypePath() {
return this.typePath;
}
public int getAnnotationTypeIndex() {
return this.annotationTypeIndex;
}
}