/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package signature.converter.dex;
import static signature.converter.dex.DexUtil.convertAnyWay;
import static signature.converter.dex.DexUtil.declaresExceptions;
import static signature.converter.dex.DexUtil.declaresMemberClasses;
import static signature.converter.dex.DexUtil.findPackageInfo;
import static signature.converter.dex.DexUtil.getClassModifiers;
import static signature.converter.dex.DexUtil.getClassName;
import static signature.converter.dex.DexUtil.getDefaultMappingsAnnotation;
import static signature.converter.dex.DexUtil.getDexName;
import static signature.converter.dex.DexUtil.getEnclosingClassName;
import static signature.converter.dex.DexUtil.getExceptionSignature;
import static signature.converter.dex.DexUtil.getGenericSignature;
import static signature.converter.dex.DexUtil.getKind;
import static signature.converter.dex.DexUtil.getMemberClassNames;
import static signature.converter.dex.DexUtil.getModifier;
import static signature.converter.dex.DexUtil.getPackageName;
import static signature.converter.dex.DexUtil.getQualifiedName;
import static signature.converter.dex.DexUtil.hasAnnotationDefaultSignature;
import static signature.converter.dex.DexUtil.hasGenericSignature;
import static signature.converter.dex.DexUtil.isAnnotation;
import static signature.converter.dex.DexUtil.isConstructor;
import static signature.converter.dex.DexUtil.isEnclosingClass;
import static signature.converter.dex.DexUtil.isEnum;
import static signature.converter.dex.DexUtil.isInternalAnnotation;
import static signature.converter.dex.DexUtil.isJavaLangObject;
import static signature.converter.dex.DexUtil.isMethod;
import static signature.converter.dex.DexUtil.isVisible;
import static signature.converter.dex.DexUtil.splitTypeList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import signature.converter.Visibility;
import signature.model.IAnnotation;
import signature.model.IAnnotationElement;
import signature.model.IAnnotationField;
import signature.model.IClassDefinition;
import signature.model.IClassReference;
import signature.model.IConstructor;
import signature.model.IEnumConstant;
import signature.model.IField;
import signature.model.IMethod;
import signature.model.IPackage;
import signature.model.IParameter;
import signature.model.ITypeReference;
import signature.model.ITypeVariableDefinition;
import signature.model.Kind;
import signature.model.Modifier;
import signature.model.impl.SigAnnotation;
import signature.model.impl.SigAnnotationElement;
import signature.model.impl.SigAnnotationField;
import signature.model.impl.SigApi;
import signature.model.impl.SigClassDefinition;
import signature.model.impl.SigClassReference;
import signature.model.impl.SigConstructor;
import signature.model.impl.SigEnumConstant;
import signature.model.impl.SigExecutableMember;
import signature.model.impl.SigField;
import signature.model.impl.SigMethod;
import signature.model.impl.SigPackage;
import signature.model.impl.SigParameter;
import signature.model.impl.Uninitialized;
import signature.model.util.TypePool;
import dex.structure.DexAnnotation;
import dex.structure.DexAnnotationAttribute;
import dex.structure.DexClass;
import dex.structure.DexEncodedAnnotation;
import dex.structure.DexEncodedValue;
import dex.structure.DexField;
import dex.structure.DexFile;
import dex.structure.DexMethod;
import dex.structure.DexParameter;
/**
* Converts a set of dex files to the signature compare api.
*/
public final class DexToSigConverter implements IClassInitializer {
private final FieldPool elementPool;
private final TypePool factory;
private static final Set<IField> EMPTY_FIELDS = Collections.emptySet();
private static final Set<IEnumConstant> EMPTY_ENUM_CONSTANTS = Collections
.emptySet();
private static final Set<IAnnotationField> EMPTY_ANNOTATION_FIELDS =
Collections.emptySet();
private static final List<ITypeVariableDefinition> EMPTY_TYPE_VARIABLES =
Collections.emptyList();
private static final Set<IClassDefinition> EMPTY_INNER_CLASSES =
Collections.emptySet();
private static final Set<ITypeReference> EMPTY_EXCEPTIONS = Collections
.emptySet();
private Visibility visibility;
private Map<String, DexClass> dexNameToDexClass;
/**
* Creates a new instance of {@link DexToSigConverter}.
*/
public DexToSigConverter() {
factory = new TypePool();
elementPool = new FieldPool();
}
public SigApi convertApi(String apiName, Set<DexFile> dexFiles,
Visibility visibility) {
this.visibility = visibility;
SigApi api = new SigApi(apiName, visibility);
api.setPackages(convertPackages(dexFiles));
factory.replaceAllUninitialiezWithNull();
return api;
}
/**
* Converts the given {@link DexFile}s into the corresponding (packages
* including their (classes and their members, etc.))E
*
* @param parsedFiles
* the dex files to convert
* @return the converted packages
*/
/* package */Set<IPackage> convertPackages(Set<DexFile> parsedFiles) {
Map<String, SigPackage> packageNameToPackage =
new HashMap<String, SigPackage>();
Map<SigPackage, Set<DexClass>> packageToDexClasses =
new HashMap<SigPackage, Set<DexClass>>();
dexNameToDexClass = new HashMap<String, DexClass>();
for (DexFile dexFile : parsedFiles) {
List<DexClass> definedClasses = dexFile.getDefinedClasses();
for (DexClass dexClass : definedClasses) {
dexNameToDexClass.put(dexClass.getName(), dexClass);
String dexName = dexClass.getName();
String packageName = getPackageName(dexName);
SigPackage aPackage = packageNameToPackage.get(packageName);
if (aPackage == null) {
aPackage = convertPackage(packageName);
packageNameToPackage.put(packageName, aPackage);
Set<DexClass> classes = new HashSet<DexClass>();
packageToDexClasses.put(aPackage, classes);
}
Set<DexClass> classes = packageToDexClasses.get(aPackage);
classes.add(dexClass);
}
}
Set<SigClassDefinition> allClasses = new HashSet<SigClassDefinition>();
for (SigPackage aPackage : packageToDexClasses.keySet()) {
Set<SigClassDefinition> classes = convertClasses(packageToDexClasses
.get(aPackage));
allClasses.addAll(classes);
aPackage.setClasses(new HashSet<IClassDefinition>(classes));
}
// remove package info
for (SigPackage aPackage : packageToDexClasses.keySet()) {
IClassDefinition packageInfo = findPackageInfo(aPackage);
if (packageInfo != null) {
aPackage.setAnnotations(packageInfo.getAnnotations());
aPackage.getClasses().remove(packageInfo);
}
}
// link enclosed classes only if they are part of visible api
for (SigClassDefinition sigClass : allClasses) {
String dexName = getDexName(sigClass);
DexClass dexClass = dexNameToDexClass.get(dexName);
if (declaresMemberClasses(dexClass)) {
Set<String> enclosedClassesNames =
getMemberClassNames(dexClass);
Set<IClassDefinition> memberClasses =
new HashSet<IClassDefinition>();
for (String enclosedClassName : enclosedClassesNames) {
SigClassDefinition memberClass = factory.getClass(
getPackageName(enclosedClassName),
getClassName(enclosedClassName));
// add inner class only if parsed
if (allClasses.contains(memberClass)) {
memberClasses.add(memberClass);
}
}
sigClass.setInnerClasses(memberClasses);
} else {
sigClass.setInnerClasses(EMPTY_INNER_CLASSES);
}
}
// remove inner classes, is outer class is not visible
for (SigClassDefinition sigClass : allClasses) {
if (hasInvisibleParent(sigClass, dexNameToDexClass)) {
SigPackage sigPackage = packageNameToPackage.get(sigClass
.getPackageName());
sigPackage.getClasses().remove(sigClass);
}
}
return new HashSet<IPackage>(packageToDexClasses.keySet());
}
private boolean hasInvisibleParent(IClassDefinition sigClass,
Map<String, DexClass> dexNameToDexClass) {
do {
String dexName = getDexName(sigClass);
DexClass dexClass = dexNameToDexClass.get(dexName);
if (isEnclosingClass(dexClass)) {
IClassDefinition declaringClass = sigClass.getDeclaringClass();
DexClass declaringDexClass = dexNameToDexClass
.get(getDexName(declaringClass));
if (!isVisible(declaringDexClass, visibility)) {
return true;
}
}
} while ((sigClass = sigClass.getDeclaringClass()) != null);
return false;
}
/**
* Converts a simple string to the corresponding {@link SigPackage}.<br>
* Format: "a.b.c"
*
* @param packageName
* the name of the package
* @return the package
*/
protected SigPackage convertPackage(String packageName) {
SigPackage sigPackage = new SigPackage(packageName);
return sigPackage;
}
/**
* Converts a set of {@link DexClass} objects to a set of the corresponding
* {@link SigClassDefinition} objects.
*
* @param dexClasses
* the {@link DexClass} objects
* @return a set of {@link DexClass} objects
*/
protected Set<SigClassDefinition> convertClasses(Set<DexClass> dexClasses) {
Set<SigClassDefinition> classes = new HashSet<SigClassDefinition>();
for (DexClass dexClass : dexClasses) {
// convert all classes but synthetic, return only initialized
if (convertAnyWay(dexClass)) {
SigClassDefinition sigCLass = convertClass(dexClass);
if (isVisible(dexClass, visibility)) {
classes.add(sigCLass);
}
}
}
return classes;
}
/**
* Converts a {@link DexClass} to the corresponding
* {@link SigClassDefinition}.
*
* @param dexClass
* the {@link DexClass} to convert
* @return the corresponding {@link SigClassDefinition}
*/
protected SigClassDefinition convertClass(DexClass dexClass) {
assert dexClass != null;
String packageName = getPackageName(dexClass.getName());
String className = getClassName(dexClass.getName());
SigClassDefinition sigClass = factory.getClass(packageName, className);
// Kind
sigClass.setKind(getKind(dexClass));
// modifiers
Set<Modifier> modifiers = getModifier(getClassModifiers(dexClass));
sigClass.setModifiers(modifiers);
if (isEnclosingClass(dexClass)) {
String declaringClassDexName = getEnclosingClassName(dexClass);
declaringClassDexName = getClassName(declaringClassDexName);
// declaring class is in same package
sigClass.setDeclaringClass(factory.getClass(sigClass
.getPackageName(), declaringClassDexName));
} else {
sigClass.setDeclaringClass(null);
}
if (hasGenericSignature(dexClass)) {
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
parser.parseForClass(sigClass, getGenericSignature(dexClass));
sigClass.setTypeParameters(parser.formalTypeParameters);
if (Kind.INTERFACE.equals(sigClass.getKind())) {
sigClass.setSuperClass(null);
} else {
sigClass.setSuperClass(parser.superclassType);
}
sigClass.setInterfaces(new HashSet<ITypeReference>(
parser.interfaceTypes));
} else {
// Type parameters
sigClass.setTypeParameters(EMPTY_TYPE_VARIABLES);
// java.lang.Object has no super class
if (isJavaLangObject(dexClass)) {
sigClass.setSuperClass(null);
} else {
if (Kind.INTERFACE.equals(sigClass.getKind())
|| Kind.ANNOTATION.equals(sigClass.getKind())) {
sigClass.setSuperClass(null);
} else {
String superClassPackageName = getPackageName(dexClass
.getSuperClass());
String superClassName = getClassName(dexClass
.getSuperClass());
sigClass.setSuperClass(factory.getClassReference(
superClassPackageName, superClassName));
}
}
List<String> interfaceDexNames = dexClass.getInterfaces();
Set<ITypeReference> interfaces = new HashSet<ITypeReference>();
for (String interfaceDexName : interfaceDexNames) {
String interfacePackageName = getPackageName(interfaceDexName);
String interfaceName = getClassName(interfaceDexName);
SigClassDefinition interfaze = factory.getClass(
interfacePackageName, interfaceName);
interfaze.setKind(Kind.INTERFACE);
interfaces.add(new SigClassReference(interfaze));
}
sigClass.setInterfaces(interfaces);
}
// constructors
Set<SigConstructor> constructors = convertConstructors(dexClass
.getMethods());
for (SigConstructor constructor : constructors) {
constructor.setDeclaringClass(sigClass);
}
sigClass.setConstructors(new HashSet<IConstructor>(constructors));
// methods
Set<SigMethod> methods = Collections.emptySet();
if (isAnnotation(dexClass)) {
Map<String, Object> mappings = getDefaultValueMapping(dexClass);
Set<SigAnnotationField> annotationFields = convertAnnotationFields(
dexClass.getMethods(), mappings);
sigClass.setAnnotationFields(new HashSet<IAnnotationField>(
annotationFields));
addAnnotationsToAnnotationFields(dexClass.getMethods(),
annotationFields);
sigClass.setEnumConstants(EMPTY_ENUM_CONSTANTS);
sigClass.setFields(EMPTY_FIELDS);
// sigClass.setAnnotationFields(new
// HashSet<IAnnotationField>(convertAnnotationFields(dexClass)));
} else if (isEnum(dexClass)) {
Set<IField> fields = new HashSet<IField>();
Set<IEnumConstant> enumConstants = new HashSet<IEnumConstant>();
for (DexField dexField : dexClass.getFields()) {
if (isVisible(dexField, visibility)) {
if (dexField.isEnumConstant()) {
enumConstants.add(convertEnumConstant(dexField));
} else {
fields.add(convertField(dexField));
}
}
}
sigClass.setFields(fields);
sigClass.setEnumConstants(enumConstants);
sigClass.setAnnotationFields(EMPTY_ANNOTATION_FIELDS);
methods = convertMethods(dexClass.getMethods());
} else {
// fields
sigClass.setFields(new HashSet<IField>(convertFields(dexClass
.getFields())));
sigClass.setEnumConstants(EMPTY_ENUM_CONSTANTS);
sigClass.setAnnotationFields(EMPTY_ANNOTATION_FIELDS);
methods = convertMethods(dexClass.getMethods());
}
for (SigMethod method : methods) {
method.setDeclaringClass(sigClass);
}
sigClass.setMethods(new HashSet<IMethod>(methods));
// Annotations
sigClass.setAnnotations(convertAnnotations(dexClass.getAnnotations()));
return sigClass;
}
@SuppressWarnings("unchecked")
private Map<String, Object> getDefaultValueMapping(DexClass dexClass) {
HashMap<String, Object> mappings = new HashMap<String, Object>();
if (hasAnnotationDefaultSignature(dexClass)) {
// read mapping to defaults from annotation
DexAnnotation annotation = getDefaultMappingsAnnotation(dexClass);
DexAnnotationAttribute dexAnnotationAttribute = annotation
.getAttributes().get(0);
if ("value".equals(dexAnnotationAttribute.getName())) {
DexEncodedValue encodedValue = dexAnnotationAttribute
.getEncodedValue();
DexEncodedValue value = (DexEncodedValue) encodedValue
.getValue();
List<DexAnnotationAttribute> defaults =
(List<DexAnnotationAttribute>) value.getValue();
for (DexAnnotationAttribute defaultAttribute : defaults) {
mappings.put(defaultAttribute.getName(),
convertEncodedValue(defaultAttribute
.getEncodedValue()));
}
}
}
return mappings;
}
private void addAnnotationsToAnnotationFields(List<DexMethod> methods,
Set<SigAnnotationField> annotationFields) {
Map<String, SigAnnotationField> nameToAnnotationField =
new HashMap<String, SigAnnotationField>();
for (SigAnnotationField annotationField : annotationFields) {
nameToAnnotationField.put(annotationField.getName(),
annotationField);
}
for (DexMethod method : methods) {
SigAnnotationField annotationField = nameToAnnotationField
.get(method.getName());
annotationField.setAnnotations(convertAnnotations(method
.getAnnotations()));
}
}
private Set<SigAnnotationField> convertAnnotationFields(
List<DexMethod> list, Map<String, Object> mappings) {
Set<SigAnnotationField> annotationfields =
new HashSet<SigAnnotationField>();
for (DexMethod dexMethod : list) {
if (isVisible(dexMethod, visibility)) {
annotationfields.add(convertAnnotationField(dexMethod, mappings
.get(dexMethod.getName())));
}
}
return annotationfields;
}
private SigAnnotationField convertAnnotationField(DexMethod dexMethod,
Object defaultValue) {
SigAnnotationField annotationField = new SigAnnotationField(dexMethod
.getName());
annotationField.setDefaultValue(defaultValue);
annotationField.setModifiers(getModifier(dexMethod.getModifiers()));
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
annotationField.setType(parser.parseNonGenericType(dexMethod
.getReturnType()));
return annotationField;
}
private IEnumConstant convertEnumConstant(DexField dexField) {
String qualifiedTypeName = getQualifiedName(dexField
.getDeclaringClass().getName());
SigEnumConstant enumConstant = elementPool.getEnumConstant(
qualifiedTypeName, dexField.getName());
Set<Modifier> modifiers = getModifier(dexField.getModifiers());
modifiers.add(Modifier.STATIC);
enumConstant.setModifiers(modifiers);
String typePackageName = getPackageName(dexField.getType());
String typeName = getClassName(dexField.getType());
enumConstant.setType(factory.getClassReference(typePackageName,
typeName));
enumConstant.setAnnotations(convertAnnotations(dexField
.getAnnotations()));
return enumConstant;
}
private Set<SigField> convertFields(List<DexField> dexFields) {
Set<SigField> fields = new HashSet<SigField>();
for (DexField dexField : dexFields) {
if (isVisible(dexField, visibility)) {
fields.add(convertField(dexField));
}
}
return fields;
}
private SigField convertField(DexField dexField) {
String qualTypeName = getQualifiedName(dexField.getDeclaringClass()
.getName());
SigField field = elementPool.getField(qualTypeName, dexField.getName());
field.setModifiers(getModifier(dexField.getModifiers()));
field.setAnnotations(convertAnnotations(dexField.getAnnotations()));
if (hasGenericSignature(dexField)) {
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
String declaringClassPackageName = getPackageName(dexField
.getDeclaringClass().getName());
String declaringClassName = getClassName(dexField
.getDeclaringClass().getName());
parser.parseForField(factory.getClass(declaringClassPackageName,
declaringClassName), getGenericSignature(dexField));
field.setType(parser.fieldType);
} else {
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
field.setType(parser.parseNonGenericType(dexField.getType()));
}
return field;
}
/**
* Converts a set of {@link DexMethod} to a set of corresponding
* {@link IConstructor}. This method ignores methods which are not
* constructors.
*
* @param methods
* the {@link DexMethod}s to convert
* @return the corresponding {@link IConstructor}s
*/
private Set<SigConstructor> convertConstructors(List<DexMethod> methods) {
Set<SigConstructor> constructors = new HashSet<SigConstructor>();
for (DexMethod method : methods) {
if (isConstructor(method) && isVisible(method, visibility)) {
constructors.add(convertConstructor(method));
}
}
return constructors;
}
/**
* Converts a set of {@link DexMethod} to a set of corresponding
* {@link DexMethod}. This method ignores methods which are constructors.
*
* @param methods
* the {@link DexMethod}s to convert
* @return the corresponding {@link IConstructor}s
*/
private Set<SigMethod> convertMethods(List<DexMethod> methods) {
Set<SigMethod> sigMethods = new HashSet<SigMethod>();
for (DexMethod method : methods) {
if (isMethod(method) && isVisible(method, visibility)) {
sigMethods.add(convertMethod(method));
}
}
return sigMethods;
}
/**
* Converts a dexMethod which must be a constructor to the corresponding
* {@link SigConstructor} instance.
*
* @param dexMethod
* the dex constructor to convert
* @return the corresponding {@link SigConstructor}
*/
public SigConstructor convertConstructor(DexMethod dexMethod) {
String declaringClassName = getClassName(dexMethod.getDeclaringClass()
.getName());
SigConstructor constructor = new SigConstructor(declaringClassName);
constructor.setModifiers(getModifier(dexMethod.getModifiers()));
String declaringClassPackageName = getPackageName(dexMethod
.getDeclaringClass().getName());
SigClassDefinition declaringClass = factory.getClass(
declaringClassPackageName, declaringClassName);
constructor.setDeclaringClass(declaringClass);
// Annotations
constructor.setAnnotations(convertAnnotations(dexMethod
.getAnnotations()));
if (hasGenericSignature(dexMethod)) {
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
parser.parseForConstructor(constructor,
getGenericSignature(dexMethod));
// type parameters
constructor.setTypeParameters(parser.formalTypeParameters);
// parameters
// generic parameter types parameters
List<DexParameter> dexParameters = dexMethod.getParameters();
List<IParameter> parameters = new ArrayList<IParameter>(
parser.parameterTypes.size());
Iterator<DexParameter> iterator = dexParameters.iterator();
for (ITypeReference parameterType : parser.parameterTypes) {
SigParameter parameter = new SigParameter(parameterType);
iterator.hasNext();
DexParameter dexParam = iterator.next();
parameter.setAnnotations(convertAnnotations(dexParam
.getAnnotations()));
parameters.add(parameter);
}
constructor.setParameters(parameters);
// exceptions
constructor.setExceptions(new HashSet<ITypeReference>(
parser.exceptionTypes));
} else {
convertNonGenericExecutableMember(constructor, dexMethod);
// remove first parameter of non static inner class constructors
// implicit outer.this reference
if (declaringClass.getDeclaringClass() != null) {
if (!declaringClass.getModifiers().contains(Modifier.STATIC)) {
if (constructor.getParameters().isEmpty()) {
throw new IllegalStateException(
"Expected at least one parameter!");
}
IParameter first = constructor.getParameters().remove(0);
String enclosingName = declaringClass.getDeclaringClass()
.getName();
String firstParameterTypeName = ((IClassReference) first
.getType()).getClassDefinition().getName();
if (!enclosingName.equals(firstParameterTypeName))
throw new IllegalStateException(
"Expected first constructor parameter of type "
+ enclosingName);
}
}
}
addExceptions(constructor, dexMethod);
return constructor;
}
public SigMethod convertMethod(DexMethod dexMethod) {
SigMethod method = new SigMethod(dexMethod.getName());
method.setModifiers(getModifier(dexMethod.getModifiers()));
String declaringClassPackageName = getPackageName(dexMethod
.getDeclaringClass().getName());
String declaringClassName = getClassName(dexMethod.getDeclaringClass()
.getName());
method.setDeclaringClass(factory.getClass(declaringClassPackageName,
declaringClassName));
// Annotations
method.setAnnotations(convertAnnotations(dexMethod.getAnnotations()));
if (hasGenericSignature(dexMethod)) {
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
parser.parseForMethod(method, getGenericSignature(dexMethod));
// type parameters
method.setTypeParameters(parser.formalTypeParameters);
// generic parameter types parameters
List<DexParameter> dexParameters = dexMethod.getParameters();
List<IParameter> parameters = new ArrayList<IParameter>(
parser.parameterTypes.size());
Iterator<DexParameter> iterator = dexParameters.iterator();
for (ITypeReference parameterType : parser.parameterTypes) {
SigParameter parameter = new SigParameter(parameterType);
iterator.hasNext();
DexParameter dexParam = iterator.next();
parameter.setAnnotations(convertAnnotations(dexParam
.getAnnotations()));
parameters.add(parameter);
}
method.setParameters(parameters);
// exceptions
method.setExceptions(new HashSet<ITypeReference>(
parser.exceptionTypes));
method.setReturnType(parser.returnType);
} else {
convertNonGenericExecutableMember(method, dexMethod);
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
ITypeReference type = parser.parseNonGenericReturnType(dexMethod
.getReturnType());
method.setReturnType(type);
}
addExceptions(method, dexMethod);
return method;
}
private void addExceptions(SigExecutableMember member,
DexMethod dexMethod) {
if (declaresExceptions(dexMethod)) {
String exceptionSignature = getExceptionSignature(dexMethod);
Set<String> exceptionTypeNames = splitTypeList(exceptionSignature);
Set<ITypeReference> exceptions = new HashSet<ITypeReference>();
for (String exTypeName : exceptionTypeNames) {
String packageName = getPackageName(exTypeName);
String className = getClassName(exTypeName);
exceptions.add(factory
.getClassReference(packageName, className));
}
member.setExceptions(exceptions);
} else {
member.setExceptions(EMPTY_EXCEPTIONS);
}
}
private void convertNonGenericExecutableMember(SigExecutableMember member,
DexMethod dexMethod) {
List<DexParameter> dexParameters = dexMethod.getParameters();
List<IParameter> parameters = new ArrayList<IParameter>(dexParameters
.size());
for (DexParameter dexParameter : dexParameters) {
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
ITypeReference type = parser.parseNonGenericType(dexParameter
.getTypeName());
SigParameter parameter = new SigParameter(type);
parameters.add(parameter);
// Annotations
parameter.setAnnotations(convertAnnotations(dexParameter
.getAnnotations()));
}
member.setParameters(parameters);
member.setTypeParameters(EMPTY_TYPE_VARIABLES);
// if (declaresExceptions(dexMethod)) {
// String exceptionSignature = getExceptionSignature(dexMethod);
// Set<String> exceptionTypeNames = splitTypeList(exceptionSignature);
// Set<IType> exceptions = new HashSet<IType>();
//
// for (String exTypeName : exceptionTypeNames) {
// String packageName = getPackageName(exTypeName);
// String className = getClassName(exTypeName);
// exceptions.add(factory.getClass(packageName, className));
// }
// member.setExceptions(exceptions);
// } else {
// member.setExceptions(EMPTY_EXCEPTIONS);
// }
}
/**
* Converts a set of {@link DexAnnotation} to a set of corresponding
* {@link SigAnnotation}.
*
* @param dexAnnotations
* the {@link DexAnnotation}s to convert
* @return the corresponding {@link SigAnnotation}s
*/
private Set<IAnnotation> convertAnnotations(
Set<DexAnnotation> dexAnnotations) {
Set<IAnnotation> annotations = new HashSet<IAnnotation>();
for (DexAnnotation dexAnnotation : dexAnnotations) {
if (!isInternalAnnotation(dexAnnotation)) {
annotations.add(convertAnnotation(dexAnnotation));
}
}
return annotations;
}
/**
* Converts a {@link DexAnnotation} to the corresponding
* {@link SigAnnotation}.
*
* @param dexAnnotation
* the {@link DexAnnotation} to convert
* @return the corresponding {@link SigAnnotation}
*/
protected SigAnnotation convertAnnotation(DexAnnotation dexAnnotation) {
SigAnnotation sigAnnotation = new SigAnnotation();
String packageName = getPackageName(dexAnnotation.getTypeName());
String className = getClassName(dexAnnotation.getTypeName());
sigAnnotation
.setType(factory.getClassReference(packageName, className));
sigAnnotation.setElements(convertAnnotationElements(dexAnnotation
.getAttributes()));
return sigAnnotation;
}
private Set<IAnnotationElement> convertAnnotationElements(
List<DexAnnotationAttribute> attributes) {
Set<IAnnotationElement> annotationAttributes =
new HashSet<IAnnotationElement>();
for (DexAnnotationAttribute dexAnnotationAttribute : attributes) {
annotationAttributes
.add(convertAnnotationAttribute(dexAnnotationAttribute));
}
return annotationAttributes;
}
private IAnnotationElement convertAnnotationAttribute(
DexAnnotationAttribute dexAnnotationAttribute) {
SigAnnotationElement sigElement = new SigAnnotationElement();
String nameOfField = dexAnnotationAttribute.getName();
String typeName = dexAnnotationAttribute.getAnnotation().getTypeName();
SigClassDefinition annotationClass = factory.getClass(
getPackageName(typeName), getClassName(typeName));
if (!Uninitialized.isInitialized(
annotationClass.getAnnotationFields())) {
initializeClass(getPackageName(typeName), getClassName(typeName));
}
for (IAnnotationField field : annotationClass.getAnnotationFields()) {
if (nameOfField.equals(field.getName())) {
sigElement.setDeclaringField(field);
}
}
sigElement.setValue(convertEncodedValue(dexAnnotationAttribute
.getEncodedValue()));
return sigElement;
}
@SuppressWarnings("unchecked")
private Object convertEncodedValue(DexEncodedValue dexEnodedValue) {
Object value = null;
switch (dexEnodedValue.getType()) {
case VALUE_INT:
case VALUE_BOOLEAN:
case VALUE_BYTE:
case VALUE_CHAR:
case VALUE_DOUBLE:
case VALUE_FLOAT:
case VALUE_LONG:
case VALUE_NULL:
case VALUE_STRING:
case VALUE_SHORT:
value = dexEnodedValue.getValue();
break;
case VALUE_ARRAY: {
List<DexEncodedValue> dexValues =
(List<DexEncodedValue>) dexEnodedValue.getValue();
Object[] arrayValues = new Object[dexValues.size()];
int i = 0;
for (DexEncodedValue dexValue : dexValues) {
arrayValues[i++] = convertEncodedValue(dexValue);
}
value = arrayValues;
break;
}
case VALUE_ANNOTATION: {
DexEncodedAnnotation annotation =
(DexEncodedAnnotation) dexEnodedValue.getValue();
SigAnnotation sigAnnotation = new SigAnnotation();
String packageName = getPackageName(annotation.getTypeName());
String className = getClassName(annotation.getTypeName());
sigAnnotation.setType(factory.getClassReference(packageName,
className));
sigAnnotation.setElements(convertAnnotationElements(annotation
.getValue()));
value = sigAnnotation;
break;
}
case VALUE_FIELD: {
String fieldDesc = (String) dexEnodedValue.getValue();
// FORMAT La/b/E;!CONSTANT
String[] typeAndFieldName = fieldDesc.split("!");
String typeName = typeAndFieldName[0];
String fieldName = typeAndFieldName[1];
value = elementPool.getField(getQualifiedName(typeName), fieldName);
break;
}
case VALUE_ENUM: {
String fieldDesc = (String) dexEnodedValue.getValue();
// FORMAT La/b/E;!CONSTANT
String[] typeAndFieldName = fieldDesc.split("!");
String typeName = typeAndFieldName[0];
String fieldName = typeAndFieldName[1];
value = elementPool.getEnumConstant(getQualifiedName(typeName),
fieldName);
break;
}
case VALUE_TYPE: {
String typeName = (String) dexEnodedValue.getValue();
GenericSignatureParser parser = new GenericSignatureParser(factory,
this);
value = parser.parseNonGenericReturnType(typeName);
break;
}
default:
throw new IllegalStateException();
}
return value;
}
public IClassDefinition initializeClass(String packageName,
String className) {
String dexName = getDexName(packageName, className);
DexClass dexClass = dexNameToDexClass.get(dexName);
return convertClass(dexClass);
}
}