Revamped support for reading Java annotation information from .class files.
The code should handle all cases now, and the APIs are improved. git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4422 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
c40917c3da
commit
7630cd79c9
|
@ -0,0 +1,24 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 IBM Corporation.
|
||||
* 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
@AnnotationWithParams(strParam="classStrParam")
|
||||
public class AnnotatedClass3 {
|
||||
|
||||
@AnnotationWithParams(enumParam=AnnotationEnum.VAL1,strArrParam={"biz","boz"},annotParam=@AnnotationWithSingleParam("sdfevs"),strParam="sdfsevs",intParam=25,klassParam=Integer.class)
|
||||
public static void foo() {
|
||||
|
||||
}
|
||||
|
||||
@AnnotationWithParams(strArrParam={})
|
||||
public static void emptyArray() {}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 IBM Corporation.
|
||||
* 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
public enum AnnotationEnum {
|
||||
|
||||
VAL1, VAL2
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 IBM Corporation.
|
||||
* 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
public @interface AnnotationWithParams {
|
||||
|
||||
String strParam() default "strdef";
|
||||
int intParam() default 0;
|
||||
Class klassParam() default Object.class;
|
||||
AnnotationEnum enumParam() default AnnotationEnum.VAL2;
|
||||
String[] strArrParam() default {"foo","baz"};
|
||||
int[] intArrParam() default {3,4};
|
||||
AnnotationWithSingleParam annotParam() default @AnnotationWithSingleParam("fsf");
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 IBM Corporation.
|
||||
* 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:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
public @interface AnnotationWithSingleParam {
|
||||
|
||||
String value() default "";
|
||||
}
|
|
@ -4,10 +4,14 @@ import java.io.IOException;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.classLoader.ShrikeCTMethod;
|
||||
import com.ibm.wala.classLoader.ShrikeClass;
|
||||
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
|
||||
import com.ibm.wala.core.tests.util.TestConstants;
|
||||
|
@ -15,8 +19,11 @@ import com.ibm.wala.core.tests.util.WalaTestCase;
|
|||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
import com.ibm.wala.types.Selector;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
|
@ -29,39 +36,59 @@ public class AnnotationTest extends WalaTestCase {
|
|||
justThisTest(AnnotationTest.class);
|
||||
}
|
||||
|
||||
@Test public void testClassAnnotations1() throws Exception {
|
||||
private static IClassHierarchy cha;
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws IOException, ClassHierarchyException {
|
||||
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
|
||||
FileProvider.getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), AnnotationTest.class.getClassLoader());
|
||||
cha = ClassHierarchy.make(scope);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void after() {
|
||||
cha = null;
|
||||
|
||||
}
|
||||
@Test
|
||||
public void testClassAnnotations1() throws Exception {
|
||||
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass1");
|
||||
|
||||
Collection<Annotation> expectedRuntimeInvisibleAnnotations = HashSetFactory.make();
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/RuntimeInvisableAnnotation")));
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/DefaultVisableAnnotation")));
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/RuntimeInvisableAnnotation")));
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/DefaultVisableAnnotation")));
|
||||
|
||||
Collection<Annotation> expectedRuntimeVisibleAnnotations = HashSetFactory.make();
|
||||
expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/RuntimeVisableAnnotation")));
|
||||
|
||||
testClassAnnontations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
|
||||
expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/RuntimeVisableAnnotation")));
|
||||
|
||||
testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
@Test public void testClassAnnotations2() throws Exception {
|
||||
@Test
|
||||
public void testClassAnnotations2() throws Exception {
|
||||
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass2");
|
||||
|
||||
Collection<Annotation> expectedRuntimeInvisibleAnnotations = HashSetFactory.make();
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/RuntimeInvisableAnnotation")));
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/RuntimeInvisableAnnotation2")));
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/RuntimeInvisableAnnotation")));
|
||||
expectedRuntimeInvisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/RuntimeInvisableAnnotation2")));
|
||||
|
||||
Collection<Annotation> expectedRuntimeVisibleAnnotations = HashSetFactory.make();
|
||||
expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/RuntimeVisableAnnotation")));
|
||||
expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/RuntimeVisableAnnotation2")));
|
||||
|
||||
testClassAnnontations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
|
||||
expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/RuntimeVisableAnnotation")));
|
||||
expectedRuntimeVisibleAnnotations.add(Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||
"Lannotations/RuntimeVisableAnnotation2")));
|
||||
|
||||
testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
private void testClassAnnontations(TypeReference typeUnderTest, Collection<Annotation> expectedRuntimeInvisibleAnnotations,
|
||||
private void testClassAnnotations(TypeReference typeUnderTest, Collection<Annotation> expectedRuntimeInvisibleAnnotations,
|
||||
Collection<Annotation> expectedRuntimeVisibleAnnotations) throws IOException, ClassHierarchyException,
|
||||
InvalidClassFileException, com.ibm.wala.shrikeCT.AnnotationsReader.UnimplementedException {
|
||||
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, FileProvider.getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), getClass().getClassLoader());
|
||||
ClassHierarchy cha = ClassHierarchy.make(scope);
|
||||
|
||||
InvalidClassFileException {
|
||||
IClass classUnderTest = cha.lookupClass(typeUnderTest);
|
||||
Assert.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest);
|
||||
Assert.assertTrue(classUnderTest instanceof ShrikeClass);
|
||||
|
@ -74,23 +101,45 @@ public class AnnotationTest extends WalaTestCase {
|
|||
assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
private <T> void assertEqualCollections(Collection<T> expected,
|
||||
Collection<T> actual) {
|
||||
if (expected == null){
|
||||
private <T> void assertEqualCollections(Collection<T> expected, Collection<T> actual) {
|
||||
if (expected == null) {
|
||||
expected = Collections.emptySet();
|
||||
}
|
||||
if (actual == null){
|
||||
if (actual == null) {
|
||||
actual = Collections.emptySet();
|
||||
}
|
||||
|
||||
if (expected.size() != actual.size()){
|
||||
|
||||
if (expected.size() != actual.size()) {
|
||||
Assert.assertTrue("expected=" + expected + " actual=" + actual, false);
|
||||
}
|
||||
for (T a : expected){
|
||||
Assert.assertTrue ("missing " + a.toString(), actual.contains(a));
|
||||
for (T a : expected) {
|
||||
Assert.assertTrue("missing " + a.toString(), actual.contains(a));
|
||||
}
|
||||
}
|
||||
// String methodSig = "annotations.AnnotatedClass1.m1()V;";
|
||||
// MethodReference mr = StringStuff.makeMethodReference(methodSig );
|
||||
//
|
||||
|
||||
@Test
|
||||
public void testClassAnnotations3() throws Exception {
|
||||
|
||||
TypeReference typeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass3");
|
||||
IClass klass = cha.lookupClass(typeRef);
|
||||
Assert.assertNotNull(klass);
|
||||
ShrikeClass shrikeClass = (ShrikeClass) klass;
|
||||
Collection<Annotation> classAnnotations = shrikeClass.getAnnotations(true);
|
||||
Assert.assertEquals("[Annotation type <Application,Lannotations/AnnotationWithParams> {strParam=classStrParam}]",
|
||||
classAnnotations.toString());
|
||||
|
||||
MethodReference methodRefUnderTest = MethodReference.findOrCreate(typeRef, Selector.make("foo()V"));
|
||||
|
||||
IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest);
|
||||
Assert.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest);
|
||||
Assert.assertTrue(methodUnderTest instanceof ShrikeCTMethod);
|
||||
ShrikeCTMethod shrikeCTMethodUnderTest = (ShrikeCTMethod) methodUnderTest;
|
||||
|
||||
Collection<Annotation> runtimeInvisibleAnnotations = shrikeCTMethodUnderTest.getAnnotations(true);
|
||||
Assert
|
||||
.assertEquals(
|
||||
"[Annotation type <Application,Lannotations/AnnotationWithParams> {enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], strArrParam=ArrayElementValue [vals=[biz, boz]], annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], strParam=sdfsevs, intParam=25, klassParam=Ljava/lang/Integer;}]",
|
||||
runtimeInvisibleAnnotations.toString());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,12 @@
|
|||
package com.ibm.wala.classLoader;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeBT.Decoder;
|
||||
import com.ibm.wala.shrikeBT.IndirectionData;
|
||||
import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.UnimplementedException;
|
||||
import com.ibm.wala.shrikeCT.ClassReader;
|
||||
import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
|
||||
import com.ibm.wala.shrikeCT.CodeReader;
|
||||
|
@ -33,7 +30,6 @@ import com.ibm.wala.shrikeCT.SignatureReader;
|
|||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.generics.MethodTypeSignature;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
|
||||
/**
|
||||
|
@ -276,7 +272,7 @@ public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMet
|
|||
return result;
|
||||
}
|
||||
|
||||
private AnnotationsReader getAnnotationsReader(boolean runtimeInvisable) {
|
||||
private AnnotationsReader getAnnotationsReader(boolean runtimeInvisible) {
|
||||
ClassReader.AttrIterator iter = new AttrIterator();
|
||||
getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter);
|
||||
|
||||
|
@ -284,7 +280,7 @@ public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMet
|
|||
AnnotationsReader result = null;
|
||||
try {
|
||||
for (; iter.isValid(); iter.advance()) {
|
||||
if (runtimeInvisable) {
|
||||
if (runtimeInvisible) {
|
||||
if (iter.getName().equals(RuntimeInvisibleAnnotationsReader.attrName)) {
|
||||
result = new RuntimeInvisibleAnnotationsReader(iter);
|
||||
break;
|
||||
|
@ -342,56 +338,22 @@ public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMet
|
|||
/**
|
||||
* read the runtime-invisible annotations from the class file
|
||||
*/
|
||||
public Collection<Annotation> getRuntimeInvisibleAnnotations() throws InvalidClassFileException, UnimplementedException {
|
||||
public Collection<Annotation> getRuntimeInvisibleAnnotations() throws InvalidClassFileException {
|
||||
return getAnnotations(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* read the runtime-visible annotations from the class file
|
||||
*/
|
||||
public Collection<Annotation> getRuntimeVisibleAnnotations() throws InvalidClassFileException, UnimplementedException {
|
||||
public Collection<Annotation> getRuntimeVisibleAnnotations() throws InvalidClassFileException {
|
||||
return getAnnotations(false);
|
||||
}
|
||||
|
||||
public Collection<Annotation> getAnnotations(boolean runtimeInvisable) throws InvalidClassFileException, UnimplementedException {
|
||||
AnnotationsReader r = getAnnotationsReader(runtimeInvisable);
|
||||
if (r != null) {
|
||||
int[] offsets = r.getAnnotationOffsets();
|
||||
Collection<Annotation> result = HashSetFactory.make();
|
||||
for (int i : offsets) {
|
||||
String type = r.getAnnotationType(i);
|
||||
type = type.replaceAll(";", "");
|
||||
TypeReference t = TypeReference.findOrCreate(getDeclaringClass().getClassLoader().getReference(), type);
|
||||
result.add(Annotation.make(t));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
public Collection<Annotation> getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
AnnotationsReader r = getAnnotationsReader(runtimeInvisible);
|
||||
return Annotation.getAnnotationsFromReader(r, getDeclaringClass().getClassLoader().getReference());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all runtime-invisible annotations associated with a given index. Returns null if the index is not valid or the
|
||||
* annotation contains arrays.
|
||||
*/
|
||||
public HashMap<String, String> getAnnotations(int index) {
|
||||
AnnotationsReader r = getAnnotationsReader(true);
|
||||
if (r == null)
|
||||
return null;
|
||||
int offsets[];
|
||||
try {
|
||||
offsets = r.getAnnotationOffsets();
|
||||
if (offsets.length <= index)
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int curOffset = offsets[index];
|
||||
HashMap<String, String> res = r.getAnnotationValues(curOffset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static final IndirectionData NO_INDIRECTIONS = new IndirectionData() {
|
||||
|
||||
|
|
|
@ -12,14 +12,12 @@ package com.ibm.wala.classLoader;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeBT.Constants;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.UnimplementedException;
|
||||
import com.ibm.wala.shrikeCT.ClassConstants;
|
||||
import com.ibm.wala.shrikeCT.ClassReader;
|
||||
import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
|
||||
|
@ -32,7 +30,6 @@ import com.ibm.wala.types.TypeName;
|
|||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.generics.ClassSignature;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.shrike.ShrikeClassReaderHandle;
|
||||
import com.ibm.wala.util.strings.Atom;
|
||||
|
@ -85,13 +82,8 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
Atom name = Atom.findOrCreateUnicodeAtom(cr.getFieldName(i));
|
||||
ImmutableByteArray b = ImmutableByteArray.make(cr.getFieldType(i));
|
||||
Collection<Annotation> annotations = null;
|
||||
try {
|
||||
annotations = getRuntimeInvisibleAnnotations(i);
|
||||
annotations = annotations.isEmpty() ? null : annotations;
|
||||
} catch (UnimplementedException e) {
|
||||
e.printStackTrace();
|
||||
// keep going
|
||||
}
|
||||
|
||||
if ((accessFlags & ClassConstants.ACC_STATIC) == 0) {
|
||||
addFieldToList(instanceList, name, b, accessFlags, annotations);
|
||||
|
@ -226,29 +218,17 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
reader.clear();
|
||||
}
|
||||
|
||||
public Collection<Annotation> getRuntimeInvisibleAnnotations() throws InvalidClassFileException, UnimplementedException {
|
||||
public Collection<Annotation> getRuntimeInvisibleAnnotations() throws InvalidClassFileException {
|
||||
return getAnnotations(true);
|
||||
}
|
||||
|
||||
public Collection<Annotation> getRuntimeVisibleAnnotations() throws InvalidClassFileException, UnimplementedException {
|
||||
public Collection<Annotation> getRuntimeVisibleAnnotations() throws InvalidClassFileException {
|
||||
return getAnnotations(false);
|
||||
}
|
||||
|
||||
public Collection<Annotation> getAnnotations(boolean runtimeInvisable) throws InvalidClassFileException, UnimplementedException {
|
||||
AnnotationsReader r = getAnnotationsReader(runtimeInvisable);
|
||||
if (r != null) {
|
||||
int[] offsets = r.getAnnotationOffsets();
|
||||
Collection<Annotation> result = HashSetFactory.make();
|
||||
for (int i : offsets) {
|
||||
String type = r.getAnnotationType(i);
|
||||
type = type.replaceAll(";", "");
|
||||
TypeReference t = TypeReference.findOrCreate(getClassLoader().getReference(), type);
|
||||
result.add(Annotation.make(t));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
public Collection<Annotation> getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
AnnotationsReader r = getAnnotationsReader(runtimeInvisible);
|
||||
return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference());
|
||||
}
|
||||
|
||||
private AnnotationsReader getAnnotationsReader(boolean runtimeInvisable) throws InvalidClassFileException {
|
||||
|
@ -278,6 +258,7 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
private InnerClassesReader getInnerClassesReader() throws InvalidClassFileException {
|
||||
ClassReader r = reader.get();
|
||||
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
||||
|
@ -320,22 +301,9 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
/**
|
||||
* read the runtime-invisible annotations from the class file
|
||||
*/
|
||||
public Collection<Annotation> getRuntimeInvisibleAnnotations(int fieldIndex) throws InvalidClassFileException,
|
||||
UnimplementedException {
|
||||
public Collection<Annotation> getRuntimeInvisibleAnnotations(int fieldIndex) throws InvalidClassFileException {
|
||||
RuntimeInvisibleAnnotationsReader r = getRuntimeInvisibleAnnotationsReader(fieldIndex);
|
||||
if (r != null) {
|
||||
int[] offsets = r.getAnnotationOffsets();
|
||||
Collection<Annotation> result = HashSetFactory.make();
|
||||
for (int i : offsets) {
|
||||
String type = r.getAnnotationType(i);
|
||||
type = type.replaceAll(";", "");
|
||||
TypeReference t = TypeReference.findOrCreate(getClassLoader().getReference(), type);
|
||||
result.add(Annotation.make(t));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference());
|
||||
}
|
||||
|
||||
private SignatureReader getSignatureReader() throws InvalidClassFileException {
|
||||
|
|
|
@ -11,41 +11,95 @@
|
|||
package com.ibm.wala.types.annotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationAttribute;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.ElementValue;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
|
||||
/**
|
||||
* Represents a Java 5.0 class file annotation
|
||||
* Represents a member annotation, e.g., Java 5.0 class file annotations
|
||||
*/
|
||||
public class Annotation {
|
||||
|
||||
|
||||
private final TypeReference type;
|
||||
private final Pair<TypeReference, Object>[] arguments;
|
||||
|
||||
private Annotation(TypeReference type, Pair<TypeReference, Object>[] arguments) {
|
||||
|
||||
/**
|
||||
* named arguments to the annotation, represented as a mapping from name to
|
||||
* value. Note that for Java annotation arguments, the values are always
|
||||
* Strings, independent of their actual type in the bytecode.
|
||||
*/
|
||||
private final Map<String, ElementValue> namedArguments;
|
||||
|
||||
/**
|
||||
* unnamed arguments to the annotation (e.g., constructor arguments for C#
|
||||
* attributes), represented as an array of pairs (T,V), where T is the
|
||||
* argument type and V is the value. The array preserves the order in which
|
||||
* the arguments were passed. If null, there are no unnamed arguments.
|
||||
*/
|
||||
private final Pair<TypeReference, Object>[] unnamedArguments;
|
||||
|
||||
private Annotation(TypeReference type, Map<String, ElementValue> namedArguments, Pair<TypeReference, Object>[] unnamedArguments) {
|
||||
this.type = type;
|
||||
this.arguments = arguments;
|
||||
if (namedArguments == null) {
|
||||
throw new IllegalArgumentException("namedArguments is null");
|
||||
}
|
||||
this.namedArguments = namedArguments;
|
||||
this.unnamedArguments = unnamedArguments;
|
||||
}
|
||||
|
||||
public static Annotation make(TypeReference t, Pair<TypeReference, Object>[] arguments) {
|
||||
return new Annotation(t, arguments);
|
||||
|
||||
public static Annotation makeUnnamedAndNamed(TypeReference t, Map<String, ElementValue> namedArguments, Pair<TypeReference,Object>[] unnamedArguments) {
|
||||
return new Annotation(t, namedArguments, unnamedArguments);
|
||||
}
|
||||
public static Annotation makeWithUnnamed(TypeReference t, Pair<TypeReference, Object>[] unnamedArguments) {
|
||||
return new Annotation(t, Collections.<String,ElementValue>emptyMap(), unnamedArguments);
|
||||
}
|
||||
|
||||
public static Annotation make(TypeReference t) {
|
||||
return make(t, null);
|
||||
return new Annotation(t, Collections.<String,ElementValue>emptyMap(), null);
|
||||
}
|
||||
|
||||
public static Annotation makeWithNamed(TypeReference t, Map<String,ElementValue> namedArguments) {
|
||||
return new Annotation(t, namedArguments, null);
|
||||
}
|
||||
|
||||
public static Collection<Annotation> getAnnotationsFromReader(AnnotationsReader r, ClassLoaderReference clRef) throws InvalidClassFileException {
|
||||
if (r != null) {
|
||||
AnnotationAttribute[] allAnnotations = r.getAllAnnotations();
|
||||
Collection<Annotation> result = HashSetFactory.make();
|
||||
for (AnnotationAttribute annot : allAnnotations) {
|
||||
String type = annot.type;
|
||||
type = type.replaceAll(";", "");
|
||||
TypeReference t = TypeReference.findOrCreate(clRef, type);
|
||||
result.add(makeWithNamed(t, annot.elementValues));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer("Annotation type " + type);
|
||||
if (arguments != null) {
|
||||
if (unnamedArguments != null) {
|
||||
sb.append("[");
|
||||
for(Pair<TypeReference, Object> arg : arguments) {
|
||||
for (Pair<TypeReference, Object> arg : unnamedArguments) {
|
||||
sb.append(" " + arg.fst.getName().getClassName() + ":" + arg.snd);
|
||||
}
|
||||
sb.append(" ]");
|
||||
}
|
||||
if (!namedArguments.isEmpty()) {
|
||||
sb.append(" " + namedArguments);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
@ -53,7 +107,7 @@ public class Annotation {
|
|||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(arguments);
|
||||
result = prime * result + Arrays.hashCode(unnamedArguments);
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
@ -67,7 +121,7 @@ public class Annotation {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Annotation other = (Annotation) obj;
|
||||
if (!Arrays.equals(arguments, other.arguments))
|
||||
if (!Arrays.equals(unnamedArguments, other.unnamedArguments))
|
||||
return false;
|
||||
if (type == null) {
|
||||
if (other.type != null)
|
||||
|
@ -77,8 +131,12 @@ public class Annotation {
|
|||
return true;
|
||||
}
|
||||
|
||||
public Pair<TypeReference, Object>[] getArguments() {
|
||||
return arguments;
|
||||
public Pair<TypeReference, Object>[] getUnnamedArguments() {
|
||||
return unnamedArguments;
|
||||
}
|
||||
|
||||
public Map<String,ElementValue> getNamedArguments() {
|
||||
return namedArguments;
|
||||
}
|
||||
|
||||
public TypeReference getType() {
|
||||
|
|
|
@ -18,7 +18,6 @@ import com.ibm.wala.classLoader.IField;
|
|||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.classLoader.ShrikeCTMethod;
|
||||
import com.ibm.wala.classLoader.ShrikeClass;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.UnimplementedException;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.types.TypeName;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
|
@ -39,10 +38,7 @@ public class Annotations {
|
|||
} catch (InvalidClassFileException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.UNREACHABLE();
|
||||
} catch (UnimplementedException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
}
|
||||
for (Annotation a : annotations) {
|
||||
if (a.getType().getName().equals(type)) {
|
||||
return true;
|
||||
|
@ -63,9 +59,6 @@ public class Annotations {
|
|||
} catch (InvalidClassFileException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.UNREACHABLE();
|
||||
} catch (UnimplementedException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
for (Annotation a : annotations) {
|
||||
if (a.getType().getName().equals(type)) {
|
||||
|
|
|
@ -16,3 +16,4 @@ Export-Package: com.ibm.wala.shrike.bench,
|
|||
com.ibm.wala.shrikeBT.tools,
|
||||
com.ibm.wala.shrikeCT
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
Require-Bundle: com.ibm.wala.util
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder;
|
|||
import com.ibm.wala.shrikeBT.shrikeCT.ClassInstrumenter;
|
||||
import com.ibm.wala.shrikeBT.shrikeCT.OfflineInstrumenter;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationAttribute;
|
||||
import com.ibm.wala.shrikeCT.ClassConstants;
|
||||
import com.ibm.wala.shrikeCT.ClassReader;
|
||||
import com.ibm.wala.shrikeCT.CodeReader;
|
||||
|
@ -286,20 +287,8 @@ public class ClassPrinter {
|
|||
|
||||
private void printAnnotations(ClassReader cr, ClassReader.AttrIterator attrs, AnnotationsReader r)
|
||||
throws InvalidClassFileException {
|
||||
try {
|
||||
int[] annotations = r.getAnnotationOffsets();
|
||||
for (int j : annotations) {
|
||||
w.write(" Annotation type: " + r.getAnnotationType(j) + "\n");
|
||||
}
|
||||
} catch (AnnotationsReader.UnimplementedException e) {
|
||||
int len = attrs.getDataSize();
|
||||
int pos = attrs.getDataOffset();
|
||||
while (len > 0) {
|
||||
int amount = Math.min(16, len);
|
||||
w.write(" " + makeHex(cr.getBytes(), pos, amount, 32) + " " + makeChars(cr.getBytes(), pos, amount) + "\n");
|
||||
len -= amount;
|
||||
pos += amount;
|
||||
}
|
||||
for (AnnotationAttribute annot : r.getAllAnnotations()) {
|
||||
w.write(" Annotation type: " + annot.type + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,14 @@
|
|||
*******************************************************************************/
|
||||
package com.ibm.wala.shrikeCT;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
|
||||
/**
|
||||
* This class reads Annotations attributes.
|
||||
* This class reads Annotations attributes, e.g., RuntimeInvisibleAnnotations.
|
||||
*
|
||||
* @author sjfink
|
||||
*/
|
||||
|
@ -40,7 +44,8 @@ public class AnnotationsReader extends AttributeReader {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return total length of this attribute in bytes, <bf>including</bf> the first 6 bytes
|
||||
* @return total length of this attribute in bytes, <bf>including</bf> the
|
||||
* first 6 bytes
|
||||
* @throws InvalidClassFileException
|
||||
*/
|
||||
public int getAttributeSize() throws InvalidClassFileException {
|
||||
|
@ -50,118 +55,238 @@ public class AnnotationsReader extends AttributeReader {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the offsets into the class file of the annotations of this attribute
|
||||
* @throws InvalidClassFileException
|
||||
* @throws UnimplementedException
|
||||
*/
|
||||
public int[] getAnnotationOffsets() throws InvalidClassFileException, UnimplementedException {
|
||||
int[] result = new int[getAnnotationCount()];
|
||||
int offset = beginOffset + 8;
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = offset;
|
||||
offset += getAnnotationSize(offset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param begin offset in the constant pool
|
||||
* @return the size, in bytes, of the annotation structure starting at a given offset
|
||||
* @throws InvalidClassFileException
|
||||
* @throws UnimplementedException
|
||||
*/
|
||||
private int getAnnotationSize(int begin) throws InvalidClassFileException, UnimplementedException {
|
||||
int offset = begin + 2;
|
||||
checkSize(offset, 2);
|
||||
int numElementValuePairs = cr.getUShort(offset);
|
||||
offset += 2;
|
||||
for (int i = 0; i < numElementValuePairs; i++) {
|
||||
offset += 2;
|
||||
offset += getElementValueSize(offset);
|
||||
}
|
||||
return offset - begin;
|
||||
}
|
||||
|
||||
/**
|
||||
* temporary migration aid until I've implemented everything.
|
||||
*
|
||||
* @author sjfink
|
||||
* get the Utf8 constant pool value, where the constant pool offset is given
|
||||
* in the class
|
||||
*
|
||||
* @param offset
|
||||
* offset in the class file at which the constant pool offset is
|
||||
* given
|
||||
*/
|
||||
public static class UnimplementedException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type of the annotation stating at a given offset
|
||||
* @throws InvalidClassFileException
|
||||
*/
|
||||
public String getAnnotationType(int offset) throws InvalidClassFileException {
|
||||
private String getUtf8ConstantPoolValue(int offset) throws InvalidClassFileException {
|
||||
checkSize(offset, 2);
|
||||
int cpOffset = cr.getUShort(offset);
|
||||
return cr.getCP().getCPUtf8(cpOffset);
|
||||
}
|
||||
|
||||
public static final int INT_TYPE = 3;
|
||||
|
||||
public static final int STRING_TYPE = 1;
|
||||
|
||||
/*
|
||||
* This method maps the internal type representation of annotation types to java types and stringifies all annotations.
|
||||
/**
|
||||
* Marker interface for possible element values in an annotation attribute.
|
||||
*
|
||||
* @see AnnotationsReader#readElementValueAndSize(int)
|
||||
*
|
||||
*/
|
||||
private String getFromConstantPool(int offset) {
|
||||
byte type = cr.getCP().getItemType(cr.getByte(offset));
|
||||
|
||||
if (type == INT_TYPE) {
|
||||
String res = "";
|
||||
try {
|
||||
res = "" + cr.getCP().getCPInt(cr.getByte(offset));
|
||||
} catch (InvalidClassFileException e) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
if (type == STRING_TYPE) {
|
||||
String res = "";
|
||||
try {
|
||||
res = cr.getCP().getCPUtf8(cr.getByte(offset));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return "";
|
||||
public static interface ElementValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns all the annotations as map key->stringified value starting at the index begin in the class file.
|
||||
* @see AnnotationsReader#readElementValueAndSize(int)
|
||||
*
|
||||
*
|
||||
* @param begin
|
||||
* @return HashMap<String, String>
|
||||
*/
|
||||
public HashMap<String, String> getAnnotationValues(int begin) {
|
||||
HashMap<String, String> res = new HashMap<String, String>();
|
||||
int offset = begin + 2;
|
||||
public static class ConstantElementValue implements ElementValue {
|
||||
|
||||
int numElementValuePairs = cr.getUShort(offset);
|
||||
public final Object val;
|
||||
|
||||
offset += 3;
|
||||
public ConstantElementValue(Object val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return val.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnnotationsReader#readElementValueAndSize(int)
|
||||
*/
|
||||
public static class EnumElementValue implements ElementValue {
|
||||
public final String enumType;
|
||||
public final String enumVal;
|
||||
|
||||
public EnumElementValue(String enumType, String enumVal) {
|
||||
super();
|
||||
this.enumType = enumType;
|
||||
this.enumVal = enumVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnumElementValue [type=" + enumType + ", val=" + enumVal + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnnotationsReader#readElementValueAndSize(int)
|
||||
*/
|
||||
public static class ArrayElementValue implements ElementValue {
|
||||
|
||||
public final ElementValue[] vals;
|
||||
|
||||
public ArrayElementValue(ElementValue[] vals) {
|
||||
super();
|
||||
this.vals = vals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArrayElementValue [vals=" + Arrays.toString(vals) + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get all the annotations declared in this attribute.
|
||||
*
|
||||
* @throws InvalidClassFileException
|
||||
*/
|
||||
public AnnotationAttribute[] getAllAnnotations() throws InvalidClassFileException {
|
||||
AnnotationAttribute[] result = new AnnotationAttribute[getAnnotationCount()];
|
||||
int offset = beginOffset + 8; // skip attribute_name_index,
|
||||
// attribute_length, and num_annotations
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
Pair<AnnotationAttribute, Integer> attributeAndSize = getAttributeAndSize(offset);
|
||||
result[i] = attributeAndSize.fst;
|
||||
offset += attributeAndSize.snd;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* annotation {
|
||||
* u2 type_index;
|
||||
* u2 num_element_value_pairs;
|
||||
* { u2 element_name_index;
|
||||
* element_value value;
|
||||
* } element_value_pairs[num_element_value_pairs]
|
||||
* </pre>
|
||||
*
|
||||
* @throws InvalidClassFileException
|
||||
*/
|
||||
private Pair<AnnotationAttribute, Integer> getAttributeAndSize(int begin) throws InvalidClassFileException {
|
||||
String type = getUtf8ConstantPoolValue(begin);
|
||||
int numElementValuePairs = cr.getUShort(begin + 2);
|
||||
int size = 4;
|
||||
int offset = begin + 4;
|
||||
Map<String, ElementValue> elementName2Val = HashMapFactory.make();
|
||||
for (int i = 0; i < numElementValuePairs; i++) {
|
||||
String res1 = getFromConstantPool(offset);
|
||||
offset += 3;
|
||||
String res2 = getFromConstantPool(offset);
|
||||
String elementName = getUtf8ConstantPoolValue(offset);
|
||||
offset += 2;
|
||||
res.put(res1, res2);
|
||||
Pair<ElementValue, Integer> elementValAndSize = readElementValueAndSize(offset);
|
||||
offset += elementValAndSize.snd;
|
||||
size += elementValAndSize.snd + 2;
|
||||
elementName2Val.put(elementName, elementValAndSize.fst);
|
||||
}
|
||||
return res;
|
||||
return Pair.make(new AnnotationAttribute(type, elementName2Val), size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size, in bytes, of the element-value structure starting at a given offset
|
||||
* Representation of an annotation attribute. An annotation has the following
|
||||
* format in the bytecode:
|
||||
*
|
||||
* <pre>
|
||||
* annotation {
|
||||
* u2 type_index;
|
||||
* u2 num_element_value_pairs;
|
||||
* { u2 element_name_index;
|
||||
* element_value value;
|
||||
* } element_value_pairs[num_element_value_pairs];
|
||||
* </pre>
|
||||
*
|
||||
* See the JVM spec section 4.7.16 for details.
|
||||
*/
|
||||
private int getElementValueSize(int begin) {
|
||||
return 3; // this is correct for any primitive type annotations.
|
||||
// TODO: Integrate array annotations
|
||||
public static class AnnotationAttribute implements ElementValue {
|
||||
|
||||
public final String type;
|
||||
|
||||
public final Map<String, ElementValue> elementValues;
|
||||
|
||||
public AnnotationAttribute(String type, Map<String, ElementValue> elementValues) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.elementValues = elementValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnnotationElementValue [type=" + type + ", elementValues=" + elementValues + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* element_value {
|
||||
* u1 tag;
|
||||
* union {
|
||||
* u2 const_value_index;
|
||||
* { u2 type_name_index;
|
||||
* u2 const_name_index;
|
||||
* } enum_const_value;
|
||||
* u2 class_info_index;
|
||||
* annotation annotation_value;
|
||||
* { u2 num_values;
|
||||
* element_value values[num_values];
|
||||
* } array_value;
|
||||
* } value;
|
||||
* </pre>
|
||||
*
|
||||
* A constant value (including class info) is represented by a
|
||||
* {@link ConstantElementValue}. An enum constant value is represented by an
|
||||
* {@link EnumElementValue}. An array value is represented by an
|
||||
* {@link ArrayElementValue}. Finally, a nested annotation is represented by
|
||||
* an {@link AnnotationAttribute}.
|
||||
*
|
||||
* @throws InvalidClassFileException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
private Pair<ElementValue, Integer> readElementValueAndSize(int offset) throws IllegalArgumentException,
|
||||
InvalidClassFileException {
|
||||
char tag = (char) cr.getByte(offset);
|
||||
// meaning of this short depends on the tag
|
||||
int nextShort = cr.getUShort(offset + 1);
|
||||
switch (tag) {
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'I':
|
||||
case 'S':
|
||||
case 'Z':
|
||||
return Pair.<ElementValue, Integer> make(new ConstantElementValue(cr.getCP().getCPInt(nextShort)), 3);
|
||||
case 'J':
|
||||
return Pair.<ElementValue, Integer> make(new ConstantElementValue(cr.getCP().getCPLong(nextShort)), 3);
|
||||
case 'D':
|
||||
return Pair.<ElementValue, Integer> make(new ConstantElementValue(cr.getCP().getCPDouble(nextShort)), 3);
|
||||
case 'F':
|
||||
return Pair.<ElementValue, Integer> make(new ConstantElementValue(cr.getCP().getCPFloat(nextShort)), 3);
|
||||
case 's': // string
|
||||
case 'c': // class; just represent as a constant element with the type name
|
||||
return Pair.<ElementValue, Integer> make(new ConstantElementValue(cr.getCP().getCPUtf8(nextShort)), 3);
|
||||
case 'e': // enum
|
||||
return Pair.<ElementValue, Integer> make(
|
||||
new EnumElementValue(cr.getCP().getCPUtf8(nextShort), cr.getCP().getCPUtf8(cr.getUShort(offset + 3))), 5);
|
||||
case '[': // array
|
||||
int numValues = nextShort;
|
||||
int numArrayBytes = 3; // start with 3 for the tag and num_values bytes
|
||||
ElementValue[] vals = new ElementValue[numValues];
|
||||
// start curOffset at beginning of array values
|
||||
int curArrayOffset = offset + 3;
|
||||
for (int i = 0; i < numValues; i++) {
|
||||
Pair<ElementValue, Integer> arrayElemValueAndSize = readElementValueAndSize(curArrayOffset);
|
||||
vals[i] = arrayElemValueAndSize.fst;
|
||||
curArrayOffset += arrayElemValueAndSize.snd;
|
||||
numArrayBytes += arrayElemValueAndSize.snd;
|
||||
}
|
||||
return Pair.<ElementValue, Integer> make(new ArrayElementValue(vals), numArrayBytes);
|
||||
case '@': // annotation
|
||||
Pair<AnnotationAttribute,Integer> attributeAndSize = getAttributeAndSize(offset+1);
|
||||
// add 1 to size for the tag
|
||||
return Pair.<ElementValue, Integer> make(attributeAndSize.fst, attributeAndSize.snd + 1);
|
||||
default:
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue