2012-09-04 22:56:05 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* Copyright (c) 2002 - 2006 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 com.ibm.wala.classLoader;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
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;
|
2013-06-28 15:00:31 +00:00
|
|
|
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationType;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.shrikeCT.ClassConstants;
|
|
|
|
import com.ibm.wala.shrikeCT.ClassReader;
|
|
|
|
import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
|
|
|
|
import com.ibm.wala.shrikeCT.InnerClassesReader;
|
|
|
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
|
|
|
import com.ibm.wala.shrikeCT.SignatureReader;
|
2017-01-20 00:12:22 +00:00
|
|
|
import com.ibm.wala.shrikeCT.SourceFileReader;
|
2016-12-02 12:31:45 +00:00
|
|
|
import com.ibm.wala.shrikeCT.TypeAnnotationsReader;
|
|
|
|
import com.ibm.wala.types.ClassLoaderReference;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.types.TypeName;
|
|
|
|
import com.ibm.wala.types.TypeReference;
|
|
|
|
import com.ibm.wala.types.annotations.Annotation;
|
2016-12-02 12:31:45 +00:00
|
|
|
import com.ibm.wala.types.annotations.TypeAnnotation;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.types.generics.ClassSignature;
|
2015-09-16 17:23:21 +00:00
|
|
|
import com.ibm.wala.types.generics.TypeSignature;
|
2013-02-03 02:27:45 +00:00
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
|
|
import com.ibm.wala.util.shrike.ShrikeClassReaderHandle;
|
|
|
|
import com.ibm.wala.util.strings.Atom;
|
|
|
|
import com.ibm.wala.util.strings.ImmutableByteArray;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A class read from Shrike
|
|
|
|
*/
|
|
|
|
public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|
|
|
|
|
|
|
static final boolean DEBUG = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The Shrike object that knows how to read the class file
|
|
|
|
*/
|
|
|
|
private final ShrikeClassReaderHandle reader;
|
2013-06-28 15:00:31 +00:00
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
/**
|
2013-06-28 15:00:31 +00:00
|
|
|
* @throws IllegalArgumentException
|
|
|
|
* if reader is null
|
2012-09-04 22:56:05 +00:00
|
|
|
*/
|
|
|
|
public ShrikeClass(ShrikeClassReaderHandle reader, IClassLoader loader, IClassHierarchy cha) throws InvalidClassFileException {
|
|
|
|
super(loader, cha);
|
|
|
|
if (reader == null) {
|
|
|
|
throw new IllegalArgumentException("reader is null");
|
|
|
|
}
|
|
|
|
this.reader = reader;
|
|
|
|
computeTypeReference();
|
|
|
|
this.hashCode = 2161 * getReference().hashCode();
|
|
|
|
// as long as the reader is around, pull more data out
|
|
|
|
// of it before the soft reference to it disappears
|
|
|
|
computeSuperName();
|
|
|
|
computeModifiers();
|
|
|
|
computeInterfaceNames();
|
|
|
|
computeFields();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute the fields declared by this class
|
|
|
|
*
|
2013-06-28 15:00:31 +00:00
|
|
|
* @throws InvalidClassFileException
|
|
|
|
* iff Shrike fails to read the class file correctly
|
2012-09-04 22:56:05 +00:00
|
|
|
*/
|
|
|
|
private void computeFields() throws InvalidClassFileException {
|
|
|
|
ClassReader cr = reader.get();
|
|
|
|
int fieldCount = cr.getFieldCount();
|
|
|
|
List<FieldImpl> instanceList = new ArrayList<FieldImpl>(fieldCount);
|
|
|
|
List<FieldImpl> staticList = new ArrayList<FieldImpl>(fieldCount);
|
|
|
|
try {
|
|
|
|
for (int i = 0; i < fieldCount; i++) {
|
|
|
|
int accessFlags = cr.getFieldAccessFlags(i);
|
|
|
|
Atom name = Atom.findOrCreateUnicodeAtom(cr.getFieldName(i));
|
|
|
|
ImmutableByteArray b = ImmutableByteArray.make(cr.getFieldType(i));
|
2013-06-28 15:00:31 +00:00
|
|
|
Collection<Annotation> annotations = HashSetFactory.make();
|
2013-04-08 20:50:26 +00:00
|
|
|
annotations.addAll(getRuntimeInvisibleAnnotations(i));
|
|
|
|
annotations.addAll(getRuntimeVisibleAnnotations(i));
|
|
|
|
annotations = annotations.isEmpty() ? null : annotations;
|
2015-09-16 17:23:21 +00:00
|
|
|
|
2016-12-02 12:31:45 +00:00
|
|
|
Collection<TypeAnnotation> typeAnnotations = HashSetFactory.make();
|
|
|
|
typeAnnotations.addAll(getRuntimeInvisibleTypeAnnotations(i));
|
|
|
|
typeAnnotations.addAll(getRuntimeVisibleTypeAnnotations(i));
|
|
|
|
typeAnnotations = typeAnnotations.isEmpty() ? null : typeAnnotations;
|
|
|
|
|
2015-09-16 17:23:21 +00:00
|
|
|
TypeSignature sig = null;
|
|
|
|
SignatureReader signatureReader = getSignatureReader(i);
|
|
|
|
if (signatureReader != null) {
|
|
|
|
String signature = signatureReader.getSignature();
|
|
|
|
if (signature != null) {
|
|
|
|
sig = TypeSignature.make(signature);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
if ((accessFlags & ClassConstants.ACC_STATIC) == 0) {
|
2016-12-02 12:31:45 +00:00
|
|
|
addFieldToList(instanceList, name, b, accessFlags, annotations, typeAnnotations, sig);
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
2016-12-02 12:31:45 +00:00
|
|
|
addFieldToList(staticList, name, b, accessFlags, annotations, typeAnnotations, sig);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
instanceFields = new IField[instanceList.size()];
|
|
|
|
populateFieldArrayFromList(instanceList, instanceFields);
|
|
|
|
staticFields = new IField[staticList.size()];
|
|
|
|
populateFieldArrayFromList(staticList, staticFields);
|
|
|
|
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @throws InvalidClassFileException
|
|
|
|
*/
|
|
|
|
private void computeModifiers() throws InvalidClassFileException {
|
|
|
|
modifiers = reader.get().getAccessFlags();
|
|
|
|
}
|
|
|
|
|
2013-06-28 15:00:31 +00:00
|
|
|
/**
|
|
|
|
* Note that this is called from the constructor, at which point this class is
|
|
|
|
* not yet ready to actually load the superclass. Instead, we pull out the
|
|
|
|
* name of the superclass and cache it here, to avoid hitting the reader
|
|
|
|
* later.
|
2012-09-04 22:56:05 +00:00
|
|
|
*/
|
|
|
|
private void computeSuperName() {
|
|
|
|
try {
|
|
|
|
String s = reader.get().getSuperName();
|
|
|
|
if (s != null) {
|
|
|
|
superName = ImmutableByteArray.make("L" + s);
|
|
|
|
}
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-06-28 15:00:31 +00:00
|
|
|
* Note that this is called from the constructor, at which point this class is
|
|
|
|
* not yet ready to actually load the interfaces. Instead, we pull out the
|
|
|
|
* name of the interfaces and cache it here, to avoid hitting the reader
|
|
|
|
* later.
|
2012-09-04 22:56:05 +00:00
|
|
|
*/
|
|
|
|
private void computeInterfaceNames() {
|
|
|
|
try {
|
|
|
|
String[] s = reader.get().getInterfaceNames();
|
|
|
|
interfaceNames = new ImmutableByteArray[s.length];
|
|
|
|
for (int i = 0; i < interfaceNames.length; i++) {
|
|
|
|
interfaceNames[i] = ImmutableByteArray.make("L" + s[i]);
|
|
|
|
}
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* initialize the declared methods array
|
|
|
|
*
|
|
|
|
* @throws InvalidClassFileException
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
protected ShrikeCTMethod[] computeDeclaredMethods() throws InvalidClassFileException {
|
|
|
|
int methodCount = reader.get().getMethodCount();
|
|
|
|
ShrikeCTMethod[] result = new ShrikeCTMethod[methodCount];
|
|
|
|
for (int i = 0; i < methodCount; i++) {
|
|
|
|
ShrikeCTMethod m = new ShrikeCTMethod(this, i);
|
|
|
|
if (DEBUG) {
|
|
|
|
System.err.println(("Register method " + m + " for class " + this));
|
|
|
|
}
|
|
|
|
result[i] = m;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* initialize the TypeReference field for this instance
|
|
|
|
*
|
2013-06-28 15:00:31 +00:00
|
|
|
* @throws InvalidClassFileException
|
|
|
|
* iff Shrike can't read this class
|
2012-09-04 22:56:05 +00:00
|
|
|
*/
|
|
|
|
private void computeTypeReference() throws InvalidClassFileException {
|
|
|
|
String className = "L" + reader.get().getName();
|
|
|
|
ImmutableByteArray name = ImmutableByteArray.make(className);
|
|
|
|
|
|
|
|
typeReference = TypeReference.findOrCreate(getClassLoader().getReference(), TypeName.findOrCreate(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see java.lang.Object#equals(Object)
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object obj) {
|
|
|
|
// it's ok to use instanceof since this class is final
|
|
|
|
// if (this.getClass().equals(obj.getClass())) {
|
|
|
|
if (obj instanceof ShrikeClass) {
|
|
|
|
return getReference().equals(((ShrikeClass) obj).getReference());
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ClassReader getReader() {
|
|
|
|
try {
|
|
|
|
return reader.get();
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2013-06-28 15:00:31 +00:00
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
/**
|
|
|
|
* Clear all optional cached data associated with this class
|
|
|
|
*/
|
|
|
|
public void clearSoftCaches() {
|
|
|
|
// toss optional information from each method.
|
|
|
|
if (methodMap != null) {
|
|
|
|
for (Iterator it = getDeclaredMethods().iterator(); it.hasNext();) {
|
|
|
|
ShrikeCTMethod m = (ShrikeCTMethod) it.next();
|
|
|
|
m.clearCaches();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// clear the methodMap cache
|
|
|
|
// SJF: don't do this!!! makes it hard to clear caches on methods.
|
|
|
|
// methodMap = null;
|
|
|
|
inheritCache = null;
|
|
|
|
// clear the cached interfaces
|
|
|
|
allInterfaces = null;
|
|
|
|
// toss away the Shrike reader
|
|
|
|
reader.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<Annotation> getRuntimeInvisibleAnnotations() throws InvalidClassFileException {
|
|
|
|
return getAnnotations(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<Annotation> getRuntimeVisibleAnnotations() throws InvalidClassFileException {
|
|
|
|
return getAnnotations(false);
|
|
|
|
}
|
2013-06-28 15:00:31 +00:00
|
|
|
|
2013-06-25 15:53:58 +00:00
|
|
|
@Override
|
2013-02-03 02:27:45 +00:00
|
|
|
public Collection<Annotation> getAnnotations() {
|
|
|
|
Collection<Annotation> result = HashSetFactory.make();
|
|
|
|
try {
|
|
|
|
result.addAll(getAnnotations(true));
|
|
|
|
result.addAll(getAnnotations(false));
|
|
|
|
} catch (InvalidClassFileException e) {
|
2013-06-28 15:00:31 +00:00
|
|
|
|
2013-02-03 02:27:45 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-03-04 18:49:58 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
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 {
|
|
|
|
ClassReader r = reader.get();
|
|
|
|
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
|
|
|
r.initClassAttributeIterator(attrs);
|
|
|
|
|
2013-06-28 15:00:31 +00:00
|
|
|
return AnnotationsReader.getReaderForAnnotation(runtimeInvisable ? AnnotationType.RuntimeInvisibleAnnotations
|
|
|
|
: AnnotationType.RuntimeVisibleAnnotations, attrs);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
2016-12-02 12:31:45 +00:00
|
|
|
|
|
|
|
public Collection<TypeAnnotation> getTypeAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
|
|
|
|
TypeAnnotationsReader r = getTypeAnnotationsReader(runtimeInvisible);
|
|
|
|
final ClassLoaderReference clRef = getClassLoader().getReference();
|
|
|
|
return TypeAnnotation.getTypeAnnotationsFromReader(
|
|
|
|
r,
|
|
|
|
TypeAnnotation.targetConverterAtClassFile(clRef),
|
|
|
|
clRef
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private TypeAnnotationsReader getTypeAnnotationsReader(boolean runtimeInvisible) throws InvalidClassFileException {
|
|
|
|
ClassReader r = reader.get();
|
|
|
|
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
|
|
|
r.initClassAttributeIterator(attrs);
|
|
|
|
|
|
|
|
return TypeAnnotationsReader.getReaderForAnnotationAtClassfile(
|
|
|
|
runtimeInvisible ? TypeAnnotationsReader.AnnotationType.RuntimeInvisibleTypeAnnotations
|
|
|
|
: TypeAnnotationsReader.AnnotationType.RuntimeVisibleTypeAnnotations,
|
|
|
|
attrs,
|
|
|
|
getSignatureReader(-1)
|
|
|
|
);
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
|
2017-01-20 00:12:22 +00:00
|
|
|
interface GetReader<T> {
|
|
|
|
T getReader(ClassReader.AttrIterator iter) throws InvalidClassFileException;
|
|
|
|
}
|
|
|
|
|
|
|
|
<T> T getReader(ClassReader.AttrIterator iter, String attrName, GetReader<T> reader) {
|
|
|
|
// search for the attribute
|
|
|
|
try {
|
|
|
|
for (; iter.isValid(); iter.advance()) {
|
|
|
|
if (iter.getName().equals(attrName)) {
|
|
|
|
return reader.getReader(iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
private InnerClassesReader getInnerClassesReader() throws InvalidClassFileException {
|
|
|
|
ClassReader r = reader.get();
|
|
|
|
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
|
|
|
r.initClassAttributeIterator(attrs);
|
|
|
|
|
|
|
|
// search for the desired attribute
|
|
|
|
InnerClassesReader result = null;
|
|
|
|
try {
|
|
|
|
for (; attrs.isValid(); attrs.advance()) {
|
|
|
|
if (attrs.getName().equals("InnerClasses")) {
|
|
|
|
result = new InnerClassesReader(attrs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-01-20 00:12:22 +00:00
|
|
|
SourceFileReader getSourceFileReader() {
|
|
|
|
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
|
|
|
getReader().initClassAttributeIterator(attrs);
|
|
|
|
|
|
|
|
return getReader(attrs, "SourceFile", new GetReader<SourceFileReader>() {
|
|
|
|
@Override
|
|
|
|
public SourceFileReader getReader(AttrIterator iter) throws InvalidClassFileException {
|
|
|
|
return new SourceFileReader(iter);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-04-08 20:50:26 +00:00
|
|
|
private AnnotationsReader getFieldAnnotationsReader(boolean runtimeInvisible, int fieldIndex) throws InvalidClassFileException {
|
2012-09-04 22:56:05 +00:00
|
|
|
ClassReader.AttrIterator iter = new AttrIterator();
|
|
|
|
reader.get().initFieldAttributeIterator(fieldIndex, iter);
|
|
|
|
|
2013-06-28 15:00:31 +00:00
|
|
|
return AnnotationsReader.getReaderForAnnotation(runtimeInvisible ? AnnotationType.RuntimeInvisibleAnnotations
|
|
|
|
: AnnotationType.RuntimeVisibleAnnotations, iter);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read the runtime-invisible annotations from the class file
|
|
|
|
*/
|
|
|
|
public Collection<Annotation> getRuntimeInvisibleAnnotations(int fieldIndex) throws InvalidClassFileException {
|
2013-04-08 20:50:26 +00:00
|
|
|
return getFieldAnnotations(fieldIndex, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read the runtime-invisible annotations from the class file
|
|
|
|
*/
|
|
|
|
public Collection<Annotation> getRuntimeVisibleAnnotations(int fieldIndex) throws InvalidClassFileException {
|
|
|
|
return getFieldAnnotations(fieldIndex, false);
|
|
|
|
}
|
2013-06-28 15:00:31 +00:00
|
|
|
|
2013-04-08 20:50:26 +00:00
|
|
|
protected Collection<Annotation> getFieldAnnotations(int fieldIndex, boolean runtimeInvisible) throws InvalidClassFileException {
|
|
|
|
AnnotationsReader r = getFieldAnnotationsReader(runtimeInvisible, fieldIndex);
|
2012-09-04 22:56:05 +00:00
|
|
|
return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference());
|
|
|
|
}
|
2016-12-02 12:31:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private TypeAnnotationsReader getFieldTypeAnnotationsReader(boolean runtimeInvisible, int fieldIndex) throws InvalidClassFileException {
|
|
|
|
ClassReader.AttrIterator iter = new AttrIterator();
|
|
|
|
reader.get().initFieldAttributeIterator(fieldIndex, iter);
|
|
|
|
|
|
|
|
return TypeAnnotationsReader.getReaderForAnnotationAtFieldInfo(
|
|
|
|
runtimeInvisible ? TypeAnnotationsReader.AnnotationType.RuntimeInvisibleTypeAnnotations
|
|
|
|
: TypeAnnotationsReader.AnnotationType.RuntimeVisibleTypeAnnotations,
|
|
|
|
iter
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* read the runtime-invisible type annotations from the class file
|
|
|
|
*/
|
|
|
|
public Collection<TypeAnnotation> getRuntimeInvisibleTypeAnnotations(int fieldIndex) throws InvalidClassFileException {
|
|
|
|
return getFieldTypeAnnotations(fieldIndex, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read the runtime-visible type annotations from the class file
|
|
|
|
*/
|
|
|
|
public Collection<TypeAnnotation> getRuntimeVisibleTypeAnnotations(int fieldIndex) throws InvalidClassFileException {
|
|
|
|
return getFieldTypeAnnotations(fieldIndex, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Collection<TypeAnnotation> getFieldTypeAnnotations(int fieldIndex, boolean runtimeInvisible) throws InvalidClassFileException {
|
|
|
|
TypeAnnotationsReader r = getFieldTypeAnnotationsReader(runtimeInvisible, fieldIndex);
|
|
|
|
final ClassLoaderReference clRef = getClassLoader().getReference();
|
|
|
|
return TypeAnnotation.getTypeAnnotationsFromReader(
|
|
|
|
r,
|
|
|
|
TypeAnnotation.targetConverterAtFieldInfo(clRef),
|
|
|
|
clRef
|
|
|
|
);
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
|
2015-09-16 17:23:21 +00:00
|
|
|
private SignatureReader getSignatureReader(int index) throws InvalidClassFileException {
|
2012-09-04 22:56:05 +00:00
|
|
|
ClassReader r = reader.get();
|
|
|
|
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
2015-09-16 17:23:21 +00:00
|
|
|
if (index == -1) {
|
|
|
|
r.initClassAttributeIterator(attrs);
|
|
|
|
} else {
|
|
|
|
r.initFieldAttributeIterator(index, attrs);
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
// search for the desired attribute
|
|
|
|
SignatureReader result = null;
|
|
|
|
try {
|
|
|
|
for (; attrs.isValid(); attrs.advance()) {
|
|
|
|
if (attrs.getName().toString().equals("Signature")) {
|
|
|
|
result = new SignatureReader(attrs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (InvalidClassFileException e) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ClassSignature getClassSignature() throws InvalidClassFileException {
|
|
|
|
// TODO: cache this later?
|
2015-09-16 17:23:21 +00:00
|
|
|
SignatureReader r = getSignatureReader(-1);
|
2012-09-04 22:56:05 +00:00
|
|
|
if (r == null) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
return ClassSignature.make(r.getSignature());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ModuleEntry getModuleEntry() {
|
|
|
|
return reader.getModuleEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-06-28 15:00:31 +00:00
|
|
|
* Does the class file indicate that this class is a member of some other
|
|
|
|
* class?
|
2012-09-04 22:56:05 +00:00
|
|
|
*
|
|
|
|
* @throws InvalidClassFileException
|
|
|
|
*/
|
|
|
|
public boolean isInnerClass() throws InvalidClassFileException {
|
|
|
|
InnerClassesReader r = getInnerClassesReader();
|
|
|
|
if (r != null) {
|
|
|
|
for (String s : r.getInnerClasses()) {
|
|
|
|
if (s.equals(getName().toString().substring(1))) {
|
|
|
|
String outer = r.getOuterClass(s);
|
|
|
|
return outer != null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does the class file indicate that this class is a static inner class?
|
|
|
|
*
|
|
|
|
* @throws InvalidClassFileException
|
|
|
|
*/
|
|
|
|
public boolean isStaticInnerClass() throws InvalidClassFileException {
|
|
|
|
InnerClassesReader r = getInnerClassesReader();
|
|
|
|
if (r != null) {
|
|
|
|
for (String s : r.getInnerClasses()) {
|
|
|
|
if (s.equals(getName().toString().substring(1))) {
|
|
|
|
String outer = r.getOuterClass(s);
|
|
|
|
if (outer != null) {
|
|
|
|
int modifiers = r.getAccessFlags(s);
|
|
|
|
boolean result = ((modifiers & Constants.ACC_STATIC) != 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-28 15:00:31 +00:00
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
/**
|
2013-06-28 15:00:31 +00:00
|
|
|
* If this is an inner class, return the outer class. Else return null.
|
|
|
|
*
|
|
|
|
* @throws InvalidClassFileException
|
2012-09-04 22:56:05 +00:00
|
|
|
*/
|
|
|
|
public TypeReference getOuterClass() throws InvalidClassFileException {
|
|
|
|
if (!isInnerClass()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
InnerClassesReader r = getInnerClassesReader();
|
|
|
|
for (String s : r.getInnerClasses()) {
|
|
|
|
if (s.equals(getName().toString().substring(1))) {
|
|
|
|
String outer = r.getOuterClass(s);
|
|
|
|
if (outer != null) {
|
|
|
|
return TypeReference.findOrCreate(getClassLoader().getReference(), "L" + outer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2013-06-28 15:00:31 +00:00
|
|
|
|
|
|
|
@Override
|
2013-06-25 15:53:58 +00:00
|
|
|
public Module getContainer() {
|
|
|
|
return reader.getModuleEntry().getContainer();
|
|
|
|
}
|
2017-02-03 01:33:27 +00:00
|
|
|
}
|