1418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// for details. All rights reserved. Use of this source code is governed by a
3418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// BSD-style license that can be found in the LICENSE file.
4418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpackage com.android.tools.r8;
5418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
6418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.dex.ApplicationReader;
7418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexApplication;
8418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexEncodedField;
9418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexEncodedMethod;
10418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexField;
11418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMethod;
12418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexProgramClass;
13418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexType;
14418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.naming.ClassNameMapper;
15418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.naming.MemberNaming.FieldSignature;
16418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.naming.MemberNaming.MethodSignature;
17418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.AndroidApp;
18418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.AndroidApp.Builder;
19418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.InternalOptions;
20418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.ListUtils;
21418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.Timing;
22418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.IOException;
23418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Paths;
24418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Arrays;
25418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.List;
26418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.concurrent.ExecutionException;
27418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.concurrent.ExecutorService;
28418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.concurrent.Executors;
29418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
30418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpublic class PrintClassList {
31418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
32418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public static void main(String[] args) throws IOException, ExecutionException {
33418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    List<String> dexFiles = Arrays.asList(args);
34418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Builder builder = AndroidApp.builder();
35418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (args[0].endsWith("map")) {
36418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      builder.setProguardMapFile(Paths.get(args[0]));
37418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      dexFiles = dexFiles.subList(1, dexFiles.size());
38418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
398842c41758db478ebc54437f583367750cd18378Alan Leung    builder.addProgramFiles(ListUtils.map(dexFiles, Paths::get), false);
40418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
41418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    ExecutorService executorService = Executors.newCachedThreadPool();
42418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexApplication application =
43418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new ApplicationReader(builder.build(), new InternalOptions(), new Timing("PrintClassList"))
44418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            .read(executorService);
45418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    ClassNameMapper map = application.getProguardMap();
46418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (DexProgramClass clazz : application.classes()) {
47418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      System.out.print(maybeDeobfuscateType(map, clazz.type));
48418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      System.out.println();
49418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      printMethods(clazz.directMethods(), map);
50418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      printMethods(clazz.virtualMethods(), map);
51418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      printFields(clazz.staticFields(), map);
52418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      printFields(clazz.instanceFields(), map);
53418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
54418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    executorService.shutdown();
55418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
56418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
57418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void printMethods(DexEncodedMethod[] methods, ClassNameMapper map) {
58418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (DexEncodedMethod encodedMethod : methods) {
59418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexMethod method = encodedMethod.method;
60418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
61418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (map != null) {
62418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        System.out.println(map.originalNameOf(method));
63418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      } else {
64418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // Detour via Signature to get the same formatting.
65418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        MethodSignature signature = MethodSignature.fromDexMethod(method);
66418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        System.out.println(method.holder.toSourceString() + " " + signature);
67418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
68418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
69418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
70418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
71418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void printFields(DexEncodedField[] fields, ClassNameMapper map) {
72418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (DexEncodedField encodedField : fields) {
73418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexField field = encodedField.field;
74418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (map != null) {
75418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        System.out.println(map.originalNameOf(field));
76418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      } else {
77418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // Detour via Signature to get the same formatting.
78418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        FieldSignature signature = new FieldSignature(field.name.toSourceString(),
79418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            field.type.toSourceString());
80418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        System.out.println(field.clazz.toSourceString() + " " + signature);
81418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
82418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
83418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
84418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
85418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static String maybeDeobfuscateType(ClassNameMapper map, DexType type) {
86418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return map == null ? type.toSourceString() : map.originalNameOf(type);
87418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
88418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager}
89