Remove a constructor from AppInfoWithLiveness.

This change also updates the static type of AppInfoWithSubtyping to require a
direct application, instead of converting it implicitly.

Bug: 139464956
Change-Id: I58e2f0791599f6cc9f1d3948bfe6367da86d2de3
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 2aa0ac5..5e47207 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerFactory;
 import com.android.tools.r8.shaking.MainDexClasses;
@@ -46,7 +46,7 @@
   private List<String> run(AndroidApp app, ExecutorService executor)
       throws IOException {
     try {
-      DexApplication application =
+      DirectMappedDexApplication application =
           new ApplicationReader(app, options, timing).read(executor).toDirect();
       AppView<? extends AppInfoWithSubtyping> appView =
           AppView.createForR8(new AppInfoWithSubtyping(application), options);
diff --git a/src/main/java/com/android/tools/r8/PrintSeeds.java b/src/main/java/com/android/tools/r8/PrintSeeds.java
index 654b5aa..41c399f 100644
--- a/src/main/java/com/android/tools/r8/PrintSeeds.java
+++ b/src/main/java/com/android/tools/r8/PrintSeeds.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerFactory;
@@ -84,7 +84,7 @@
     assert !options.forceProguardCompatibility;
     Timing timing = new Timing("PrintSeeds");
     try {
-      DexApplication application =
+      DirectMappedDexApplication application =
           new ApplicationReader(command.getInputApp(), options, timing).read(executor).toDirect();
       AppView<? extends AppInfoWithSubtyping> appView =
           AppView.createForR8(new AppInfoWithSubtyping(application), options);
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index ab5707a..d8d93ab 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.DexValue.DexValueType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
@@ -73,7 +74,7 @@
   private Map<DexType, Set<DexField>> fields = Maps.newIdentityHashMap();
   private Set<DexType> noObfuscationTypes = Sets.newIdentityHashSet();
   private Set<String> keepPackageNames = Sets.newHashSet();
-  private final DexApplication application;
+  private final DirectMappedDexApplication application;
   private final AppInfoWithSubtyping appInfo;
   private int errors;
 
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 4ae59e3..1ab4fc4 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
 import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
@@ -254,7 +255,7 @@
               "Running R8 version " + Version.LABEL + " with assertions enabled."));
     }
     try {
-      DexApplication application =
+      DirectMappedDexApplication application =
           new ApplicationReader(inputApp, options, timing).read(executorService).toDirect();
 
       // Now that the dex-application is fully loaded, close any internal archive providers.
@@ -315,7 +316,7 @@
                 .run(executorService));
 
         AppView<AppInfoWithLiveness> appViewWithLiveness = runEnqueuer(executorService, appView);
-        application = appViewWithLiveness.appInfo().app();
+        application = appViewWithLiveness.appInfo().app().asDirect();
         assert appView.rootSet().verifyKeptFieldsAreAccessedAndLive(appViewWithLiveness.appInfo());
         assert appView.rootSet().verifyKeptMethodsAreTargetedAndLive(appViewWithLiveness.appInfo());
         assert appView.rootSet().verifyKeptTypesAreLive(appViewWithLiveness.appInfo());
@@ -506,7 +507,7 @@
       CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
       try {
         IRConverter converter = new IRConverter(appView, timing, printer, mainDexClasses);
-        application = converter.optimize(executorService);
+        application = converter.optimize(executorService).asDirect();
       } finally {
         timing.end();
       }
@@ -691,7 +692,8 @@
 
       // Add automatic main dex classes to an eventual manual list of classes.
       if (!options.mainDexKeepRules.isEmpty()) {
-        application = application.builder().addToMainDexList(mainDexClasses.getClasses()).build();
+        application =
+            application.builder().addToMainDexList(mainDexClasses.getClasses()).build().asDirect();
       }
 
       // Perform minification.
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 4c7ea07..495c0b3 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -13,6 +13,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayDeque;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Deque;
 import java.util.HashSet;
@@ -141,11 +142,16 @@
   private final Map<DexType, Boolean> mayHaveFinalizeMethodDirectlyOrIndirectlyCache =
       new ConcurrentHashMap<>();
 
-  public AppInfoWithSubtyping(DexApplication application) {
+  public AppInfoWithSubtyping(DirectMappedDexApplication application) {
+    this(application, application.allClasses());
+  }
+
+  public AppInfoWithSubtyping(
+      DirectMappedDexApplication application, Collection<DexClass> classes) {
     super(application);
     typeInfo = new ConcurrentHashMap<>();
     // Recompute subtype map if we have modified the graph.
-    populateSubtypeMap(application.asDirect(), application.dexItemFactory);
+    populateSubtypeMap(classes, application::definitionFor, application.dexItemFactory);
   }
 
   protected AppInfoWithSubtyping(AppInfoWithSubtyping previous) {
@@ -283,16 +289,19 @@
     }
   }
 
-  private void populateSubtypeMap(DirectMappedDexApplication app, DexItemFactory dexItemFactory) {
+  private void populateSubtypeMap(
+      Collection<DexClass> classes,
+      Function<DexType, DexClass> definitions,
+      DexItemFactory dexItemFactory) {
     getTypeInfo(dexItemFactory.objectType).tagAsSubtypeRoot();
     Map<DexType, Set<DexType>> map = new IdentityHashMap<>();
-    for (DexClass clazz : app.allClasses()) {
-      populateAllSuperTypes(map, clazz.type, clazz, app::definitionFor);
+    for (DexClass clazz : classes) {
+      populateAllSuperTypes(map, clazz.type, clazz, definitions);
     }
     for (Map.Entry<DexType, Set<DexType>> entry : map.entrySet()) {
       subtypeMap.put(entry.getKey(), ImmutableSet.copyOf(entry.getValue()));
     }
-    assert validateLevelsAreCorrect(app::definitionFor, dexItemFactory);
+    assert validateLevelsAreCorrect(definitions, dexItemFactory);
   }
 
   private boolean validateLevelsAreCorrect(
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 0b19b93..389148c 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -233,7 +233,7 @@
     }
 
     @Override
-    public DexApplication build() {
+    public DirectMappedDexApplication build() {
       // Rebuild the map. This will fail if keys are not unique.
       // TODO(zerny): Consider not rebuilding the map if no program classes are added.
       Map<DexType, DexClass> allClasses =
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 2e47edf..fee3aff 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -8,7 +8,6 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClasspathClass;
@@ -190,7 +189,7 @@
 
   // TODO(zerny): Clean up the constructors so we have just one.
   AppInfoWithLiveness(
-      DexApplication application,
+      DirectMappedDexApplication application,
       Set<DexType> liveTypes,
       Set<DexType> instantiatedAnnotationTypes,
       Set<DexType> instantiatedAppServices,
@@ -402,7 +401,7 @@
 
   private AppInfoWithLiveness(
       AppInfoWithLiveness previous,
-      DexApplication application,
+      DirectMappedDexApplication application,
       Collection<DexType> removedClasses,
       Collection<DexReference> additionalPinnedItems) {
     this(
@@ -454,90 +453,6 @@
     assert removedClasses == null || assertNoItemRemoved(previous.pinnedItems, removedClasses);
   }
 
-  private AppInfoWithLiveness(
-      AppInfoWithLiveness previous, DirectMappedDexApplication application, GraphLense lense) {
-    super(application);
-    this.liveTypes = rewriteItems(previous.liveTypes, lense::lookupType);
-    this.instantiatedAnnotationTypes =
-        rewriteItems(previous.instantiatedAnnotationTypes, lense::lookupType);
-    this.instantiatedAppServices =
-        rewriteItems(previous.instantiatedAppServices, lense::lookupType);
-    this.instantiatedTypes = rewriteItems(previous.instantiatedTypes, lense::lookupType);
-    this.instantiatedLambdas = rewriteItems(previous.instantiatedLambdas, lense::lookupType);
-    this.targetedMethods = lense.rewriteMethodsConservatively(previous.targetedMethods);
-    this.failedResolutionTargets =
-        lense.rewriteMethodsConservatively(previous.failedResolutionTargets);
-    this.bootstrapMethods = lense.rewriteMethodsConservatively(previous.bootstrapMethods);
-    this.methodsTargetedByInvokeDynamic =
-        lense.rewriteMethodsConservatively(previous.methodsTargetedByInvokeDynamic);
-    this.virtualMethodsTargetedByInvokeDirect =
-        lense.rewriteMethodsConservatively(previous.virtualMethodsTargetedByInvokeDirect);
-    this.liveMethods = lense.rewriteMethodsConservatively(previous.liveMethods);
-    this.fieldAccessInfoCollection =
-        previous.fieldAccessInfoCollection.rewrittenWithLens(application, lense);
-    this.pinnedItems = lense.rewriteReferencesConservatively(previous.pinnedItems);
-    this.virtualInvokes =
-        rewriteKeysConservativelyWhileMergingValues(
-            previous.virtualInvokes, lense::lookupMethodInAllContexts);
-    this.interfaceInvokes =
-        rewriteKeysConservativelyWhileMergingValues(
-            previous.interfaceInvokes, lense::lookupMethodInAllContexts);
-    this.superInvokes =
-        rewriteKeysConservativelyWhileMergingValues(
-            previous.superInvokes, lense::lookupMethodInAllContexts);
-    this.directInvokes =
-        rewriteKeysConservativelyWhileMergingValues(
-            previous.directInvokes, lense::lookupMethodInAllContexts);
-    this.staticInvokes =
-        rewriteKeysConservativelyWhileMergingValues(
-            previous.staticInvokes, lense::lookupMethodInAllContexts);
-    // TODO(sgjesse): Rewrite call sites as well? Right now they are only used by minification
-    // after second tree shaking.
-    this.callSites = previous.callSites;
-    // Don't rewrite pruned types - the removed types are identified by their original name.
-    this.prunedTypes = previous.prunedTypes;
-    this.mayHaveSideEffects =
-        rewriteReferenceKeys(previous.mayHaveSideEffects, lense::lookupReference);
-    this.noSideEffects = rewriteReferenceKeys(previous.noSideEffects, lense::lookupReference);
-    this.assumedValues = rewriteReferenceKeys(previous.assumedValues, lense::lookupReference);
-    assert lense.assertDefinitionsNotModified(
-        previous.alwaysInline.stream()
-            .map(this::definitionFor)
-            .filter(Objects::nonNull)
-            .collect(Collectors.toList()));
-    this.alwaysInline = lense.rewriteMethodsWithRenamedSignature(previous.alwaysInline);
-    this.forceInline = lense.rewriteMethodsWithRenamedSignature(previous.forceInline);
-    this.neverInline = lense.rewriteMethodsWithRenamedSignature(previous.neverInline);
-    this.whyAreYouNotInlining =
-        lense.rewriteMethodsWithRenamedSignature(previous.whyAreYouNotInlining);
-    this.keepConstantArguments =
-        lense.rewriteMethodsWithRenamedSignature(previous.keepConstantArguments);
-    this.keepUnusedArguments =
-        lense.rewriteMethodsWithRenamedSignature(previous.keepUnusedArguments);
-    this.reprocess = lense.rewriteMethodsWithRenamedSignature(previous.reprocess);
-    this.neverReprocess = lense.rewriteMethodsWithRenamedSignature(previous.neverReprocess);
-    assert lense.assertDefinitionsNotModified(
-        previous.neverMerge.stream()
-            .map(this::definitionFor)
-            .filter(Objects::nonNull)
-            .collect(Collectors.toList()));
-    this.alwaysClassInline = previous.alwaysClassInline.rewriteItems(lense::lookupType);
-    this.neverClassInline = rewriteItems(previous.neverClassInline, lense::lookupType);
-    this.neverMerge = rewriteItems(previous.neverMerge, lense::lookupType);
-    this.neverPropagateValue = lense.rewriteReferencesConservatively(previous.neverPropagateValue);
-    this.identifierNameStrings =
-        lense.rewriteReferencesConservatively(previous.identifierNameStrings);
-    // Switchmap classes should never be affected by renaming.
-    assert lense.assertDefinitionsNotModified(
-        previous.switchMaps.keySet().stream()
-            .map(this::definitionFor)
-            .filter(Objects::nonNull)
-            .collect(Collectors.toList()));
-    this.switchMaps = rewriteReferenceKeys(previous.switchMaps, lense::lookupField);
-    this.enumValueInfoMaps = rewriteReferenceKeys(previous.enumValueInfoMaps, lense::lookupType);
-    this.constClassReferences = previous.constClassReferences;
-  }
-
   public AppInfoWithLiveness(
       AppInfoWithLiveness previous,
       Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
@@ -693,7 +608,7 @@
   // TODO(b/139464956): Reimplement using only reachable types.
   public DexProgramClass getSingleDirectSubtype(DexProgramClass clazz) {
     DexType subtype = super.getSingleSubtype_(clazz.type);
-    return subtype == null ? null : DexProgramClass.asProgramClassOrNull(definitionFor(subtype));
+    return subtype == null ? null : asProgramClassOrNull(definitionFor(subtype));
   }
 
   /**
@@ -1040,7 +955,7 @@
    * DexApplication object.
    */
   public AppInfoWithLiveness prunedCopyFrom(
-      DexApplication application,
+      DirectMappedDexApplication application,
       Collection<DexType> removedClasses,
       Collection<DexReference> additionalPinnedItems) {
     assert checkIfObsolete();
@@ -1050,7 +965,74 @@
   public AppInfoWithLiveness rewrittenWithLense(
       DirectMappedDexApplication application, GraphLense lense) {
     assert checkIfObsolete();
-    return new AppInfoWithLiveness(this, application, lense);
+
+    // Switchmap classes should never be affected by renaming.
+    assert lense.assertDefinitionsNotModified(
+        switchMaps.keySet().stream()
+            .map(this::definitionFor)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toList()));
+
+    assert lense.assertDefinitionsNotModified(
+        neverMerge.stream()
+            .map(this::definitionFor)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toList()));
+
+    assert lense.assertDefinitionsNotModified(
+        alwaysInline.stream()
+            .map(this::definitionFor)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toList()));
+
+    return new AppInfoWithLiveness(
+        application,
+        rewriteItems(liveTypes, lense::lookupType),
+        rewriteItems(instantiatedAnnotationTypes, lense::lookupType),
+        rewriteItems(instantiatedAppServices, lense::lookupType),
+        rewriteItems(instantiatedTypes, lense::lookupType),
+        lense.rewriteMethodsConservatively(targetedMethods),
+        lense.rewriteMethodsConservatively(failedResolutionTargets),
+        lense.rewriteMethodsConservatively(bootstrapMethods),
+        lense.rewriteMethodsConservatively(methodsTargetedByInvokeDynamic),
+        lense.rewriteMethodsConservatively(virtualMethodsTargetedByInvokeDirect),
+        lense.rewriteMethodsConservatively(liveMethods),
+        fieldAccessInfoCollection.rewrittenWithLens(application, lense),
+        rewriteKeysConservativelyWhileMergingValues(
+            virtualInvokes, lense::lookupMethodInAllContexts),
+        rewriteKeysConservativelyWhileMergingValues(
+            interfaceInvokes, lense::lookupMethodInAllContexts),
+        rewriteKeysConservativelyWhileMergingValues(superInvokes, lense::lookupMethodInAllContexts),
+        rewriteKeysConservativelyWhileMergingValues(
+            directInvokes, lense::lookupMethodInAllContexts),
+        rewriteKeysConservativelyWhileMergingValues(
+            staticInvokes, lense::lookupMethodInAllContexts),
+        // TODO(sgjesse): Rewrite call sites as well? Right now they are only used by minification
+        //   after second tree shaking.
+        callSites,
+        lense.rewriteReferencesConservatively(pinnedItems),
+        rewriteReferenceKeys(mayHaveSideEffects, lense::lookupReference),
+        rewriteReferenceKeys(noSideEffects, lense::lookupReference),
+        rewriteReferenceKeys(assumedValues, lense::lookupReference),
+        lense.rewriteMethodsWithRenamedSignature(alwaysInline),
+        lense.rewriteMethodsWithRenamedSignature(forceInline),
+        lense.rewriteMethodsWithRenamedSignature(neverInline),
+        lense.rewriteMethodsWithRenamedSignature(whyAreYouNotInlining),
+        lense.rewriteMethodsWithRenamedSignature(keepConstantArguments),
+        lense.rewriteMethodsWithRenamedSignature(keepUnusedArguments),
+        lense.rewriteMethodsWithRenamedSignature(reprocess),
+        lense.rewriteMethodsWithRenamedSignature(neverReprocess),
+        alwaysClassInline.rewriteItems(lense::lookupType),
+        rewriteItems(neverClassInline, lense::lookupType),
+        rewriteItems(neverMerge, lense::lookupType),
+        lense.rewriteReferencesConservatively(neverPropagateValue),
+        lense.rewriteReferencesConservatively(identifierNameStrings),
+        // Don't rewrite pruned types - the removed types are identified by their original name.
+        prunedTypes,
+        rewriteReferenceKeys(switchMaps, lense::lookupField),
+        rewriteReferenceKeys(enumValueInfoMaps, lense::lookupType),
+        rewriteItems(instantiatedLambdas, lense::lookupType),
+        constClassReferences);
   }
 
   /**
@@ -1470,9 +1452,9 @@
   }
 
   // Split in a static method so it can be used during construction.
-  private static void forEachTypeInHierarchyOfLiveProgramClasses(
+  static void forEachTypeInHierarchyOfLiveProgramClasses(
       Consumer<DexClass> fn,
-      List<DexProgramClass> liveProgramClasses,
+      Collection<DexProgramClass> liveProgramClasses,
       Set<DexCallSite> callSites,
       AppInfoWithClassHierarchy appInfo) {
     Set<DexType> seen = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 7e381ef..ba1bdb5 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -28,7 +28,6 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Descriptor;
 import com.android.tools.r8.graph.DexAnnotation;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClasspathClass;
@@ -2336,7 +2335,7 @@
     DirectMappedDexApplication.Builder appBuilder = appInfo.app().asDirect().builder();
     postProcessLambdaDesugaring(appBuilder);
     postProcessLibraryConversionWrappers(appBuilder);
-    DexApplication app = appBuilder.build();
+    DirectMappedDexApplication app = appBuilder.build();
 
     AppInfoWithLiveness appInfoWithLiveness =
         new AppInfoWithLiveness(
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
index bfefefa..718b9a9 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -6,12 +6,12 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.DexAnnotation;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Maps;
 import java.util.Map;
@@ -29,14 +29,14 @@
   private final Set<DexType> roots;
   private final AppInfoWithSubtyping appInfo;
   private final Map<DexType, Boolean> annotationTypeContainEnum;
-  private final DexApplication dexApplication;
+  private final DirectMappedDexApplication dexApplication;
   private final MainDexClasses.Builder mainDexClassesBuilder;
 
   /**
    * @param roots Classes which code may be executed before secondary dex files loading.
    * @param application the dex appplication.
    */
-  public MainDexListBuilder(Set<DexProgramClass> roots, DexApplication application) {
+  public MainDexListBuilder(Set<DexProgramClass> roots, DirectMappedDexApplication application) {
     this.dexApplication = application;
     this.appInfo = new AppInfoWithSubtyping(dexApplication);
     // Only consider program classes for the root set.
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 116e315..dc66249 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.shaking;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -13,6 +12,7 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.KeyedDexItem;
@@ -56,10 +56,10 @@
             : UsagePrinter.DONT_PRINT;
   }
 
-  public DexApplication run(DexApplication application) {
+  public DirectMappedDexApplication run(DirectMappedDexApplication application) {
     Timing timing = application.timing;
     timing.begin("Pruning application...");
-    DexApplication result;
+    DirectMappedDexApplication result;
     try {
       result = removeUnused(application).build();
     } finally {
@@ -68,7 +68,7 @@
     return result;
   }
 
-  private DexApplication.Builder<?> removeUnused(DexApplication application) {
+  private DirectMappedDexApplication.Builder removeUnused(DirectMappedDexApplication application) {
     return application.builder()
         .replaceProgramClasses(getNewProgramClasses(application.classes()));
   }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 1c9972c..5094ec5 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -33,6 +33,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.SmaliWriter;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.origin.Origin;
@@ -589,7 +590,8 @@
       throws Exception {
     Timing timing = Timing.empty();
     InternalOptions options = new InternalOptions();
-    DexApplication application = new ApplicationReader(app, options, timing).read().toDirect();
+    DirectMappedDexApplication application =
+        new ApplicationReader(app, options, timing).read().toDirect();
     AppView<AppInfoWithSubtyping> appView =
         AppView.createForR8(new AppInfoWithSubtyping(application), options);
     appView.setAppServices(AppServices.builder(appView).build());
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 8c2c26c..f9c1086 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.graph.AssemblyWriter;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
@@ -1066,14 +1067,13 @@
     return String.join("/", parts);
   }
 
-  public static DexApplication buildApplication(List<String> fileNames)
+  public static DirectMappedDexApplication buildApplication(List<String> fileNames)
       throws IOException, ExecutionException {
     return buildApplicationWithAndroidJar(fileNames, getDefaultAndroidJar());
   }
 
-  public static DexApplication buildApplicationWithAndroidJar(
-      List<String> fileNames, Path androidJar)
-      throws IOException, ExecutionException {
+  public static DirectMappedDexApplication buildApplicationWithAndroidJar(
+      List<String> fileNames, Path androidJar) throws IOException, ExecutionException {
     AndroidApp input =
         AndroidApp.builder()
             .addProgramFiles(ListUtils.map(fileNames, Paths::get))
diff --git a/src/test/java/com/android/tools/r8/graph/DexTypeTest.java b/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
index 90218e0..1b5ffa9 100644
--- a/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
@@ -24,7 +24,7 @@
   @BeforeClass
   public static void makeAppInfo() throws Exception {
     InternalOptions options = new InternalOptions();
-    DexApplication application =
+    DirectMappedDexApplication application =
         new ApplicationReader(
                 AndroidApp.builder()
                     .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index 34d7c61..a2b9dce 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -48,7 +48,7 @@
       List<IRCode> additionalCode)
       throws ExecutionException {
     AppView<AppInfoWithSubtyping> appView =
-        AppView.createForR8(new AppInfoWithSubtyping(application), options);
+        AppView.createForR8(new AppInfoWithSubtyping(application.asDirect()), options);
     appView.setAppServices(AppServices.builder(appView).build());
     ExecutorService executorService = ThreadUtils.getExecutorService(options);
     appView.setRootSet(
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
index 7321e79..ebfb64f 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.utils.AndroidApp;
@@ -64,7 +64,7 @@
 
   @Before
   public void setup() throws Exception {
-    DexApplication application =
+    DirectMappedDexApplication application =
         new ApplicationReader(app, options, Timing.empty()).read().toDirect();
     appView = AppView.createForR8(new AppInfoWithSubtyping(application), options);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
index 979de40..6a4bd17 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -18,11 +18,11 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
@@ -122,7 +122,7 @@
             ? ClassFileConsumer.emptyConsumer()
             : DexIndexedConsumer.emptyConsumer();
     Timing timing = Timing.empty();
-    DexApplication application =
+    DirectMappedDexApplication application =
         new ApplicationReader(
                 AndroidApp.builder()
                     .addClassProgramData(
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index e0465b3..cac6ef5 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -17,9 +17,9 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -50,7 +50,7 @@
     D8Command.Builder d8CommandBuilder = D8Command.builder();
     d8CommandBuilder.addProgramFiles(testClassPaths);
     AndroidApp testClassApp = ToolHelper.runD8(d8CommandBuilder);
-    DexApplication application =
+    DirectMappedDexApplication application =
         new ApplicationReader(
                 AndroidApp.builder(testClassApp)
                     .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
index 5f685eb..1955c47 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
@@ -14,9 +14,9 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.ir.conversion.CallGraph.Node;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.Enqueuer;
@@ -42,7 +42,8 @@
   public PartialCallGraphTest() throws Exception {
     Timing timing = Timing.empty();
     AndroidApp app = testForD8().addProgramClasses(TestClass.class).compile().app;
-    DexApplication application = new ApplicationReader(app, options, timing).read().toDirect();
+    DirectMappedDexApplication application =
+        new ApplicationReader(app, options, timing).read().toDirect();
     AppView<AppInfoWithSubtyping> appView =
         AppView.createForR8(new AppInfoWithSubtyping(application), options);
     appView.setAppServices(AppServices.builder(appView).build());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java
index a24de2f..41eba43 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstraintWithTargetTest.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.utils.AndroidApp;
@@ -27,7 +27,7 @@
   @BeforeClass
   public static void makeAppInfo() throws Exception {
     InternalOptions options = new InternalOptions();
-    DexApplication application =
+    DirectMappedDexApplication application =
         new ApplicationReader(
                 AndroidApp.builder().addLibraryFiles(ToolHelper.getDefaultAndroidJar()).build(),
                 options,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
index 838a681..15456be 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
@@ -20,7 +20,8 @@
     Timing timing = Timing.empty();
     AndroidApp app = buildAndroidApp(ToolHelper.getClassAsBytes(mainClass));
     InternalOptions options = new InternalOptions();
-    DexApplication dexApplication = new ApplicationReader(app, options, timing).read().toDirect();
+    DirectMappedDexApplication dexApplication =
+        new ApplicationReader(app, options, timing).read().toDirect();
     AppView<?> appView = AppView.createForD8(new AppInfoWithSubtyping(dexApplication), options);
     appView.setAppServices(AppServices.builder(appView).build());
     return appView;
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index b03aeaa..f0b3c24 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerFactory;
 import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -41,7 +41,7 @@
 
   private final Timing timing;
 
-  private DexApplication program;
+  private DirectMappedDexApplication program;
   protected DexItemFactory dexItemFactory;
 
   protected NamingTestBase(
diff --git a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
index c7f8ef9..8034ad7 100644
--- a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -36,7 +36,8 @@
             .addLibraryFile(ToolHelper.getDefaultAndroidJar())
             .addProgramFiles(ToolHelper.getClassFileForTestClass(Foo.class))
             .build();
-    DexApplication application = new ApplicationReader(app, options, timing).read().toDirect();
+    DirectMappedDexApplication application =
+        new ApplicationReader(app, options, timing).read().toDirect();
     AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
     DexItemFactory factory = options.itemFactory;
     DexType fooType =
diff --git a/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java b/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java
index c1998bd..e64933b 100644
--- a/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java
@@ -9,9 +9,9 @@
 
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
@@ -21,7 +21,7 @@
 public class R8Shaking2LookupTest {
 
   static final String APP_FILE_NAME = ToolHelper.EXAMPLES_BUILD_DIR + "shaking2/classes.dex";
-  private DexApplication program;
+  private DirectMappedDexApplication program;
   private DexItemFactory dexItemFactory;
   private AppInfoWithSubtyping appInfo;