Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package signature.converter.dex;
     18 
     19 import static signature.converter.dex.DexUtil.convertAnyWay;
     20 import static signature.converter.dex.DexUtil.declaresExceptions;
     21 import static signature.converter.dex.DexUtil.declaresMemberClasses;
     22 import static signature.converter.dex.DexUtil.findPackageInfo;
     23 import static signature.converter.dex.DexUtil.getClassModifiers;
     24 import static signature.converter.dex.DexUtil.getClassName;
     25 import static signature.converter.dex.DexUtil.getDefaultMappingsAnnotation;
     26 import static signature.converter.dex.DexUtil.getDexName;
     27 import static signature.converter.dex.DexUtil.getEnclosingClassName;
     28 import static signature.converter.dex.DexUtil.getExceptionSignature;
     29 import static signature.converter.dex.DexUtil.getGenericSignature;
     30 import static signature.converter.dex.DexUtil.getKind;
     31 import static signature.converter.dex.DexUtil.getMemberClassNames;
     32 import static signature.converter.dex.DexUtil.getModifier;
     33 import static signature.converter.dex.DexUtil.getPackageName;
     34 import static signature.converter.dex.DexUtil.getQualifiedName;
     35 import static signature.converter.dex.DexUtil.hasAnnotationDefaultSignature;
     36 import static signature.converter.dex.DexUtil.hasGenericSignature;
     37 import static signature.converter.dex.DexUtil.isAnnotation;
     38 import static signature.converter.dex.DexUtil.isConstructor;
     39 import static signature.converter.dex.DexUtil.isEnclosingClass;
     40 import static signature.converter.dex.DexUtil.isEnum;
     41 import static signature.converter.dex.DexUtil.isInternalAnnotation;
     42 import static signature.converter.dex.DexUtil.isJavaLangObject;
     43 import static signature.converter.dex.DexUtil.isMethod;
     44 import static signature.converter.dex.DexUtil.isVisible;
     45 import static signature.converter.dex.DexUtil.splitTypeList;
     46 
     47 import java.util.ArrayList;
     48 import java.util.Collections;
     49 import java.util.HashMap;
     50 import java.util.HashSet;
     51 import java.util.Iterator;
     52 import java.util.List;
     53 import java.util.Map;
     54 import java.util.Set;
     55 
     56 import signature.converter.Visibility;
     57 import signature.model.IAnnotation;
     58 import signature.model.IAnnotationElement;
     59 import signature.model.IAnnotationField;
     60 import signature.model.IClassDefinition;
     61 import signature.model.IClassReference;
     62 import signature.model.IConstructor;
     63 import signature.model.IEnumConstant;
     64 import signature.model.IField;
     65 import signature.model.IMethod;
     66 import signature.model.IPackage;
     67 import signature.model.IParameter;
     68 import signature.model.ITypeReference;
     69 import signature.model.ITypeVariableDefinition;
     70 import signature.model.Kind;
     71 import signature.model.Modifier;
     72 import signature.model.impl.SigAnnotation;
     73 import signature.model.impl.SigAnnotationElement;
     74 import signature.model.impl.SigAnnotationField;
     75 import signature.model.impl.SigApi;
     76 import signature.model.impl.SigClassDefinition;
     77 import signature.model.impl.SigClassReference;
     78 import signature.model.impl.SigConstructor;
     79 import signature.model.impl.SigEnumConstant;
     80 import signature.model.impl.SigExecutableMember;
     81 import signature.model.impl.SigField;
     82 import signature.model.impl.SigMethod;
     83 import signature.model.impl.SigPackage;
     84 import signature.model.impl.SigParameter;
     85 import signature.model.impl.Uninitialized;
     86 import signature.model.util.TypePool;
     87 import dex.structure.DexAnnotation;
     88 import dex.structure.DexAnnotationAttribute;
     89 import dex.structure.DexClass;
     90 import dex.structure.DexEncodedAnnotation;
     91 import dex.structure.DexEncodedValue;
     92 import dex.structure.DexField;
     93 import dex.structure.DexFile;
     94 import dex.structure.DexMethod;
     95 import dex.structure.DexParameter;
     96 
     97 /**
     98  * Converts a set of dex files to the signature compare api.
     99  */
    100 public final class DexToSigConverter implements IClassInitializer {
    101 
    102     private final FieldPool elementPool;
    103     private final TypePool factory;
    104     private static final Set<IField> EMPTY_FIELDS = Collections.emptySet();
    105     private static final Set<IEnumConstant> EMPTY_ENUM_CONSTANTS = Collections
    106             .emptySet();
    107     private static final Set<IAnnotationField> EMPTY_ANNOTATION_FIELDS =
    108             Collections.emptySet();
    109     private static final List<ITypeVariableDefinition> EMPTY_TYPE_VARIABLES =
    110             Collections.emptyList();
    111     private static final Set<IClassDefinition> EMPTY_INNER_CLASSES =
    112             Collections.emptySet();
    113     private static final Set<ITypeReference> EMPTY_EXCEPTIONS = Collections
    114             .emptySet();
    115     private Visibility visibility;
    116     private Map<String, DexClass> dexNameToDexClass;
    117 
    118 
    119     /**
    120      * Creates a new instance of {@link DexToSigConverter}.
    121      */
    122     public DexToSigConverter() {
    123         factory = new TypePool();
    124         elementPool = new FieldPool();
    125     }
    126 
    127 
    128     public SigApi convertApi(String apiName, Set<DexFile> dexFiles,
    129             Visibility visibility) {
    130         this.visibility = visibility;
    131         SigApi api = new SigApi(apiName, visibility);
    132         api.setPackages(convertPackages(dexFiles));
    133         factory.replaceAllUninitialiezWithNull();
    134         return api;
    135     }
    136 
    137     /**
    138      * Converts the given {@link DexFile}s into the corresponding (packages
    139      * including their (classes and their members, etc.))E
    140      *
    141      * @param parsedFiles
    142      *            the dex files to convert
    143      * @return the converted packages
    144      */
    145     /* package */Set<IPackage> convertPackages(Set<DexFile> parsedFiles) {
    146         Map<String, SigPackage> packageNameToPackage =
    147                 new HashMap<String, SigPackage>();
    148         Map<SigPackage, Set<DexClass>> packageToDexClasses =
    149                 new HashMap<SigPackage, Set<DexClass>>();
    150 
    151         dexNameToDexClass = new HashMap<String, DexClass>();
    152 
    153         for (DexFile dexFile : parsedFiles) {
    154             List<DexClass> definedClasses = dexFile.getDefinedClasses();
    155             for (DexClass dexClass : definedClasses) {
    156 
    157                 dexNameToDexClass.put(dexClass.getName(), dexClass);
    158 
    159                 String dexName = dexClass.getName();
    160                 String packageName = getPackageName(dexName);
    161                 SigPackage aPackage = packageNameToPackage.get(packageName);
    162                 if (aPackage == null) {
    163                     aPackage = convertPackage(packageName);
    164                     packageNameToPackage.put(packageName, aPackage);
    165 
    166                     Set<DexClass> classes = new HashSet<DexClass>();
    167                     packageToDexClasses.put(aPackage, classes);
    168                 }
    169                 Set<DexClass> classes = packageToDexClasses.get(aPackage);
    170                 classes.add(dexClass);
    171             }
    172         }
    173 
    174         Set<SigClassDefinition> allClasses = new HashSet<SigClassDefinition>();
    175 
    176         for (SigPackage aPackage : packageToDexClasses.keySet()) {
    177             Set<SigClassDefinition> classes = convertClasses(packageToDexClasses
    178                     .get(aPackage));
    179             allClasses.addAll(classes);
    180             aPackage.setClasses(new HashSet<IClassDefinition>(classes));
    181         }
    182 
    183         // remove package info
    184         for (SigPackage aPackage : packageToDexClasses.keySet()) {
    185             IClassDefinition packageInfo = findPackageInfo(aPackage);
    186             if (packageInfo != null) {
    187                 aPackage.setAnnotations(packageInfo.getAnnotations());
    188                 aPackage.getClasses().remove(packageInfo);
    189             }
    190         }
    191 
    192         // link enclosed classes only if they are part of visible api
    193         for (SigClassDefinition sigClass : allClasses) {
    194             String dexName = getDexName(sigClass);
    195             DexClass dexClass = dexNameToDexClass.get(dexName);
    196 
    197             if (declaresMemberClasses(dexClass)) {
    198                 Set<String> enclosedClassesNames =
    199                         getMemberClassNames(dexClass);
    200                 Set<IClassDefinition> memberClasses =
    201                         new HashSet<IClassDefinition>();
    202                 for (String enclosedClassName : enclosedClassesNames) {
    203                     SigClassDefinition memberClass = factory.getClass(
    204                             getPackageName(enclosedClassName),
    205                             getClassName(enclosedClassName));
    206                     // add inner class only if parsed
    207                     if (allClasses.contains(memberClass)) {
    208                         memberClasses.add(memberClass);
    209                     }
    210                 }
    211                 sigClass.setInnerClasses(memberClasses);
    212             } else {
    213                 sigClass.setInnerClasses(EMPTY_INNER_CLASSES);
    214             }
    215         }
    216 
    217         // remove inner classes, is outer class is not visible
    218         for (SigClassDefinition sigClass : allClasses) {
    219             if (hasInvisibleParent(sigClass, dexNameToDexClass)) {
    220                 SigPackage sigPackage = packageNameToPackage.get(sigClass
    221                         .getPackageName());
    222                 sigPackage.getClasses().remove(sigClass);
    223             }
    224         }
    225         return new HashSet<IPackage>(packageToDexClasses.keySet());
    226     }
    227 
    228     private boolean hasInvisibleParent(IClassDefinition sigClass,
    229             Map<String, DexClass> dexNameToDexClass) {
    230 
    231         do {
    232             String dexName = getDexName(sigClass);
    233             DexClass dexClass = dexNameToDexClass.get(dexName);
    234             if (isEnclosingClass(dexClass)) {
    235                 IClassDefinition declaringClass = sigClass.getDeclaringClass();
    236                 DexClass declaringDexClass = dexNameToDexClass
    237                         .get(getDexName(declaringClass));
    238                 if (!isVisible(declaringDexClass, visibility)) {
    239                     return true;
    240                 }
    241             }
    242         } while ((sigClass = sigClass.getDeclaringClass()) != null);
    243         return false;
    244     }
    245 
    246     /**
    247      * Converts a simple string to the corresponding {@link SigPackage}.<br>
    248      * Format: "a.b.c"
    249      *
    250      * @param packageName
    251      *            the name of the package
    252      * @return the package
    253      */
    254     protected SigPackage convertPackage(String packageName) {
    255         SigPackage sigPackage = new SigPackage(packageName);
    256         return sigPackage;
    257     }
    258 
    259     /**
    260      * Converts a set of {@link DexClass} objects to a set of the corresponding
    261      * {@link SigClassDefinition} objects.
    262      *
    263      * @param dexClasses
    264      *            the {@link DexClass} objects
    265      * @return a set of {@link DexClass} objects
    266      */
    267     protected Set<SigClassDefinition> convertClasses(Set<DexClass> dexClasses) {
    268         Set<SigClassDefinition> classes = new HashSet<SigClassDefinition>();
    269         for (DexClass dexClass : dexClasses) {
    270             // convert all classes but synthetic, return only initialized
    271             if (convertAnyWay(dexClass)) {
    272                 SigClassDefinition sigCLass = convertClass(dexClass);
    273                 if (isVisible(dexClass, visibility)) {
    274                     classes.add(sigCLass);
    275                 }
    276             }
    277         }
    278         return classes;
    279     }
    280 
    281     /**
    282      * Converts a {@link DexClass} to the corresponding
    283      * {@link SigClassDefinition}.
    284      *
    285      * @param dexClass
    286      *            the {@link DexClass} to convert
    287      * @return the corresponding {@link SigClassDefinition}
    288      */
    289     protected SigClassDefinition convertClass(DexClass dexClass) {
    290         assert dexClass != null;
    291 
    292         String packageName = getPackageName(dexClass.getName());
    293         String className = getClassName(dexClass.getName());
    294         SigClassDefinition sigClass = factory.getClass(packageName, className);
    295         // Kind
    296         sigClass.setKind(getKind(dexClass));
    297         // modifiers
    298         Set<Modifier> modifiers = getModifier(getClassModifiers(dexClass));
    299         sigClass.setModifiers(modifiers);
    300 
    301         if (isEnclosingClass(dexClass)) {
    302             String declaringClassDexName = getEnclosingClassName(dexClass);
    303             declaringClassDexName = getClassName(declaringClassDexName);
    304             // declaring class is in same package
    305             sigClass.setDeclaringClass(factory.getClass(sigClass
    306                     .getPackageName(), declaringClassDexName));
    307         } else {
    308             sigClass.setDeclaringClass(null);
    309         }
    310 
    311         if (hasGenericSignature(dexClass)) {
    312             GenericSignatureParser parser = new GenericSignatureParser(factory,
    313                     this);
    314             parser.parseForClass(sigClass, getGenericSignature(dexClass));
    315             sigClass.setTypeParameters(parser.formalTypeParameters);
    316 
    317             if (Kind.INTERFACE.equals(sigClass.getKind())) {
    318                 sigClass.setSuperClass(null);
    319             } else {
    320                 sigClass.setSuperClass(parser.superclassType);
    321             }
    322 
    323             sigClass.setInterfaces(new HashSet<ITypeReference>(
    324                     parser.interfaceTypes));
    325         } else {
    326 
    327             // Type parameters
    328             sigClass.setTypeParameters(EMPTY_TYPE_VARIABLES);
    329 
    330             // java.lang.Object has no super class
    331             if (isJavaLangObject(dexClass)) {
    332                 sigClass.setSuperClass(null);
    333             } else {
    334 
    335                 if (Kind.INTERFACE.equals(sigClass.getKind())
    336                         || Kind.ANNOTATION.equals(sigClass.getKind())) {
    337                     sigClass.setSuperClass(null);
    338                 } else {
    339                     String superClassPackageName = getPackageName(dexClass
    340                             .getSuperClass());
    341                     String superClassName = getClassName(dexClass
    342                             .getSuperClass());
    343                     sigClass.setSuperClass(factory.getClassReference(
    344                             superClassPackageName, superClassName));
    345                 }
    346             }
    347 
    348             List<String> interfaceDexNames = dexClass.getInterfaces();
    349             Set<ITypeReference> interfaces = new HashSet<ITypeReference>();
    350             for (String interfaceDexName : interfaceDexNames) {
    351                 String interfacePackageName = getPackageName(interfaceDexName);
    352                 String interfaceName = getClassName(interfaceDexName);
    353                 SigClassDefinition interfaze = factory.getClass(
    354                         interfacePackageName, interfaceName);
    355                 interfaze.setKind(Kind.INTERFACE);
    356                 interfaces.add(new SigClassReference(interfaze));
    357             }
    358             sigClass.setInterfaces(interfaces);
    359         }
    360 
    361         // constructors
    362         Set<SigConstructor> constructors = convertConstructors(dexClass
    363                 .getMethods());
    364         for (SigConstructor constructor : constructors) {
    365             constructor.setDeclaringClass(sigClass);
    366         }
    367         sigClass.setConstructors(new HashSet<IConstructor>(constructors));
    368 
    369         // methods
    370         Set<SigMethod> methods = Collections.emptySet();
    371 
    372 
    373         if (isAnnotation(dexClass)) {
    374             Map<String, Object> mappings = getDefaultValueMapping(dexClass);
    375             Set<SigAnnotationField> annotationFields = convertAnnotationFields(
    376                     dexClass.getMethods(), mappings);
    377             sigClass.setAnnotationFields(new HashSet<IAnnotationField>(
    378                     annotationFields));
    379             addAnnotationsToAnnotationFields(dexClass.getMethods(),
    380                     annotationFields);
    381 
    382             sigClass.setEnumConstants(EMPTY_ENUM_CONSTANTS);
    383             sigClass.setFields(EMPTY_FIELDS);
    384 
    385             // sigClass.setAnnotationFields(new
    386             // HashSet<IAnnotationField>(convertAnnotationFields(dexClass)));
    387         } else if (isEnum(dexClass)) {
    388             Set<IField> fields = new HashSet<IField>();
    389             Set<IEnumConstant> enumConstants = new HashSet<IEnumConstant>();
    390 
    391             for (DexField dexField : dexClass.getFields()) {
    392                 if (isVisible(dexField, visibility)) {
    393                     if (dexField.isEnumConstant()) {
    394                         enumConstants.add(convertEnumConstant(dexField));
    395                     } else {
    396                         fields.add(convertField(dexField));
    397                     }
    398                 }
    399             }
    400 
    401             sigClass.setFields(fields);
    402             sigClass.setEnumConstants(enumConstants);
    403             sigClass.setAnnotationFields(EMPTY_ANNOTATION_FIELDS);
    404             methods = convertMethods(dexClass.getMethods());
    405         } else {
    406             // fields
    407             sigClass.setFields(new HashSet<IField>(convertFields(dexClass
    408                     .getFields())));
    409             sigClass.setEnumConstants(EMPTY_ENUM_CONSTANTS);
    410             sigClass.setAnnotationFields(EMPTY_ANNOTATION_FIELDS);
    411             methods = convertMethods(dexClass.getMethods());
    412         }
    413 
    414         for (SigMethod method : methods) {
    415             method.setDeclaringClass(sigClass);
    416         }
    417         sigClass.setMethods(new HashSet<IMethod>(methods));
    418 
    419         // Annotations
    420         sigClass.setAnnotations(convertAnnotations(dexClass.getAnnotations()));
    421 
    422         return sigClass;
    423     }
    424 
    425     @SuppressWarnings("unchecked")
    426     private Map<String, Object> getDefaultValueMapping(DexClass dexClass) {
    427         HashMap<String, Object> mappings = new HashMap<String, Object>();
    428         if (hasAnnotationDefaultSignature(dexClass)) {
    429             // read mapping to defaults from annotation
    430             DexAnnotation annotation = getDefaultMappingsAnnotation(dexClass);
    431             DexAnnotationAttribute dexAnnotationAttribute = annotation
    432                     .getAttributes().get(0);
    433             if ("value".equals(dexAnnotationAttribute.getName())) {
    434                 DexEncodedValue encodedValue = dexAnnotationAttribute
    435                         .getEncodedValue();
    436                 DexEncodedValue value = (DexEncodedValue) encodedValue
    437                         .getValue();
    438                 List<DexAnnotationAttribute> defaults =
    439                         (List<DexAnnotationAttribute>) value.getValue();
    440                 for (DexAnnotationAttribute defaultAttribute : defaults) {
    441                     mappings.put(defaultAttribute.getName(),
    442                             convertEncodedValue(defaultAttribute
    443                                     .getEncodedValue()));
    444                 }
    445             }
    446         }
    447         return mappings;
    448     }
    449 
    450 
    451     private void addAnnotationsToAnnotationFields(List<DexMethod> methods,
    452             Set<SigAnnotationField> annotationFields) {
    453         Map<String, SigAnnotationField> nameToAnnotationField =
    454                 new HashMap<String, SigAnnotationField>();
    455 
    456         for (SigAnnotationField annotationField : annotationFields) {
    457             nameToAnnotationField.put(annotationField.getName(),
    458                     annotationField);
    459         }
    460 
    461         for (DexMethod method : methods) {
    462             SigAnnotationField annotationField = nameToAnnotationField
    463                     .get(method.getName());
    464             annotationField.setAnnotations(convertAnnotations(method
    465                     .getAnnotations()));
    466         }
    467     }
    468 
    469 
    470     private Set<SigAnnotationField> convertAnnotationFields(
    471             List<DexMethod> list, Map<String, Object> mappings) {
    472         Set<SigAnnotationField> annotationfields =
    473                 new HashSet<SigAnnotationField>();
    474         for (DexMethod dexMethod : list) {
    475             if (isVisible(dexMethod, visibility)) {
    476                 annotationfields.add(convertAnnotationField(dexMethod, mappings
    477                         .get(dexMethod.getName())));
    478             }
    479         }
    480         return annotationfields;
    481     }
    482 
    483     private SigAnnotationField convertAnnotationField(DexMethod dexMethod,
    484             Object defaultValue) {
    485         SigAnnotationField annotationField = new SigAnnotationField(dexMethod
    486                 .getName());
    487         annotationField.setDefaultValue(defaultValue);
    488         annotationField.setModifiers(getModifier(dexMethod.getModifiers()));
    489         GenericSignatureParser parser = new GenericSignatureParser(factory,
    490                 this);
    491         annotationField.setType(parser.parseNonGenericType(dexMethod
    492                 .getReturnType()));
    493         return annotationField;
    494     }
    495 
    496     private IEnumConstant convertEnumConstant(DexField dexField) {
    497         String qualifiedTypeName = getQualifiedName(dexField
    498                 .getDeclaringClass().getName());
    499         SigEnumConstant enumConstant = elementPool.getEnumConstant(
    500                 qualifiedTypeName, dexField.getName());
    501         Set<Modifier> modifiers = getModifier(dexField.getModifiers());
    502         modifiers.add(Modifier.STATIC);
    503         enumConstant.setModifiers(modifiers);
    504 
    505         String typePackageName = getPackageName(dexField.getType());
    506         String typeName = getClassName(dexField.getType());
    507         enumConstant.setType(factory.getClassReference(typePackageName,
    508                 typeName));
    509         enumConstant.setAnnotations(convertAnnotations(dexField
    510                 .getAnnotations()));
    511         return enumConstant;
    512     }
    513 
    514     private Set<SigField> convertFields(List<DexField> dexFields) {
    515         Set<SigField> fields = new HashSet<SigField>();
    516         for (DexField dexField : dexFields) {
    517             if (isVisible(dexField, visibility)) {
    518                 fields.add(convertField(dexField));
    519             }
    520         }
    521         return fields;
    522     }
    523 
    524     private SigField convertField(DexField dexField) {
    525         String qualTypeName = getQualifiedName(dexField.getDeclaringClass()
    526                 .getName());
    527         SigField field = elementPool.getField(qualTypeName, dexField.getName());
    528 
    529         field.setModifiers(getModifier(dexField.getModifiers()));
    530 
    531         field.setAnnotations(convertAnnotations(dexField.getAnnotations()));
    532 
    533         if (hasGenericSignature(dexField)) {
    534             GenericSignatureParser parser = new GenericSignatureParser(factory,
    535                     this);
    536             String declaringClassPackageName = getPackageName(dexField
    537                     .getDeclaringClass().getName());
    538             String declaringClassName = getClassName(dexField
    539                     .getDeclaringClass().getName());
    540 
    541             parser.parseForField(factory.getClass(declaringClassPackageName,
    542                     declaringClassName), getGenericSignature(dexField));
    543             field.setType(parser.fieldType);
    544         } else {
    545             GenericSignatureParser parser = new GenericSignatureParser(factory,
    546                     this);
    547             field.setType(parser.parseNonGenericType(dexField.getType()));
    548         }
    549 
    550         return field;
    551     }
    552 
    553     /**
    554      * Converts a set of {@link DexMethod} to a set of corresponding
    555      * {@link IConstructor}. This method ignores methods which are not
    556      * constructors.
    557      *
    558      * @param methods
    559      *            the {@link DexMethod}s to convert
    560      * @return the corresponding {@link IConstructor}s
    561      */
    562     private Set<SigConstructor> convertConstructors(List<DexMethod> methods) {
    563         Set<SigConstructor> constructors = new HashSet<SigConstructor>();
    564         for (DexMethod method : methods) {
    565             if (isConstructor(method) && isVisible(method, visibility)) {
    566                 constructors.add(convertConstructor(method));
    567             }
    568         }
    569         return constructors;
    570     }
    571 
    572     /**
    573      * Converts a set of {@link DexMethod} to a set of corresponding
    574      * {@link DexMethod}. This method ignores methods which are constructors.
    575      *
    576      * @param methods
    577      *            the {@link DexMethod}s to convert
    578      * @return the corresponding {@link IConstructor}s
    579      */
    580     private Set<SigMethod> convertMethods(List<DexMethod> methods) {
    581         Set<SigMethod> sigMethods = new HashSet<SigMethod>();
    582         for (DexMethod method : methods) {
    583             if (isMethod(method) && isVisible(method, visibility)) {
    584                 sigMethods.add(convertMethod(method));
    585             }
    586         }
    587         return sigMethods;
    588     }
    589 
    590     /**
    591      * Converts a dexMethod which must be a constructor to the corresponding
    592      * {@link SigConstructor} instance.
    593      *
    594      * @param dexMethod
    595      *            the dex constructor to convert
    596      * @return the corresponding {@link SigConstructor}
    597      */
    598     public SigConstructor convertConstructor(DexMethod dexMethod) {
    599         String declaringClassName = getClassName(dexMethod.getDeclaringClass()
    600                 .getName());
    601 
    602         SigConstructor constructor = new SigConstructor(declaringClassName);
    603         constructor.setModifiers(getModifier(dexMethod.getModifiers()));
    604         String declaringClassPackageName = getPackageName(dexMethod
    605                 .getDeclaringClass().getName());
    606 
    607 
    608         SigClassDefinition declaringClass = factory.getClass(
    609                 declaringClassPackageName, declaringClassName);
    610         constructor.setDeclaringClass(declaringClass);
    611 
    612         // Annotations
    613         constructor.setAnnotations(convertAnnotations(dexMethod
    614                 .getAnnotations()));
    615 
    616         if (hasGenericSignature(dexMethod)) {
    617             GenericSignatureParser parser = new GenericSignatureParser(factory,
    618                     this);
    619             parser.parseForConstructor(constructor,
    620                     getGenericSignature(dexMethod));
    621 
    622             // type parameters
    623             constructor.setTypeParameters(parser.formalTypeParameters);
    624 
    625             // parameters
    626             // generic parameter types parameters
    627             List<DexParameter> dexParameters = dexMethod.getParameters();
    628             List<IParameter> parameters = new ArrayList<IParameter>(
    629                     parser.parameterTypes.size());
    630             Iterator<DexParameter> iterator = dexParameters.iterator();
    631             for (ITypeReference parameterType : parser.parameterTypes) {
    632                 SigParameter parameter = new SigParameter(parameterType);
    633                 iterator.hasNext();
    634                 DexParameter dexParam = iterator.next();
    635                 parameter.setAnnotations(convertAnnotations(dexParam
    636                         .getAnnotations()));
    637                 parameters.add(parameter);
    638             }
    639 
    640             constructor.setParameters(parameters);
    641 
    642             // exceptions
    643             constructor.setExceptions(new HashSet<ITypeReference>(
    644                     parser.exceptionTypes));
    645 
    646         } else {
    647             convertNonGenericExecutableMember(constructor, dexMethod);
    648 
    649             // remove first parameter of non static inner class constructors
    650             // implicit outer.this reference
    651             if (declaringClass.getDeclaringClass() != null) {
    652                 if (!declaringClass.getModifiers().contains(Modifier.STATIC)) {
    653                     if (constructor.getParameters().isEmpty()) {
    654                         throw new IllegalStateException(
    655                                 "Expected at least one parameter!");
    656                     }
    657                     IParameter first = constructor.getParameters().remove(0);
    658                     String enclosingName = declaringClass.getDeclaringClass()
    659                             .getName();
    660                     String firstParameterTypeName = ((IClassReference) first
    661                             .getType()).getClassDefinition().getName();
    662                     if (!enclosingName.equals(firstParameterTypeName))
    663                         throw new IllegalStateException(
    664                                 "Expected first constructor parameter of type "
    665                                         + enclosingName);
    666                 }
    667             }
    668         }
    669 
    670         addExceptions(constructor, dexMethod);
    671         return constructor;
    672     }
    673 
    674     public SigMethod convertMethod(DexMethod dexMethod) {
    675         SigMethod method = new SigMethod(dexMethod.getName());
    676         method.setModifiers(getModifier(dexMethod.getModifiers()));
    677 
    678         String declaringClassPackageName = getPackageName(dexMethod
    679                 .getDeclaringClass().getName());
    680         String declaringClassName = getClassName(dexMethod.getDeclaringClass()
    681                 .getName());
    682 
    683         method.setDeclaringClass(factory.getClass(declaringClassPackageName,
    684                 declaringClassName));
    685 
    686         // Annotations
    687         method.setAnnotations(convertAnnotations(dexMethod.getAnnotations()));
    688 
    689         if (hasGenericSignature(dexMethod)) {
    690             GenericSignatureParser parser = new GenericSignatureParser(factory,
    691                     this);
    692             parser.parseForMethod(method, getGenericSignature(dexMethod));
    693 
    694             // type parameters
    695             method.setTypeParameters(parser.formalTypeParameters);
    696 
    697             // generic parameter types parameters
    698             List<DexParameter> dexParameters = dexMethod.getParameters();
    699             List<IParameter> parameters = new ArrayList<IParameter>(
    700                     parser.parameterTypes.size());
    701             Iterator<DexParameter> iterator = dexParameters.iterator();
    702             for (ITypeReference parameterType : parser.parameterTypes) {
    703                 SigParameter parameter = new SigParameter(parameterType);
    704                 iterator.hasNext();
    705                 DexParameter dexParam = iterator.next();
    706                 parameter.setAnnotations(convertAnnotations(dexParam
    707                         .getAnnotations()));
    708                 parameters.add(parameter);
    709             }
    710             method.setParameters(parameters);
    711 
    712             // exceptions
    713             method.setExceptions(new HashSet<ITypeReference>(
    714                     parser.exceptionTypes));
    715             method.setReturnType(parser.returnType);
    716 
    717         } else {
    718             convertNonGenericExecutableMember(method, dexMethod);
    719             GenericSignatureParser parser = new GenericSignatureParser(factory,
    720                     this);
    721             ITypeReference type = parser.parseNonGenericReturnType(dexMethod
    722                     .getReturnType());
    723             method.setReturnType(type);
    724         }
    725         addExceptions(method, dexMethod);
    726         return method;
    727     }
    728 
    729     private void addExceptions(SigExecutableMember member,
    730             DexMethod dexMethod) {
    731         if (declaresExceptions(dexMethod)) {
    732             String exceptionSignature = getExceptionSignature(dexMethod);
    733             Set<String> exceptionTypeNames = splitTypeList(exceptionSignature);
    734             Set<ITypeReference> exceptions = new HashSet<ITypeReference>();
    735 
    736             for (String exTypeName : exceptionTypeNames) {
    737                 String packageName = getPackageName(exTypeName);
    738                 String className = getClassName(exTypeName);
    739                 exceptions.add(factory
    740                         .getClassReference(packageName, className));
    741             }
    742             member.setExceptions(exceptions);
    743         } else {
    744             member.setExceptions(EMPTY_EXCEPTIONS);
    745         }
    746     }
    747 
    748     private void convertNonGenericExecutableMember(SigExecutableMember member,
    749             DexMethod dexMethod) {
    750         List<DexParameter> dexParameters = dexMethod.getParameters();
    751         List<IParameter> parameters = new ArrayList<IParameter>(dexParameters
    752                 .size());
    753 
    754         for (DexParameter dexParameter : dexParameters) {
    755             GenericSignatureParser parser = new GenericSignatureParser(factory,
    756                     this);
    757             ITypeReference type = parser.parseNonGenericType(dexParameter
    758                     .getTypeName());
    759             SigParameter parameter = new SigParameter(type);
    760             parameters.add(parameter);
    761             // Annotations
    762             parameter.setAnnotations(convertAnnotations(dexParameter
    763                     .getAnnotations()));
    764         }
    765         member.setParameters(parameters);
    766 
    767         member.setTypeParameters(EMPTY_TYPE_VARIABLES);
    768 
    769         // if (declaresExceptions(dexMethod)) {
    770         // String exceptionSignature = getExceptionSignature(dexMethod);
    771         // Set<String> exceptionTypeNames = splitTypeList(exceptionSignature);
    772         // Set<IType> exceptions = new HashSet<IType>();
    773         //
    774         // for (String exTypeName : exceptionTypeNames) {
    775         // String packageName = getPackageName(exTypeName);
    776         // String className = getClassName(exTypeName);
    777         // exceptions.add(factory.getClass(packageName, className));
    778         // }
    779         // member.setExceptions(exceptions);
    780         // } else {
    781         // member.setExceptions(EMPTY_EXCEPTIONS);
    782         // }
    783     }
    784 
    785     /**
    786      * Converts a set of {@link DexAnnotation} to a set of corresponding
    787      * {@link SigAnnotation}.
    788      *
    789      * @param dexAnnotations
    790      *            the {@link DexAnnotation}s to convert
    791      * @return the corresponding {@link SigAnnotation}s
    792      */
    793     private Set<IAnnotation> convertAnnotations(
    794             Set<DexAnnotation> dexAnnotations) {
    795         Set<IAnnotation> annotations = new HashSet<IAnnotation>();
    796         for (DexAnnotation dexAnnotation : dexAnnotations) {
    797             if (!isInternalAnnotation(dexAnnotation)) {
    798                 annotations.add(convertAnnotation(dexAnnotation));
    799             }
    800         }
    801         return annotations;
    802     }
    803 
    804     /**
    805      * Converts a {@link DexAnnotation} to the corresponding
    806      * {@link SigAnnotation}.
    807      *
    808      * @param dexAnnotation
    809      *            the {@link DexAnnotation} to convert
    810      * @return the corresponding {@link SigAnnotation}
    811      */
    812     protected SigAnnotation convertAnnotation(DexAnnotation dexAnnotation) {
    813         SigAnnotation sigAnnotation = new SigAnnotation();
    814         String packageName = getPackageName(dexAnnotation.getTypeName());
    815         String className = getClassName(dexAnnotation.getTypeName());
    816         sigAnnotation
    817                 .setType(factory.getClassReference(packageName, className));
    818         sigAnnotation.setElements(convertAnnotationElements(dexAnnotation
    819                 .getAttributes()));
    820         return sigAnnotation;
    821     }
    822 
    823     private Set<IAnnotationElement> convertAnnotationElements(
    824             List<DexAnnotationAttribute> attributes) {
    825         Set<IAnnotationElement> annotationAttributes =
    826                 new HashSet<IAnnotationElement>();
    827         for (DexAnnotationAttribute dexAnnotationAttribute : attributes) {
    828             annotationAttributes
    829                     .add(convertAnnotationAttribute(dexAnnotationAttribute));
    830         }
    831         return annotationAttributes;
    832     }
    833 
    834     private IAnnotationElement convertAnnotationAttribute(
    835             DexAnnotationAttribute dexAnnotationAttribute) {
    836 
    837         SigAnnotationElement sigElement = new SigAnnotationElement();
    838         String nameOfField = dexAnnotationAttribute.getName();
    839 
    840 
    841         String typeName = dexAnnotationAttribute.getAnnotation().getTypeName();
    842         SigClassDefinition annotationClass = factory.getClass(
    843                 getPackageName(typeName), getClassName(typeName));
    844         if (!Uninitialized.isInitialized(
    845                 annotationClass.getAnnotationFields())) {
    846             initializeClass(getPackageName(typeName), getClassName(typeName));
    847         }
    848         for (IAnnotationField field : annotationClass.getAnnotationFields()) {
    849             if (nameOfField.equals(field.getName())) {
    850                 sigElement.setDeclaringField(field);
    851             }
    852         }
    853 
    854         sigElement.setValue(convertEncodedValue(dexAnnotationAttribute
    855                 .getEncodedValue()));
    856         return sigElement;
    857     }
    858 
    859     @SuppressWarnings("unchecked")
    860     private Object convertEncodedValue(DexEncodedValue dexEnodedValue) {
    861         Object value = null;
    862         switch (dexEnodedValue.getType()) {
    863         case VALUE_INT:
    864         case VALUE_BOOLEAN:
    865         case VALUE_BYTE:
    866         case VALUE_CHAR:
    867         case VALUE_DOUBLE:
    868         case VALUE_FLOAT:
    869         case VALUE_LONG:
    870         case VALUE_NULL:
    871         case VALUE_STRING:
    872         case VALUE_SHORT:
    873             value = dexEnodedValue.getValue();
    874             break;
    875         case VALUE_ARRAY: {
    876             List<DexEncodedValue> dexValues =
    877                     (List<DexEncodedValue>) dexEnodedValue.getValue();
    878             Object[] arrayValues = new Object[dexValues.size()];
    879             int i = 0;
    880             for (DexEncodedValue dexValue : dexValues) {
    881                 arrayValues[i++] = convertEncodedValue(dexValue);
    882             }
    883             value = arrayValues;
    884             break;
    885         }
    886         case VALUE_ANNOTATION: {
    887             DexEncodedAnnotation annotation =
    888                     (DexEncodedAnnotation) dexEnodedValue.getValue();
    889             SigAnnotation sigAnnotation = new SigAnnotation();
    890             String packageName = getPackageName(annotation.getTypeName());
    891             String className = getClassName(annotation.getTypeName());
    892             sigAnnotation.setType(factory.getClassReference(packageName,
    893                     className));
    894 
    895             sigAnnotation.setElements(convertAnnotationElements(annotation
    896                     .getValue()));
    897             value = sigAnnotation;
    898             break;
    899         }
    900         case VALUE_FIELD: {
    901             String fieldDesc = (String) dexEnodedValue.getValue();
    902             // FORMAT La/b/E;!CONSTANT
    903             String[] typeAndFieldName = fieldDesc.split("!");
    904             String typeName = typeAndFieldName[0];
    905             String fieldName = typeAndFieldName[1];
    906             value = elementPool.getField(getQualifiedName(typeName), fieldName);
    907             break;
    908         }
    909         case VALUE_ENUM: {
    910             String fieldDesc = (String) dexEnodedValue.getValue();
    911             // FORMAT La/b/E;!CONSTANT
    912             String[] typeAndFieldName = fieldDesc.split("!");
    913             String typeName = typeAndFieldName[0];
    914             String fieldName = typeAndFieldName[1];
    915             value = elementPool.getEnumConstant(getQualifiedName(typeName),
    916                     fieldName);
    917             break;
    918         }
    919         case VALUE_TYPE: {
    920             String typeName = (String) dexEnodedValue.getValue();
    921             GenericSignatureParser parser = new GenericSignatureParser(factory,
    922                     this);
    923             value = parser.parseNonGenericReturnType(typeName);
    924             break;
    925         }
    926         default:
    927             throw new IllegalStateException();
    928         }
    929         return value;
    930     }
    931 
    932     public IClassDefinition initializeClass(String packageName,
    933             String className) {
    934         String dexName = getDexName(packageName, className);
    935         DexClass dexClass = dexNameToDexClass.get(dexName);
    936         return convertClass(dexClass);
    937     }
    938 }
    939