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      */
DexToSigConverter()122     public DexToSigConverter() {
123         factory = new TypePool();
124         elementPool = new FieldPool();
125     }
126 
127 
convertApi(String apiName, Set<DexFile> dexFiles, Visibility visibility)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      */
convertPackages(Set<DexFile> parsedFiles)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 
hasInvisibleParent(IClassDefinition sigClass, Map<String, DexClass> dexNameToDexClass)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      */
convertPackage(String packageName)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      */
convertClasses(Set<DexClass> dexClasses)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      */
convertClass(DexClass dexClass)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")
getDefaultValueMapping(DexClass dexClass)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 
addAnnotationsToAnnotationFields(List<DexMethod> methods, Set<SigAnnotationField> annotationFields)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 
convertAnnotationFields( List<DexMethod> list, Map<String, Object> mappings)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 
convertAnnotationField(DexMethod dexMethod, Object defaultValue)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 
convertEnumConstant(DexField dexField)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 
convertFields(List<DexField> dexFields)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 
convertField(DexField dexField)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      */
convertConstructors(List<DexMethod> methods)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      */
convertMethods(List<DexMethod> methods)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      */
convertConstructor(DexMethod dexMethod)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 
convertMethod(DexMethod dexMethod)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 
addExceptions(SigExecutableMember member, DexMethod dexMethod)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 
convertNonGenericExecutableMember(SigExecutableMember member, DexMethod dexMethod)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      */
convertAnnotations( Set<DexAnnotation> dexAnnotations)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      */
convertAnnotation(DexAnnotation dexAnnotation)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 
convertAnnotationElements( List<DexAnnotationAttribute> attributes)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 
convertAnnotationAttribute( DexAnnotationAttribute dexAnnotationAttribute)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")
convertEncodedValue(DexEncodedValue dexEnodedValue)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 
initializeClass(String packageName, String className)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