blob: 322f82796c25db06a2c825fe1a23a7478f7d7847 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 GoPivotal, Inc. All Rights Reserved.
* 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 (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 407191 - [1.8] Binary access support for type annotations
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.compiler.classfmt;
import java.util.Arrays;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
/**
* The TypeAnnotationInfo class does not currently support type annotations within code
* blocks (those that have a target type of 0x40 and higher) - it is not yet clear that
* these need to be accessible.
*/
public class TypeAnnotationInfo extends ClassFileStruct implements IBinaryTypeAnnotation {
private AnnotationInfo annotation;
private int targetType = 0;
// info is used in different ways:
// TargetType 0x00: CLASS_TYPE_PARAMETER: type parameter index
// TargetType 0x01: METHOD_TYPE_PARAMETER: type parameter index
// TargetType 0x10: CLASS_EXTENDS: supertype index (-1 = superclass, 0..N superinterface)
// TargetType 0x11: CLASS_TYPE_PARAMETER_BOUND: type parameter index
// TargetType 0x12: METHOD_TYPE_PARAMETER_BOUND: type parameter index
// TargetType 0x16: METHOD_FORMAL_PARAMETER: method formal parameter index
// TargetType 0x17: THROWS: throws type index
private int info;
// TargetType 0x11: CLASS_TYPE_PARAMETER_BOUND: bound index
// TargetType 0x12: METHOD_TYPE_PARAMETER_BOUND: bound index
private int info2;
private int[] typePath; // each pair of ints in the array is a type path entry
int readOffset = 0;
TypeAnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset) {
super(classFileBytes, contantPoolOffsets, offset);
}
TypeAnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset, boolean runtimeVisible, boolean populate) {
this(classFileBytes, contantPoolOffsets, offset);
this.readOffset = 0;
this.targetType = u1At(0);
switch (this.targetType) {
case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER:
case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER:
this.info = u1At(1); // typeParameterIndex
this.readOffset += 2;
break;
case AnnotationTargetTypeConstants.CLASS_EXTENDS:
this.info = u2At(1); // supertypeIndex
this.readOffset += 3;
break;
case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND:
case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND:
this.info = u1At(1); // typeParameterIndex
this.info2 = u1At(2); // boundIndex;
this.readOffset += 3;
break;
case AnnotationTargetTypeConstants.FIELD:
case AnnotationTargetTypeConstants.METHOD_RETURN:
case AnnotationTargetTypeConstants.METHOD_RECEIVER:
this.readOffset ++;
break;
case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER :
this.info = u1At(1); // methodFormalParameterIndex
this.readOffset += 2;
break;
case AnnotationTargetTypeConstants.THROWS :
this.info = u2At(1); // throwsTypeIndex
this.readOffset += 3;
break;
default:
throw new IllegalStateException("Target type not handled "+this.targetType); //$NON-NLS-1$
}
int typePathLength = u1At(this.readOffset);
this.readOffset ++;
if (typePathLength == 0) {
this.typePath = NO_TYPE_PATH;
} else {
this.typePath = new int[typePathLength*2];
int index = 0;
for (int i = 0; i < typePathLength; i++) {
this.typePath[index++] = u1At(this.readOffset++); // entry kind
this.typePath[index++] = u1At(this.readOffset++); // type argument index
}
}
this.annotation = new AnnotationInfo(classFileBytes, this.constantPoolOffsets, this.structOffset + this.readOffset, runtimeVisible, populate);
this.readOffset += this.annotation.readOffset;
}
@Override
public IBinaryAnnotation getAnnotation() {
return this.annotation;
}
protected void initialize() {
this.annotation.initialize();
}
@Override
protected void reset() {
this.annotation.reset();
super.reset();
}
@Override
public String toString() {
return BinaryTypeFormatter.annotationToString(this);
}
@Override
public int getTargetType() {
return this.targetType;
}
@Override
public int getSupertypeIndex() {
// assert this.targetType == 0x10
return this.info;
}
@Override
public int getTypeParameterIndex() {
// assert this.targetType == 0x00 or 0x01
return this.info;
}
@Override
public int getBoundIndex() {
// assert this.targetType == 0x11 or 0x12
return this.info2;
}
@Override
public int getMethodFormalParameterIndex() {
// assert this.targetType == 0x16
return this.info;
}
@Override
public int getThrowsTypeIndex() {
// assert this.targetType == 0x17
return this.info;
}
@Override
public int[] getTypePath() {
return this.typePath;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.targetType;
result = prime * result + this.info;
result = prime * result + this.info2;
if (this.typePath != null) {
for (int i = 0, max = this.typePath.length; i < max; i++) {
result = prime * result + this.typePath[i];
}
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
TypeAnnotationInfo other = (TypeAnnotationInfo) obj;
if (this.targetType != other.targetType) {
return false;
}
if (this.info != other.info) {
return false;
}
if (this.info2 != other.info2) {
return false;
}
if (!Arrays.equals(this.typePath, other.typePath)) {
return false;
}
return this.annotation.equals(other.annotation);
}
}