Commit 4c656fe9 authored by pcregut's avatar pcregut

[Bug 316340]

- Changes to InnerClass annotation: creation of an explicit MemberClass annotation (no more test if name is null, this was wrong for named inner classes)
- InnerClass name computed from the real name of the class. It cannot be recomputed on named InnerClasses.
- Propagation of the MemberClass annotation to the structure of asmdex (tree visitor, logelements, etc.)
- Modification of the test case structure to get more visibility on what is wrong (parameterized test suite)
- Updated Junit.
- Added test case for Inner and Member class covering all the known variants (static or not, named or not, member not inner).
parent 6d2068cf
......@@ -4,6 +4,6 @@
<classpathentry kind="src" path="test/conform"/>
<classpathentry kind="src" path="test/perf"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="lib" path="lib/junit-4.8.2.jar"/>
<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
......@@ -577,7 +577,7 @@ public class ApplicationReader {
// Visits the inner class, if any.
if (classAnnotationsOffset != 0) {
dexFile.seek(classAnnotationsOffset); // Get to the annotation_set_item.
readInnerClassAnnotations(classVisitor);
readInnerClassAnnotations(className, classVisitor);
dexFile.seek(classAnnotationsOffset);
readMemberClassesAnnotations(classVisitor);
......@@ -1342,7 +1342,8 @@ public class ApplicationReader {
// Obfuscators may remove mention of the inner name. We must cope with it.
String outerName =
(i<0) ? null : name.substring(0, i) + ";"; // Adds the ";" at the end.
classVisitor.visitInnerClass(name, outerName, innerName, accessFlags);
// classVisitor.visitInnerClass(name, outerName, innerName, accessFlags);
classVisitor.visitMemberClass(name, outerName, innerName);
}
}
}
......@@ -1351,9 +1352,10 @@ public class ApplicationReader {
* Reads the Annotations, check only the ones related to inner classes
* (EnclosingClass, InnerClasses), and call the visitInnerClass accordingly.
* The dex file reader must point on an annotation_set_item.
* @param className
* @param classVisitor the visitor to visit the inner class.
*/
private void readInnerClassAnnotations(ClassVisitor classVisitor) {
private void readInnerClassAnnotations(String className, ClassVisitor classVisitor) {
// Creates the InnerClass and EnclosingClass Parsers and makes the search for these
// specific annotations in the annotations.
......@@ -1373,17 +1375,9 @@ public class ApplicationReader {
EnclosingClassSpecificAnnotationParser enclosingParser = (EnclosingClassSpecificAnnotationParser)enclosingClassSpecificAnnotationParser;
// Gets the information.
//int classId = enclosingParser.getClassId();
//String outerClassName = dexFile.getStringItemFromTypeIndex(classId);
String outerClassName = enclosingParser.getClassName();
String simpleNameInnerClass = innerParser.getSimpleNameInnerClass();
String nameInnerClass = null;
// Reconstruction of the name of the inner class.
if ((simpleNameInnerClass != null) && (outerClassName != null)) {
nameInnerClass = outerClassName.replace(';', '$') + simpleNameInnerClass + ';';
}
classVisitor.visitInnerClass(nameInnerClass, outerClassName, simpleNameInnerClass, innerParser.getAccessFlagsInnerClass());
classVisitor.visitInnerClass(className, outerClassName, simpleNameInnerClass, innerParser.getAccessFlagsInnerClass());
}
}
......@@ -1431,10 +1425,16 @@ public class ApplicationReader {
String outerClassName = dexFile.getNameFromMethodIndex(methodId);
String nameInnerClass = null;
// Reconstruction the name of the inner class.
/*
if ((nameEnclosingClass != null) && (simpleNameInnerClass != null) && (outerClassName != null)) {
nameInnerClass = nameEnclosingClass.replace(';', '$') + '1' + simpleNameInnerClass;
}
classVisitor.visitInnerClass(nameInnerClass, outerClassName, simpleNameInnerClass, innerParser.getAccessFlagsInnerClass());
*/
if ((nameEnclosingClass != null) && (simpleNameInnerClass != null) && (outerClassName != null)) {
nameInnerClass = nameEnclosingClass.replace(';', '$') + '1' + simpleNameInnerClass + ";";
}
classVisitor.visitInnerClass(nameInnerClass, nameEnclosingClass, simpleNameInnerClass, innerParser.getAccessFlagsInnerClass());
}
}
......
......@@ -211,6 +211,22 @@ public abstract class ClassVisitor {
}
}
/**
* Visits information about a member class.
*
* @param outerName the internal name of the class to which the member class
* belongs.
* @param innerName the (simple) name of the member class inside its
* enclosing class.
*/
public void visitMemberClass(
String name,
String outerName,
String innerName) {
if (cv != null) {
cv.visitMemberClass(name,outerName, innerName);
}
}
/**
* Visits a field of the class.
*
......
......@@ -52,457 +52,449 @@ import org.ow2.asmdex.structureWriter.Method;
*/
public class ClassWriter extends ClassVisitor {
/**
* The Application Writer of this Class Writer. It is only useful for the optimization that consists
* in copying the Constant Pool and skips the visit of Methods that aren't transformed by any Adapter.
*/
private ApplicationWriter applicationWriter;
/**
* The Constant Pool of the Application.
*/
private ConstantPool constantPool;
/**
* Contains all the information of the Class.
*/
private ClassDefinitionItem classDefinitionItem;
/**
* Stores the Method this is linked to, if any, which means the current Class is defined in this Method
* body. This Method is set by visitOuterClass and is never reset after as, according to the documentation,
* a Class may have either of an EnclosingClass or EnclosingMethod annotation.
*/
private Method enclosingMethod = null;
/**
* Constructor.
* @param applicationWriter the Application Writer.
* @param constantPool the constantPool of the Application.
* @param access the access flags of the class.
* @param name the name of the class.
* @param signature the signature of the class. Used only for generics. May be null.
* @param superName the name of the super class.
* @param interfaces the name of the interfaces of the class.
*/
public ClassWriter(ApplicationWriter applicationWriter, ConstantPool constantPool, int access,
String name, String[] signature, String superName, String[] interfaces) {
super(Opcodes.ASM4);
this.applicationWriter = applicationWriter;
this.constantPool = constantPool;
classDefinitionItem = constantPool.addClassToConstantPool(name, superName, access,
interfaces, signature);
}
// -----------------------------------------------------
// Getters and Setters.
// -----------------------------------------------------
/**
* Returns the ApplicationWriter of this Class Writer.
*/
public ApplicationWriter getApplicationWriter() {
return applicationWriter;
}
/**
* Returns the name of the Class.
* @return the name of the Class.
*/
public String getName() {
return classDefinitionItem.getClassName();
}
/**
* Returns the current class definition item.
* @return the current class definition item.
*/
public ClassDefinitionItem getClassDefinitionItem() {
return classDefinitionItem;
}
/**
* Returns the Constant Pool related to this Application.
* @return the Constant Pool related to this Application.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
// -----------------------------------------------------
// Visitor methods.
// -----------------------------------------------------
@Override
public void visit(int version, int access, String name, String[] signature,
String superName, String[] interfaces) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.print(" ClassWriter : visit. Name = " + name
+ ", SuperClassName = " + superName
);
if (interfaces != null) {
System.out.print(". Interfaces = ");
for (int i = 0; i < interfaces.length; i++) {
System.out.print(interfaces[i] + ", ");
}
}
if (signature != null) {
System.out.print(". Signature = ");
for (int i = 0; i < signature.length; i++) {
System.out.print(signature[i] + ", ");
}
}
System.out.println();
}
// Creates the Signature Annotation if it exists.
// Note that we use the signature that was *already* set by the ApplicationWriter, not the one
// that is just given, even though they should be the same.
String[] savedSignature = classDefinitionItem.getSignature();
if (savedSignature != null) {
int size = savedSignature.length;
if (size > 0) {
AnnotationVisitor av = visitAnnotation(Constants.SIGNATURE_ANNOTATION_INTERNAL_NAME, false);
AnnotationVisitor subAv = av.visitArray(Constants.VALUE_STRING);
for (String string : savedSignature) {
subAv.visit(null, string);
}
subAv.visitEnd();
av.visitEnd();
}
}
}
@Override
public void visitSource(String source, String debug) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitSource. Source = " + source);
}
classDefinitionItem.setSourceFileName(source);
constantPool.addStringToConstantPool(source);
}
@Override
public void visitEnd() {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitEnd.");
}
// Checks if the MemberClass array is Null. If not, we create a dalvik.annotation.MemberClasses around it
// and adds it as an Class Annotation.
EncodedValueArray array = classDefinitionItem.getMemberClassArray();
if (array != null) {
String val = Constants.VALUE_STRING;
constantPool.addStringToConstantPool(val);
constantPool.addTypeToConstantPool(Constants.MEMBER_CLASSES_ANNOTATION_INTERNAL_NAME);
AnnotationItem annotationItem = new AnnotationItem(Opcodes.VISIBILITY_SYSTEM,
Constants.MEMBER_CLASSES_ANNOTATION_INTERNAL_NAME);
AnnotationElement annotationElement = new AnnotationElement(val, array);
annotationItem.addAnnotationElement(annotationElement);
classDefinitionItem.addAnnotationItem(annotationItem);
constantPool.addAnnotationItemToConstantPool(annotationItem);
}
// Checks if the Class contains Default Annotations. If yes, we have to create <i>ONE</i>
// AnnotationItem regrouping them.
List<AnnotationItem> defaultAnnotationItems = classDefinitionItem.getAnnotationItemsForDefaultAnnotation();
if ((defaultAnnotationItems != null) && (defaultAnnotationItems.size() > 0)) {
EncodedValueAnnotation createdEncodedValueAnnotation = null;
String encodedAnnotationType = null;
for (AnnotationItem annotationItems : defaultAnnotationItems) {
// There should only one AnnotationElement, but we make a loop for security.
for (AnnotationElement currentElement : annotationItems.getAnnotationElements()) {
EncodedValueAnnotation currentEncodedValue = (EncodedValueAnnotation)currentElement.getEncodedValue();
encodedAnnotationType = currentEncodedValue.getAnnotationType();
if (createdEncodedValueAnnotation == null) {
createdEncodedValueAnnotation = new EncodedValueAnnotation(encodedAnnotationType);
}
// There should be one AnnotationElement in the Annotation, but we make a loop for security.
for (AnnotationElement currentAnnotationElement : currentEncodedValue.getAnnotationElements()) {
createdEncodedValueAnnotation.addAnnotationElement(currentAnnotationElement);
}
}
}
// We set up the DefaultAnnotation we need to create.
AnnotationItem createdAnnotationItem = new AnnotationItem(Opcodes.VISIBILITY_SYSTEM,
Constants.ANNOTATION_DEFAULT_INTERNAL_NAME);
// It consists of only one EncodedAnnotation, which has one AnnotationElement, of type "value"
// and of one EncodedValue of VALUE_ANNOTATION type.
AnnotationElement createdAnnotationElement = new AnnotationElement(Constants.VALUE_STRING, createdEncodedValueAnnotation);
createdAnnotationItem.addAnnotationElement(createdAnnotationElement);
// Adds the newly created AnnotationItem to the Constant Pool and to the Class.
classDefinitionItem.addAnnotationItem(createdAnnotationItem);
constantPool.addAnnotationItemToConstantPool(createdAnnotationItem);
}
// Now that the annotation_set_item are fully known, we can register it to the Constant Pool.
constantPool.addAnnotationSetItemToConstantPool(classDefinitionItem.getAnnotationSetItem());
// We also build the annotation_directory_item.
classDefinitionItem.buildAnnotationDirectoryItem();
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String[] signature, String[] exceptions) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.print(" ClassWriter : visitMethod. Access = " + access +
", Name = " + name + ", Desc = " + desc);
if (signature != null) {
System.out.print(". Signature = ");
for (String sig : signature) {
System.out.print(sig +", ");
}
}
if (exceptions != null) {
System.out.print(". Exceptions = ");
for (String exception : exceptions) {
System.out.print(exception +", ");
}
}
System.out.println();
}
MethodWriter methodWriter = new MethodWriter(this, access, name, desc, signature, exceptions);
// Registers the method to the Class. It may be virtual or direct.
Method method = methodWriter.getMethod();
classDefinitionItem.addMethod(method);
// If the Method is using This (non static and non constructor), the String "this" is added to the
// Constant Pool.
if (method.isUsingThis()) {
constantPool.addStringToConstantPool(Constants.THIS_STRING);
}
// Manages the Signature Annotation if it exists.
String[] savedSignature = method.getSignature();
if (savedSignature != null) {
int size = savedSignature.length;
if (size > 0) {
AnnotationVisitor av = methodWriter.visitAnnotation(Constants.SIGNATURE_ANNOTATION_INTERNAL_NAME, false);
AnnotationVisitor subAv = av.visitArray(Constants.VALUE_STRING);
for (String string : savedSignature) {
subAv.visit(null, string);
}
subAv.visitEnd();
av.visitEnd();
}
}
// If there are exceptions, we need to create a dalvik.annotation.Throws annotation.
// It consists of an Array Annotation with the type of the Exceptions as elements.
if ((exceptions != null) && (exceptions.length > 0)) {
String valString = Constants.VALUE_STRING;
constantPool.addStringToConstantPool(valString);
constantPool.addTypeToConstantPool(Constants.EXCEPTION_ANNOTATION_INTERNAL_NAME);
EncodedValueArray array = new EncodedValueArray();
for (String exception : exceptions) {
constantPool.addTypeToConstantPool(exception);
EncodedValue value = new EncodedValueType(exception);
array.addEncodedValue(value);
}
AnnotationElement annotationElement = new AnnotationElement(valString, array);
AnnotationItem annotationItem = new AnnotationItem(Opcodes.VISIBILITY_SYSTEM,
Constants.EXCEPTION_ANNOTATION_INTERNAL_NAME);
annotationItem.addAnnotationElement(annotationElement);
method.addAnnotationItem(annotationItem);
constantPool.addAnnotationItemToConstantPool(annotationItem);
}
return methodWriter;
}
@Override
public FieldVisitor visitField(int access, String name, String desc,
String[] signature, Object value) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.print(" ClassWriter : visitField. Access = " + access +
", Name = " + name + ", Desc = " + desc + ", value = " + value
);
if (signature != null) {
System.out.print(". Signature = ");
for (String sig : signature) {
System.out.print(sig +", ");
}
}
System.out.println();
}
FieldWriter fieldWriter = new FieldWriter(constantPool, getName(), access, name, desc,
signature, value);
// Registers the Field to the Class. It may be a static or instance Field.
Field field = fieldWriter.getField();
classDefinitionItem.addField(field);
// Manages the Signature Annotation if it exists.
String[] savedSignature = field.getSignature();
if (savedSignature != null) {
int size = savedSignature.length;
if (size > 0) {
AnnotationVisitor av = fieldWriter.visitAnnotation(Constants.SIGNATURE_ANNOTATION_INTERNAL_NAME, false);
AnnotationVisitor subAv = av.visitArray(Constants.VALUE_STRING);
for (String string : savedSignature) {
subAv.visit(null, string);
}
subAv.visitEnd();
av.visitEnd();
}
}
return fieldWriter;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitAnnotation. Desc = " + desc +
", visible = " + visible
);
}
// Creates an AnnotationItem, incomplete for now (no Elements), and registers it to the Class.
// We do not add it to the Constant Pool now because of this incompleteness.
AnnotationWriter annotationWriter = AnnotationWriter.createAnnotationWriter(desc, visible, constantPool, null);
classDefinitionItem.addAnnotationItem(annotationWriter.getAnnotationItem());
return annotationWriter;
}
@Override
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitInnerClass. Name = " + name
+ ", outerName = " + outerName
+ ", innerName = " + innerName
+ ", access = " + access
);
}
// Register all the given data to the ConstantPool. If the name is Null, the OuterName
// is not a Type, but just a String.
if (name == null) {
constantPool.addStringToConstantPool(outerName);
} else {
constantPool.addTypeToConstantPool(name);
constantPool.addTypeToConstantPool(outerName);
constantPool.addStringToConstantPool(innerName);
}
// According to the given parameters, we can know if we're visiting an Inner Class, or if
// we're declaring them. If the name of the InnerClass is the same as the current Class, we're
// visiting it.
// Also, if name is Null means an anonymous class.
if ((name == null) || (name.equals(classDefinitionItem.getClassName()))) {
// We're inside an Inner Class, visiting it.
// Two annotations need to be created. The Enclosing Class/Method, and the Inner Class.
// If the enclosingMethod reference is null, we create an Enclosing Class, else an Enclosing
// Method.
// Encodes the first annotation : Enclosing Class or Enclosing Method.
boolean isEnclosingClass = (enclosingMethod == null);
String annotationType = (isEnclosingClass ? Constants.ENCLOSING_CLASS_ANNOTATION_INTERNAL_NAME :
Constants.ENCLOSING_METHOD_ANNOTATION_INTERNAL_NAME);
String val = Constants.VALUE_STRING;
constantPool.addStringToConstantPool(val);
constantPool.addTypeToConstantPool(annotationType);
AnnotationItem annotationItem = new AnnotationItem(Opcodes.VISIBILITY_SYSTEM, annotationType);
EncodedValue encodedValue;
if (isEnclosingClass) {
// Enclosing Class.
encodedValue = EncodedValueFactory.getEncodedValue(outerName, Opcodes.VALUE_TYPE);
} else {
// Enclosing Method.
encodedValue = EncodedValueFactory.getEncodedValue(enclosingMethod, Opcodes.VALUE_METHOD);
}
AnnotationElement annotationElement = new AnnotationElement(val, encodedValue);
annotationItem.addAnnotationElement(annotationElement);
constantPool.addAnnotationItemToConstantPool(annotationItem);
classDefinitionItem.addAnnotationItem(annotationItem);
// Encodes the second annotation : the Inner Class.
annotationItem = new AnnotationItem(Opcodes.VISIBILITY_SYSTEM,
Constants.INNER_CLASS_ANNOTATION_INTERNAL_NAME);
// Encodes the "name".
val = Constants.NAME_STRING;
constantPool.addStringToConstantPool(val);
constantPool.addTypeToConstantPool(Constants.INNER_CLASS_ANNOTATION_INTERNAL_NAME);
// According to the documentation, if the class is anonymous, the name becomes a Null value.
if (name == null) {
encodedValue = EncodedValueFactory.getEncodedNullValue();
} else {
encodedValue = EncodedValueFactory.getEncodedValue(innerName, Opcodes.VALUE_STRING);
}
annotationElement = new AnnotationElement(val, encodedValue);
annotationItem.addAnnotationElement(annotationElement);
// Encodes the "accessFlags".
val = Constants.ACCESS_FLAGS_STRING;
constantPool.addStringToConstantPool(val);
encodedValue = EncodedValueFactory.getEncodedValue(access, Opcodes.VALUE_INT);
annotationElement = new AnnotationElement(val, encodedValue);
annotationItem.addAnnotationElement(annotationElement);
constantPool.addAnnotationItemToConstantPool(annotationItem);
classDefinitionItem.addAnnotationItem(annotationItem);
} else {
// We're declaring an Inner Class.
// One annotation needs to be created, the MemberClasses Annotation.
// However, we don't create it now because it needs may be filled by several calls to
// the visitInnerClass() method. On the first call, we create an Encoded Array which we store.
// On each call, we add the newly reference to an Inner Class inside this Array.
// When the class visit has ended, we test if the Array exists. If yes, we build an annotation around
// it, and adds to the Class and the Constant Pool.
classDefinitionItem.addMemberClassValue(name, constantPool);
}
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitOuterClass. Name = " + name
+ ", owner = " + owner
+ ", desc = " + desc
);
}
// We found a reference to a Method. This Method could have been found before, or
// not, in which case Constant Pool adds it.
// We store this Method, which means that the next visitInnerClass will take it in account, generating
// a Enclosing Method annotation instead of a Enclosing Class annotation.
enclosingMethod = constantPool.addMethodToConstantPool(name, owner, desc, Opcodes.ACC_UNKNOWN, null, null);
}
@Override
public void visitAttribute(Object attr) {
// This method is ignored, as Attributes are not supported by AsmDex.
}
/**
* The Application Writer of this Class Writer. It is only useful for the optimization that consists
* in copying the Constant Pool and skips the visit of Methods that aren't transformed by any Adapter.
*/
private ApplicationWriter applicationWriter;
/**
* The Constant Pool of the Application.
*/
private ConstantPool constantPool;
/**
* Contains all the information of the Class.
*/
private ClassDefinitionItem classDefinitionItem;
/**
* Stores the Method this is linked to, if any, which means the current Class is defined in this Method
* body. This Method is set by visitOuterClass and is never reset after as, according to the documentation,
* a Class may have either of an EnclosingClass or EnclosingMethod annotation.
*/
private Method enclosingMethod = null;
/**
* Constructor.
* @param applicationWriter the Application Writer.
* @param constantPool the constantPool of the Application.
* @param access the access flags of the class.
* @param name the name of the class.
* @param signature the signature of the class. Used only for generics. May be null.
* @param superName the name of the super class.
* @param interfaces the name of the interfaces of the class.
*/
public ClassWriter(ApplicationWriter applicationWriter, ConstantPool constantPool, int access,
String name, String[] signature, String superName, String[] interfaces) {
super(Opcodes.ASM4);
this.applicationWriter = applicationWriter;
this.constantPool = constantPool;
classDefinitionItem = constantPool.addClassToConstantPool(name, superName, access,
interfaces, signature);
}
// -----------------------------------------------------
// Getters and Setters.
// -----------------------------------------------------
/**
* Returns the ApplicationWriter of this Class Writer.
*/
public ApplicationWriter getApplicationWriter() {
return applicationWriter;
}
/**
* Returns the name of the Class.
* @return the name of the Class.
*/
public String getName() {
return classDefinitionItem.getClassName();
}
/**
* Returns the current class definition item.
* @return the current class definition item.
*/
public ClassDefinitionItem getClassDefinitionItem() {
return classDefinitionItem;
}
/**
* Returns the Constant Pool related to this Application.
* @return the Constant Pool related to this Application.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
// -----------------------------------------------------
// Visitor methods.
// -----------------------------------------------------
@Override
public void visit(int version, int access, String name, String[] signature,
String superName, String[] interfaces) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.print(" ClassWriter : visit. Name = " + name
+ ", SuperClassName = " + superName
);
if (interfaces != null) {
System.out.print(". Interfaces = ");
for (int i = 0; i < interfaces.length; i++) {
System.out.print(interfaces[i] + ", ");
}
}
if (signature != null) {
System.out.print(". Signature = ");
for (int i = 0; i < signature.length; i++) {
System.out.print(signature[i] + ", ");
}
}
System.out.println();
}
// Creates the Signature Annotation if it exists.
// Note that we use the signature that was *already* set by the ApplicationWriter, not the one
// that is just given, even though they should be the same.
String[] savedSignature = classDefinitionItem.getSignature();
if (savedSignature != null) {
int size = savedSignature.length;
if (size > 0) {
AnnotationVisitor av = visitAnnotation(Constants.SIGNATURE_ANNOTATION_INTERNAL_NAME, false);
AnnotationVisitor subAv = av.visitArray(Constants.VALUE_STRING);
for (String string : savedSignature) {
subAv.visit(null, string);
}
subAv.visitEnd();
av.visitEnd();
}
}
}
@Override
public void visitSource(String source, String debug) {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitSource. Source = " + source);
}
classDefinitionItem.setSourceFileName(source);
constantPool.addStringToConstantPool(source);
}
@Override
public void visitEnd() {
if (ApplicationWriter.DISPLAY_WRITER_INFORMATION) {
System.out.println(" ClassWriter : visitEnd.");
}
// Checks if the MemberClass array is Null. If not, we create a dalvik.annotation.MemberClasses around it
// and adds it as an Class Annotation.
EncodedValueArray array = classDefinitionItem.getMemberClassArray();
if (array != null) {
String val = Constants.VALUE_STRING;
constantPool.addStringToConstantPool(val);
constantPool.addTypeToConstantPool(Constants.MEMBER_CLASSES_ANNOTATION_INTERNAL_NAME);
AnnotationItem annotationItem = new AnnotationItem(Opcodes.VISIBILITY_SYSTEM,
Constants.MEMBER_CLASSES_ANNOTATION_INTERNAL_NAME);
AnnotationElement annotationElement = new AnnotationElement(val, array);
annotationItem.addAnnotationElement(annotationElement);
classDefinitionItem.addAnnotationItem(annotationItem);
constantPool.addAnnotationItemToConstantPool(annotationItem);
}
// Checks if the Class contains Default Annotations. If yes, we have to create <i>ONE</i>
// AnnotationItem regrouping them.
List<AnnotationItem> defaultAnnotationItems = classDefinitionItem.getAnnotationItemsForDefaultAnnotation();
if ((defaultAnnotationItems != null) && (defaultAnnotationItems.size() > 0)) {
EncodedValueAnnotation createdEncodedValueAnnotation = null;