Refactor NestedGraphLens to a top-level class
Bug: 182099754
Change-Id: I73560e7b5f10c38ed5345cdb72bedc25d85ee73f
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 3912ae6..9e056df 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.SetUtils;
-import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
@@ -33,7 +32,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
/**
* A GraphLens implements a virtual view on top of the graph, used to delay global rewrites until
@@ -959,288 +957,4 @@
return getIdentityLens().isContextFreeForMethods();
}
}
-
- /**
- * GraphLens implementation with a parent lens using a simple mapping for type, method and field
- * mapping.
- *
- * <p>Subclasses can override the lookup methods.
- *
- * <p>For method mapping where invocation type can change just override {@link
- * #mapInvocationType(DexMethod, DexMethod, Type)} if the default name mapping applies, and only
- * invocation type might need to change.
- */
- public static class NestedGraphLens extends NonIdentityGraphLens {
-
- protected final DexItemFactory dexItemFactory;
-
- protected final Map<DexType, DexType> typeMap;
- protected final Map<DexMethod, DexMethod> methodMap;
- protected final BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap;
-
- // Map that store the original signature of methods that have been affected, for example, by
- // vertical class merging. Needed to generate a correct Proguard map in the end.
- protected BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod>
- originalMethodSignatures;
-
- // Overrides this if the sub type needs to be a nested lens while it doesn't have any mappings
- // at all, e.g., publicizer lens that changes invocation type only.
- protected boolean isLegitimateToHaveEmptyMappings() {
- return false;
- }
-
- public NestedGraphLens(
- Map<DexType, DexType> typeMap,
- Map<DexMethod, DexMethod> methodMap,
- BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
- BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures,
- GraphLens previousLens,
- DexItemFactory dexItemFactory) {
- super(dexItemFactory, previousLens);
- assert !typeMap.isEmpty()
- || !methodMap.isEmpty()
- || !fieldMap.isEmpty()
- || isLegitimateToHaveEmptyMappings();
- this.typeMap = typeMap.isEmpty() ? null : typeMap;
- this.methodMap = methodMap;
- this.fieldMap = fieldMap;
- this.originalMethodSignatures = originalMethodSignatures;
- this.dexItemFactory = dexItemFactory;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- protected DexType internalGetOriginalType(DexType previous) {
- return previous;
- }
-
- protected Iterable<DexType> internalGetOriginalTypes(DexType previous) {
- return IterableUtils.singleton(internalGetOriginalType(previous));
- }
-
- @Override
- public DexType getOriginalType(DexType type) {
- return getPrevious().getOriginalType(internalGetOriginalType(type));
- }
-
- @Override
- public Iterable<DexType> getOriginalTypes(DexType type) {
- return IterableUtils.flatMap(internalGetOriginalTypes(type), getPrevious()::getOriginalTypes);
- }
-
- @Override
- public DexField getOriginalFieldSignature(DexField field) {
- DexField originalField = fieldMap.getRepresentativeKeyOrDefault(field, field);
- return getPrevious().getOriginalFieldSignature(originalField);
- }
-
- @Override
- public DexMethod getOriginalMethodSignature(DexMethod method) {
- DexMethod originalMethod = internalGetPreviousMethodSignature(method);
- return getPrevious().getOriginalMethodSignature(originalMethod);
- }
-
- @Override
- public DexField getRenamedFieldSignature(DexField originalField) {
- DexField renamedField = getPrevious().getRenamedFieldSignature(originalField);
- return internalGetNextFieldSignature(renamedField);
- }
-
- @Override
- public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
- if (this == applied) {
- return originalMethod;
- }
- DexMethod renamedMethod = getPrevious().getRenamedMethodSignature(originalMethod, applied);
- return internalGetNextMethodSignature(renamedMethod);
- }
-
- @Override
- protected DexType internalDescribeLookupClassType(DexType previous) {
- return typeMap != null ? typeMap.getOrDefault(previous, previous) : previous;
- }
-
- @Override
- protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
- if (previous.hasReboundReference()) {
- // Rewrite the rebound reference and then "fixup" the non-rebound reference.
- DexField rewrittenReboundReference = previous.getRewrittenReboundReference(fieldMap);
- DexField rewrittenNonReboundReference =
- previous.getReference() == previous.getReboundReference()
- ? rewrittenReboundReference
- : rewrittenReboundReference.withHolder(
- internalDescribeLookupClassType(previous.getReference().getHolderType()),
- dexItemFactory);
- return FieldLookupResult.builder(this)
- .setReboundReference(rewrittenReboundReference)
- .setReference(rewrittenNonReboundReference)
- .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType))
- .build();
- } else {
- // TODO(b/168282032): We should always have the rebound reference, so this should become
- // unreachable.
- DexField rewrittenReference = previous.getRewrittenReference(fieldMap);
- return FieldLookupResult.builder(this)
- .setReference(rewrittenReference)
- .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType))
- .build();
- }
- }
-
- @Override
- public MethodLookupResult internalDescribeLookupMethod(
- MethodLookupResult previous, DexMethod context) {
- if (previous.hasReboundReference()) {
- // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win
- // that only subclasses which are known to need it actually do it?
- DexMethod rewrittenReboundReference = previous.getRewrittenReboundReference(methodMap);
- DexMethod rewrittenReference =
- previous.getReference() == previous.getReboundReference()
- ? rewrittenReboundReference
- : // This assumes that the holder will always be moved in lock-step with the method!
- rewrittenReboundReference.withHolder(
- internalDescribeLookupClassType(previous.getReference().getHolderType()),
- dexItemFactory);
- return MethodLookupResult.builder(this)
- .setReference(rewrittenReference)
- .setReboundReference(rewrittenReboundReference)
- .setPrototypeChanges(
- internalDescribePrototypeChanges(
- previous.getPrototypeChanges(), rewrittenReboundReference))
- .setType(
- mapInvocationType(
- rewrittenReboundReference, previous.getReference(), previous.getType()))
- .build();
- } else {
- // TODO(b/168282032): We should always have the rebound reference, so this should become
- // unreachable.
- DexMethod newMethod = methodMap.get(previous.getReference());
- if (newMethod == null) {
- return previous;
- }
- // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win
- // that only subclasses which are known to need it actually do it?
- return MethodLookupResult.builder(this)
- .setReference(newMethod)
- .setPrototypeChanges(
- internalDescribePrototypeChanges(previous.getPrototypeChanges(), newMethod))
- .setType(mapInvocationType(newMethod, previous.getReference(), previous.getType()))
- .build();
- }
- }
-
- @Override
- public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
- DexMethod method) {
- DexMethod previous = internalGetPreviousMethodSignature(method);
- RewrittenPrototypeDescription lookup =
- getPrevious().lookupPrototypeChangesForMethodDefinition(previous);
- return internalDescribePrototypeChanges(lookup, method);
- }
-
- protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
- RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
- return prototypeChanges;
- }
-
- protected DexField internalGetNextFieldSignature(DexField field) {
- return fieldMap.getOrDefault(field, field);
- }
-
- @Override
- protected DexMethod internalGetPreviousMethodSignature(DexMethod method) {
- return originalMethodSignatures.getRepresentativeValueOrDefault(method, method);
- }
-
- protected DexMethod internalGetNextMethodSignature(DexMethod method) {
- return originalMethodSignatures.getRepresentativeKeyOrDefault(method, method);
- }
-
- @Override
- public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) {
- return getPrevious().lookupGetFieldForMethod(field, context);
- }
-
- @Override
- public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) {
- return getPrevious().lookupPutFieldForMethod(field, context);
- }
-
- /**
- * Default invocation type mapping.
- *
- * <p>This is an identity mapping. If a subclass need invocation type mapping either override
- * this method or {@link #lookupMethod(DexMethod, DexMethod, Type)}
- */
- protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) {
- return type;
- }
-
- /**
- * Standard mapping between interface and virtual invoke type.
- *
- * <p>Handle methods moved from interface to class or class to interface.
- */
- public static Type mapVirtualInterfaceInvocationTypes(
- DexDefinitionSupplier definitions,
- DexMethod newMethod,
- DexMethod originalMethod,
- Type type) {
- if (type == Type.VIRTUAL || type == Type.INTERFACE) {
- // Get the invoke type of the actual definition.
- DexClass newTargetClass = definitions.definitionFor(newMethod.getHolderType());
- if (newTargetClass == null) {
- return type;
- }
- DexClass originalTargetClass = definitions.definitionFor(originalMethod.getHolderType());
- if (originalTargetClass != null
- && (originalTargetClass.isInterface() ^ (type == Type.INTERFACE))) {
- // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
- // the IncompatibleClassChangeError the original invoke would have triggered.
- return newTargetClass.accessFlags.isInterface() ? Type.VIRTUAL : Type.INTERFACE;
- }
- return newTargetClass.accessFlags.isInterface() ? Type.INTERFACE : Type.VIRTUAL;
- }
- return type;
- }
-
- @Override
- public boolean isContextFreeForMethods() {
- return getPrevious().isContextFreeForMethods();
- }
-
- @Override
- public boolean verifyIsContextFreeForMethod(DexMethod method) {
- assert getPrevious().verifyIsContextFreeForMethod(method);
- return true;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- if (typeMap != null) {
- for (Map.Entry<DexType, DexType> entry : typeMap.entrySet()) {
- builder.append(entry.getKey().toSourceString()).append(" -> ");
- builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
- }
- }
- for (Map.Entry<DexMethod, DexMethod> entry : methodMap.entrySet()) {
- builder.append(entry.getKey().toSourceString()).append(" -> ");
- builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
- }
- fieldMap.forEachManyToOneMapping(
- (keys, value) -> {
- builder.append(
- keys.stream()
- .map(DexField::toSourceString)
- .collect(Collectors.joining("," + System.lineSeparator())));
- builder.append(" -> ");
- builder.append(value.toSourceString()).append(System.lineSeparator());
- });
- builder.append(getPrevious().toString());
- return builder.toString();
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
new file mode 100644
index 0000000..84e2a37
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
@@ -0,0 +1,292 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * GraphLens implementation with a parent lens using a simple mapping for type, method and field
+ * mapping.
+ *
+ * <p>Subclasses can override the lookup methods.
+ *
+ * <p>For method mapping where invocation type can change just override {@link
+ * #mapInvocationType(DexMethod, DexMethod, Type)} if the default name mapping applies, and only
+ * invocation type might need to change.
+ */
+public class NestedGraphLens extends NonIdentityGraphLens {
+
+ protected final DexItemFactory dexItemFactory;
+
+ protected final Map<DexType, DexType> typeMap;
+ protected final Map<DexMethod, DexMethod> methodMap;
+ protected final BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap;
+
+ // Map that store the original signature of methods that have been affected, for example, by
+ // vertical class merging. Needed to generate a correct Proguard map in the end.
+ protected BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures;
+
+ // Overrides this if the sub type needs to be a nested lens while it doesn't have any mappings
+ // at all, e.g., publicizer lens that changes invocation type only.
+ protected boolean isLegitimateToHaveEmptyMappings() {
+ return false;
+ }
+
+ public NestedGraphLens(
+ Map<DexType, DexType> typeMap,
+ Map<DexMethod, DexMethod> methodMap,
+ BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
+ BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures,
+ GraphLens previousLens,
+ DexItemFactory dexItemFactory) {
+ super(dexItemFactory, previousLens);
+ assert !typeMap.isEmpty()
+ || !methodMap.isEmpty()
+ || !fieldMap.isEmpty()
+ || isLegitimateToHaveEmptyMappings();
+ this.typeMap = typeMap.isEmpty() ? null : typeMap;
+ this.methodMap = methodMap;
+ this.fieldMap = fieldMap;
+ this.originalMethodSignatures = originalMethodSignatures;
+ this.dexItemFactory = dexItemFactory;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ protected DexType internalGetOriginalType(DexType previous) {
+ return previous;
+ }
+
+ protected Iterable<DexType> internalGetOriginalTypes(DexType previous) {
+ return IterableUtils.singleton(internalGetOriginalType(previous));
+ }
+
+ @Override
+ public DexType getOriginalType(DexType type) {
+ return getPrevious().getOriginalType(internalGetOriginalType(type));
+ }
+
+ @Override
+ public Iterable<DexType> getOriginalTypes(DexType type) {
+ return IterableUtils.flatMap(internalGetOriginalTypes(type), getPrevious()::getOriginalTypes);
+ }
+
+ @Override
+ public DexField getOriginalFieldSignature(DexField field) {
+ DexField originalField = fieldMap.getRepresentativeKeyOrDefault(field, field);
+ return getPrevious().getOriginalFieldSignature(originalField);
+ }
+
+ @Override
+ public DexMethod getOriginalMethodSignature(DexMethod method) {
+ DexMethod originalMethod = internalGetPreviousMethodSignature(method);
+ return getPrevious().getOriginalMethodSignature(originalMethod);
+ }
+
+ @Override
+ public DexField getRenamedFieldSignature(DexField originalField) {
+ DexField renamedField = getPrevious().getRenamedFieldSignature(originalField);
+ return internalGetNextFieldSignature(renamedField);
+ }
+
+ @Override
+ public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
+ if (this == applied) {
+ return originalMethod;
+ }
+ DexMethod renamedMethod = getPrevious().getRenamedMethodSignature(originalMethod, applied);
+ return internalGetNextMethodSignature(renamedMethod);
+ }
+
+ @Override
+ protected DexType internalDescribeLookupClassType(DexType previous) {
+ return typeMap != null ? typeMap.getOrDefault(previous, previous) : previous;
+ }
+
+ @Override
+ protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
+ if (previous.hasReboundReference()) {
+ // Rewrite the rebound reference and then "fixup" the non-rebound reference.
+ DexField rewrittenReboundReference = previous.getRewrittenReboundReference(fieldMap);
+ DexField rewrittenNonReboundReference =
+ previous.getReference() == previous.getReboundReference()
+ ? rewrittenReboundReference
+ : rewrittenReboundReference.withHolder(
+ internalDescribeLookupClassType(previous.getReference().getHolderType()),
+ dexItemFactory);
+ return FieldLookupResult.builder(this)
+ .setReboundReference(rewrittenReboundReference)
+ .setReference(rewrittenNonReboundReference)
+ .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType))
+ .build();
+ } else {
+ // TODO(b/168282032): We should always have the rebound reference, so this should become
+ // unreachable.
+ DexField rewrittenReference = previous.getRewrittenReference(fieldMap);
+ return FieldLookupResult.builder(this)
+ .setReference(rewrittenReference)
+ .setCastType(previous.getRewrittenCastType(this::internalDescribeLookupClassType))
+ .build();
+ }
+ }
+
+ @Override
+ public MethodLookupResult internalDescribeLookupMethod(
+ MethodLookupResult previous, DexMethod context) {
+ if (previous.hasReboundReference()) {
+ // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win
+ // that only subclasses which are known to need it actually do it?
+ DexMethod rewrittenReboundReference = previous.getRewrittenReboundReference(methodMap);
+ DexMethod rewrittenReference =
+ previous.getReference() == previous.getReboundReference()
+ ? rewrittenReboundReference
+ : // This assumes that the holder will always be moved in lock-step with the method!
+ rewrittenReboundReference.withHolder(
+ internalDescribeLookupClassType(previous.getReference().getHolderType()),
+ dexItemFactory);
+ return MethodLookupResult.builder(this)
+ .setReference(rewrittenReference)
+ .setReboundReference(rewrittenReboundReference)
+ .setPrototypeChanges(
+ internalDescribePrototypeChanges(
+ previous.getPrototypeChanges(), rewrittenReboundReference))
+ .setType(
+ mapInvocationType(
+ rewrittenReboundReference, previous.getReference(), previous.getType()))
+ .build();
+ } else {
+ // TODO(b/168282032): We should always have the rebound reference, so this should become
+ // unreachable.
+ DexMethod newMethod = methodMap.get(previous.getReference());
+ if (newMethod == null) {
+ return previous;
+ }
+ // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win
+ // that only subclasses which are known to need it actually do it?
+ return MethodLookupResult.builder(this)
+ .setReference(newMethod)
+ .setPrototypeChanges(
+ internalDescribePrototypeChanges(previous.getPrototypeChanges(), newMethod))
+ .setType(mapInvocationType(newMethod, previous.getReference(), previous.getType()))
+ .build();
+ }
+ }
+
+ @Override
+ public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(DexMethod method) {
+ DexMethod previous = internalGetPreviousMethodSignature(method);
+ RewrittenPrototypeDescription lookup =
+ getPrevious().lookupPrototypeChangesForMethodDefinition(previous);
+ return internalDescribePrototypeChanges(lookup, method);
+ }
+
+ protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
+ RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
+ return prototypeChanges;
+ }
+
+ protected DexField internalGetNextFieldSignature(DexField field) {
+ return fieldMap.getOrDefault(field, field);
+ }
+
+ @Override
+ protected DexMethod internalGetPreviousMethodSignature(DexMethod method) {
+ return originalMethodSignatures.getRepresentativeValueOrDefault(method, method);
+ }
+
+ protected DexMethod internalGetNextMethodSignature(DexMethod method) {
+ return originalMethodSignatures.getRepresentativeKeyOrDefault(method, method);
+ }
+
+ @Override
+ public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) {
+ return getPrevious().lookupGetFieldForMethod(field, context);
+ }
+
+ @Override
+ public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) {
+ return getPrevious().lookupPutFieldForMethod(field, context);
+ }
+
+ /**
+ * Default invocation type mapping.
+ *
+ * <p>This is an identity mapping. If a subclass need invocation type mapping either override this
+ * method or {@link #lookupMethod(DexMethod, DexMethod, Type)}
+ */
+ protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) {
+ return type;
+ }
+
+ /**
+ * Standard mapping between interface and virtual invoke type.
+ *
+ * <p>Handle methods moved from interface to class or class to interface.
+ */
+ public static Type mapVirtualInterfaceInvocationTypes(
+ DexDefinitionSupplier definitions, DexMethod newMethod, DexMethod originalMethod, Type type) {
+ if (type == Type.VIRTUAL || type == Type.INTERFACE) {
+ // Get the invoke type of the actual definition.
+ DexClass newTargetClass = definitions.definitionFor(newMethod.getHolderType());
+ if (newTargetClass == null) {
+ return type;
+ }
+ DexClass originalTargetClass = definitions.definitionFor(originalMethod.getHolderType());
+ if (originalTargetClass != null
+ && (originalTargetClass.isInterface() ^ (type == Type.INTERFACE))) {
+ // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
+ // the IncompatibleClassChangeError the original invoke would have triggered.
+ return newTargetClass.accessFlags.isInterface() ? Type.VIRTUAL : Type.INTERFACE;
+ }
+ return newTargetClass.accessFlags.isInterface() ? Type.INTERFACE : Type.VIRTUAL;
+ }
+ return type;
+ }
+
+ @Override
+ public boolean isContextFreeForMethods() {
+ return getPrevious().isContextFreeForMethods();
+ }
+
+ @Override
+ public boolean verifyIsContextFreeForMethod(DexMethod method) {
+ assert getPrevious().verifyIsContextFreeForMethod(method);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (typeMap != null) {
+ for (Map.Entry<DexType, DexType> entry : typeMap.entrySet()) {
+ builder.append(entry.getKey().toSourceString()).append(" -> ");
+ builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
+ }
+ }
+ for (Map.Entry<DexMethod, DexMethod> entry : methodMap.entrySet()) {
+ builder.append(entry.getKey().toSourceString()).append(" -> ");
+ builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
+ }
+ fieldMap.forEachManyToOneMapping(
+ (keys, value) -> {
+ builder.append(
+ keys.stream()
+ .map(DexField::toSourceString)
+ .collect(Collectors.joining("," + System.lineSeparator())));
+ builder.append(" -> ");
+ builder.append(value.toSourceString()).append(System.lineSeparator());
+ });
+ builder.append(getPrevious().toString());
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index bc713ce..742affa 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 9c65847..b1a0e85 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -37,9 +37,9 @@
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodCollection;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke.Type;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 3e58a94..9e508bd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -14,7 +14,7 @@
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.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index 0ebf96b..ed01d9f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index c64e51e..1a5b6bc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.utils.BooleanUtils;
@@ -21,7 +22,7 @@
import java.util.Map;
import java.util.Set;
-class EnumUnboxingLens extends GraphLens.NestedGraphLens {
+class EnumUnboxingLens extends NestedGraphLens {
private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod;
private final Set<DexType> unboxedEnums;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index 1602032..eed5089 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -21,8 +21,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
index 75a78ab..f66bf8f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
index 171dcbe..4310236 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.optimize;
-import static com.android.tools.r8.graph.GraphLens.NestedGraphLens.mapVirtualInterfaceInvocationTypes;
+import static com.android.tools.r8.graph.NestedGraphLens.mapVirtualInterfaceInvocationTypes;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
index 8ea4e1f..9a29509 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
index e6d16eb..8ac9320 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
index 008380c..7c6f295 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.code.Invoke.Type;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index d4c124f..27ec751 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -18,8 +18,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.TreeFixerBase;
import com.android.tools.r8.ir.code.NumberGenerator;