Merge "Extend context sensitive GraphLense API"
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 2e0b531..484bfe8 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -331,6 +331,14 @@
       GraphLense graphLense = GraphLense.getIdentityLense();
 
       if (appInfo.hasLiveness()) {
+        if (options.proguardConfiguration.hasApplyMappingFile()) {
+          SeedMapper seedMapper =
+              SeedMapper.seedMapperFromFile(options.proguardConfiguration.getApplyMappingFile());
+          timing.begin("apply-mapping");
+          graphLense =
+              new ProguardMapApplier(appInfo.withLiveness(), graphLense, seedMapper).run(timing);
+          timing.end();
+        }
         graphLense = new MemberRebindingAnalysis(appInfo.withLiveness(), graphLense).run();
         // Class merging requires inlining.
         if (options.enableClassMerging && options.enableInlining) {
@@ -343,14 +351,6 @@
           appInfo = appInfo.withLiveness()
               .prunedCopyFrom(application, classMerger.getRemovedClasses());
         }
-        if (options.proguardConfiguration.hasApplyMappingFile()) {
-          SeedMapper seedMapper = SeedMapper.seedMapperFromFile(
-              options.proguardConfiguration.getApplyMappingFile());
-          timing.begin("apply-mapping");
-          graphLense = new ProguardMapApplier(appInfo.withLiveness(), graphLense, seedMapper)
-              .run(timing);
-          timing.end();
-        }
         application = application.asDirect().rewrittenWithLense(graphLense);
         appInfo = appInfo.withLiveness().rewrittenWithLense(application.asDirect(), graphLense);
         // Collect switch maps and ordinals maps.
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index 06ea28d..cd3c093 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Handle;
 import org.objectweb.asm.Opcodes;
@@ -159,6 +160,26 @@
     public boolean isInvokeConstructor() {
       return this == MethodHandleType.INVOKE_CONSTRUCTOR;
     }
+
+    public Type toInvokeType() {
+      assert isMethodType();
+      switch (this) {
+        case INVOKE_STATIC:
+          return Type.STATIC;
+        case INVOKE_INSTANCE:
+          return Type.VIRTUAL;
+        case INVOKE_CONSTRUCTOR:
+          return Type.DIRECT;
+        case INVOKE_DIRECT:
+          return Type.DIRECT;
+        case INVOKE_INTERFACE:
+          return Type.INTERFACE;
+        case INVOKE_SUPER:
+          return Type.SUPER;
+        default:
+          throw new Unreachable("DexMethodHandle with unexpected type: " + this);
+      }
+    }
   }
 
   public MethodHandleType type;
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 bd22444..e4f1c8c 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -69,7 +69,6 @@
   }
 
   public DirectMappedDexApplication rewrittenWithLense(GraphLense graphLense) {
-    assert graphLense.isContextFreeForMethods();
     assert mappingIsValid(graphLense, programClasses.getAllTypes());
     assert mappingIsValid(graphLense, libraryClasses.keySet());
     // As a side effect, this will rebuild the program classes and library classes maps.
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 7c6c941..096de5a 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -3,8 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.google.common.collect.ImmutableSet;
+import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * A GraphLense implements a virtual view on top of the graph, used to delay global rewrites until
@@ -61,17 +65,32 @@
 
   public abstract DexType lookupType(DexType type);
 
+  // This overload can be used when the graph lense is known to be context insensitive.
   public DexMethod lookupMethod(DexMethod method) {
-    assert isContextFreeForMethods();
-    return lookupMethod(method, null);
+    assert isContextFreeForMethod(method);
+    return lookupMethod(method, null, null);
   }
 
-  public abstract DexMethod lookupMethod(DexMethod method, DexEncodedMethod context);
+  public abstract DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type);
+
+  // Context sensitive graph lenses should override this method.
+  public Set<DexMethod> lookupMethodInAllContexts(DexMethod method) {
+    assert isContextFreeForMethod(method);
+    DexMethod result = lookupMethod(method);
+    if (result != null) {
+      return ImmutableSet.of(result);
+    }
+    return ImmutableSet.of();
+  }
 
   public abstract DexField lookupField(DexField field);
 
   public abstract boolean isContextFreeForMethods();
 
+  public boolean isContextFreeForMethod(DexMethod method) {
+    return isContextFreeForMethods();
+  }
+
   public static GraphLense getIdentityLense() {
     return new IdentityGraphLense();
   }
@@ -88,7 +107,7 @@
     }
 
     @Override
-    public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context) {
+    public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
       return method;
     }
 
@@ -146,12 +165,21 @@
     }
 
     @Override
-    public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context) {
-      DexMethod previous = previousLense.lookupMethod(method, context);
+    public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
+      DexMethod previous = previousLense.lookupMethod(method, context, type);
       return methodMap.getOrDefault(previous, previous);
     }
 
     @Override
+    public Set<DexMethod> lookupMethodInAllContexts(DexMethod method) {
+      Set<DexMethod> result = new HashSet<>();
+      for (DexMethod previous : previousLense.lookupMethodInAllContexts(method)) {
+        result.add(methodMap.getOrDefault(previous, previous));
+      }
+      return result;
+    }
+
+    @Override
     public DexField lookupField(DexField field) {
       DexField previous = previousLense.lookupField(field);
       return fieldMap.getOrDefault(previous, previous);
@@ -163,6 +191,11 @@
     }
 
     @Override
+    public boolean isContextFreeForMethod(DexMethod method) {
+      return previousLense.isContextFreeForMethod(method);
+    }
+
+    @Override
     public String toString() {
       StringBuilder builder = new StringBuilder();
       for (Map.Entry<DexType, DexType> entry : typeMap.entrySet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index 8330e06..21b8dc4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -363,7 +363,7 @@
 
     private void processInvoke(Type type, DexMethod method) {
       DexEncodedMethod source = caller.method;
-      method = graphLense.lookupMethod(method, source);
+      method = graphLense.lookupMethod(method, source, type);
       DexEncodedMethod definition = appInfo.lookup(type, method, source.method.holder);
       if (definition != null) {
         assert !source.accessFlags.isBridge() || definition != caller.method;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 28213e1..1926b14 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -96,7 +96,7 @@
           if (!invokedHolder.isClassType()) {
             continue;
           }
-          DexMethod actualTarget = graphLense.lookupMethod(invokedMethod, method);
+          DexMethod actualTarget = graphLense.lookupMethod(invokedMethod, method, invoke.getType());
           Invoke.Type invokeType = getInvokeType(invoke, actualTarget, invokedMethod);
           if (actualTarget != invokedMethod || invoke.getType() != invokeType) {
             Invoke newInvoke = Invoke.create(invokeType, actualTarget, null,
@@ -216,7 +216,8 @@
       DexEncodedMethod method, DexMethodHandle methodHandle) {
     if (methodHandle.isMethodHandle()) {
       DexMethod invokedMethod = methodHandle.asMethod();
-      DexMethod actualTarget = graphLense.lookupMethod(invokedMethod, method);
+      DexMethod actualTarget =
+          graphLense.lookupMethod(invokedMethod, method, methodHandle.type.toInvokeType());
       if (actualTarget != invokedMethod) {
         DexClass clazz = appInfo.definitionFor(actualTarget.holder);
         MethodHandleType newType = methodHandle.type;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
index 45200d4..7dfd840 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
@@ -37,6 +37,7 @@
       AppInfoWithLiveness appInfo,
       GraphLense previousLense,
       SeedMapper seedMapper) {
+    assert previousLense.isContextFreeForMethods();
     this.appInfo = appInfo;
     this.previousLense = previousLense;
     this.seedMapper = seedMapper;
@@ -44,7 +45,7 @@
 
   public GraphLense run(Timing timing) {
     timing.begin("from-pg-map-to-lense");
-    GraphLense lenseFromMap = new MapToLenseConverter().run(previousLense);
+    GraphLense lenseFromMap = new MapToLenseConverter().run();
     timing.end();
     timing.begin("fix-types-in-programs");
     GraphLense typeFixedLense = new TreeFixer(lenseFromMap).run();
@@ -61,7 +62,7 @@
       lenseBuilder = new ConflictFreeBuilder();
     }
 
-    private GraphLense run(GraphLense previousLense) {
+    private GraphLense run() {
       // To handle inherited yet undefined methods in library classes, we are traversing types in
       // a subtyping order. That also helps us detect conflicted mappings in a diamond case:
       //   LibItfA#foo -> a, LibItfB#foo -> b, while PrgA implements LibItfA and LibItfB.
@@ -308,7 +309,7 @@
       }
       for (int i = 0; i < methods.length; i++) {
         DexEncodedMethod encodedMethod = methods[i];
-        DexMethod appliedMethod = appliedLense.lookupMethod(encodedMethod.method, encodedMethod);
+        DexMethod appliedMethod = appliedLense.lookupMethod(encodedMethod.method);
         DexType newHolderType = substituteType(appliedMethod.holder, encodedMethod);
         DexProto newProto = substituteTypesIn(appliedMethod.proto, encodedMethod);
         DexMethod newMethod;
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
index a920455d..56089f4 100644
--- a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.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.GraphLense;
+import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.optimize.InvokeSingleTargetExtractor.InvokeKind;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
@@ -43,16 +44,17 @@
       InvokeKind kind = targetExtractor.getKind();
       if (target != null && target.getArity() == method.method.getArity()) {
         assert !method.accessFlags.isPrivate() && !method.accessFlags.isConstructor();
-        target = lense.lookupMethod(target, method);
         if (kind == InvokeKind.STATIC) {
           assert method.accessFlags.isStatic();
-          DexEncodedMethod targetMethod = appInfo.lookupStaticTarget(target);
+          DexMethod actualTarget = lense.lookupMethod(target, method, Type.STATIC);
+          DexEncodedMethod targetMethod = appInfo.lookupStaticTarget(actualTarget);
           if (targetMethod != null) {
             addForwarding(method, targetMethod);
           }
         } else if (kind == InvokeKind.VIRTUAL) {
           // TODO(herhut): Add support for bridges with multiple targets.
-          DexEncodedMethod targetMethod = appInfo.lookupSingleVirtualTarget(target);
+          DexMethod actualTarget = lense.lookupMethod(target, method, Type.VIRTUAL);
+          DexEncodedMethod targetMethod = appInfo.lookupSingleVirtualTarget(actualTarget);
           if (targetMethod != null) {
             addForwarding(method, targetMethod);
           }
@@ -91,17 +93,15 @@
     }
 
     @Override
-    public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context) {
-      DexMethod previous = previousLense.lookupMethod(method, context);
+    public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
+      DexMethod previous = previousLense.lookupMethod(method, context, type);
       DexMethod bridge = bridgeTargetToBridgeMap.get(previous);
       // Do not forward calls from a bridge method to itself while the bridge method is still
       // a bridge.
-      if (bridge == null
-          || (context.accessFlags.isBridge() && bridge == context.method)) {
+      if (bridge == null || (context.accessFlags.isBridge() && bridge == context.method)) {
         return previous;
-      } else {
-        return bridge;
       }
+      return bridge;
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 43b45b4..fc408e3 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -115,7 +115,7 @@
   private void computeMethodRebinding(Set<DexMethod> methods,
       Function<DexMethod, DexEncodedMethod> lookupTarget) {
     for (DexMethod method : methods) {
-      method = lense.lookupMethod(method, null);
+      method = lense.lookupMethod(method);
       // We can safely ignore array types, as the corresponding methods are defined in a library.
       if (!method.getHolder().isClassType()) {
         continue;
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 9387e3e..2b51720 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1638,8 +1638,8 @@
       this.liveTypes = rewriteItems(previous.liveTypes, lense::lookupType);
       this.instantiatedTypes = rewriteItems(previous.instantiatedTypes, lense::lookupType);
       this.instantiatedLambdas = rewriteItems(previous.instantiatedLambdas, lense::lookupType);
-      this.targetedMethods = rewriteItems(previous.targetedMethods, lense::lookupMethod);
-      this.liveMethods = rewriteItems(previous.liveMethods, lense::lookupMethod);
+      this.targetedMethods = rewriteMethodsConservatively(previous.targetedMethods, lense);
+      this.liveMethods = rewriteMethodsConservatively(previous.liveMethods, lense);
       this.liveFields = rewriteItems(previous.liveFields, lense::lookupField);
       this.instanceFieldReads =
           rewriteKeysWhileMergingValues(previous.instanceFieldReads, lense::lookupField);
@@ -1652,11 +1652,11 @@
       this.fieldsRead = rewriteItems(previous.fieldsRead, lense::lookupField);
       this.fieldsWritten = rewriteItems(previous.fieldsWritten, lense::lookupField);
       this.pinnedItems = rewriteMixedItems(previous.pinnedItems, lense);
-      this.virtualInvokes = rewriteItems(previous.virtualInvokes, lense::lookupMethod);
-      this.interfaceInvokes = rewriteItems(previous.interfaceInvokes, lense::lookupMethod);
-      this.superInvokes = rewriteItems(previous.superInvokes, lense::lookupMethod);
-      this.directInvokes = rewriteItems(previous.directInvokes, lense::lookupMethod);
-      this.staticInvokes = rewriteItems(previous.staticInvokes, lense::lookupMethod);
+      this.virtualInvokes = rewriteMethodsConservatively(previous.virtualInvokes, lense);
+      this.interfaceInvokes = rewriteMethodsConservatively(previous.interfaceInvokes, lense);
+      this.superInvokes = rewriteMethodsConservatively(previous.superInvokes, lense);
+      this.directInvokes = rewriteMethodsConservatively(previous.directInvokes, lense);
+      this.staticInvokes = rewriteMethodsConservatively(previous.staticInvokes, lense);
       this.prunedTypes = rewriteItems(previous.prunedTypes, lense::lookupType);
       // TODO(herhut): Migrate these to Descriptors, as well.
       assert assertNotModifiedByLense(previous.noSideEffects.keySet(), lense);
@@ -1744,7 +1744,7 @@
           // We only allow changes to bridge methods, as these get retargeted even if they
           // are kept.
           assert method.accessFlags.isBridge()
-              || lense.lookupMethod(method.method, null) == method.method;
+              || lense.lookupMethod(method.method) == method.method;
         } else if (item instanceof DexEncodedField) {
           DexField field = ((DexEncodedField) item).field;
           assert lense.lookupField(field) == field;
@@ -1792,6 +1792,29 @@
       return builder.build();
     }
 
+    private static ImmutableSortedSet<DexMethod> rewriteMethodsConservatively(
+        Set<DexMethod> original, GraphLense lense) {
+      ImmutableSortedSet.Builder<DexMethod> builder =
+          new ImmutableSortedSet.Builder<>(PresortedComparable::slowCompare);
+      if (lense.isContextFreeForMethods()) {
+        for (DexMethod item : original) {
+          builder.add(lense.lookupMethod(item));
+        }
+      } else {
+        for (DexMethod item : original) {
+          // Avoid using lookupMethodInAllContexts when possible.
+          if (lense.isContextFreeForMethod(item)) {
+            builder.add(lense.lookupMethod(item));
+          } else {
+            // The lense is context sensitive, but we do not have the context here. Therefore, we
+            // conservatively look up the method in all contexts.
+            builder.addAll(lense.lookupMethodInAllContexts(item));
+          }
+        }
+      }
+      return builder.build();
+    }
+
     private static <T extends PresortedComparable<T>> ImmutableSortedSet<T> rewriteItems(
         Set<T> original, Function<T, T> rewrite) {
       ImmutableSortedSet.Builder<T> builder =
@@ -1892,7 +1915,6 @@
 
     public AppInfoWithLiveness rewrittenWithLense(DirectMappedDexApplication application,
         GraphLense lense) {
-      assert lense.isContextFreeForMethods();
       return new AppInfoWithLiveness(this, application, lense);
     }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java b/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
index a80e758..c9d34ee 100644
--- a/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
@@ -181,7 +181,8 @@
     if (Log.ENABLED) {
       Log.debug(getClass(), "Merged %d classes.", numberOfMerges);
     }
-    return renamedMembersLense.build(application.dexItemFactory, graphLense);
+    return new VerticalClassMergerGraphLense(
+        renamedMembersLense.build(application.dexItemFactory, graphLense));
   }
 
   private class ClassMerger {
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
new file mode 100644
index 0000000..1bdeb7c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2018, 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.shaking;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+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.GraphLense;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+
+// This graph lense is instantiated during vertical class merging. The graph lense is context
+// sensitive in the enclosing class of a given invoke *and* the type of the invoke (e.g., invoke-
+// super vs invoke-virtual). This is illustrated by the following example.
+//
+// public class A {
+//   public void m() { ... }
+// }
+// public class B extends A {
+//   @Override
+//   public void m() { invoke-super A.m(); ... }
+//
+//   public void m2() { invoke-virtual A.m(); ... }
+// }
+//
+// Vertical class merging will merge class A into class B. Since class B already has a method with
+// the signature "void B.m()", the method A.m will be given a fresh name and moved to class B.
+// During this process, the method corresponding to A.m will be made private such that it can be
+// called via an invoke-direct instruction.
+//
+// For the invocation "invoke-super A.m()" in B.m, this graph lense will return the newly created,
+// private method corresponding to A.m (that is now in B.m with a fresh name), such that the
+// invocation will hit the same implementation as the original super.m() call.
+//
+// For the invocation "invoke-virtual A.m()" in B.m2, this graph lense will return the method B.m.
+public class VerticalClassMergerGraphLense extends GraphLense {
+  private final GraphLense previousLense;
+
+  public VerticalClassMergerGraphLense(GraphLense previousLense) {
+    this.previousLense = previousLense;
+  }
+
+  @Override
+  public DexType lookupType(DexType type) {
+    return previousLense.lookupType(type);
+  }
+
+  @Override
+  public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
+    // TODO(christofferqa): If [type] is Type.SUPER and [method] has been merged into the class of
+    // [context], then return the DIRECT method that has been created for [method] by SimpleClass-
+    // Merger. Otherwise, return the VIRTUAL method corresponding to [method].
+    return previousLense.lookupMethod(method, context, type);
+  }
+
+  @Override
+  public Set<DexMethod> lookupMethodInAllContexts(DexMethod method) {
+    DexMethod result = lookupMethod(method);
+    if (result != null) {
+      return ImmutableSet.of(result);
+    }
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public DexField lookupField(DexField field) {
+    return previousLense.lookupField(field);
+  }
+
+  @Override
+  public boolean isContextFreeForMethods() {
+    return false;
+  }
+
+  @Override
+  public boolean isContextFreeForMethod(DexMethod method) {
+    // TODO(christofferqa): Should return false for methods where this graph lense is context
+    // sensitive.
+    return true;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index cf356df..65181dc 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -36,6 +36,9 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
+// TODO(christofferqa): Add tests to check that statically typed invocations on method handles
+// continue to work after class merging. Rewriting of method handles should be carried out by
+// LensCodeRewriter.rewriteDexMethodHandle.
 public class ClassMergingTest extends TestBase {
 
   private static final Path CF_DIR =