Merge "Fix --tool=D8|R8 selection for JCTF"
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index e21b00a..188440d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -18,11 +18,14 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -305,6 +308,38 @@
     return builder.build();
   }
 
+  public DexEncodedMethod toForwardingMethod(DexClass holder, DexItemFactory itemFactory) {
+    assert accessFlags.isPublic();
+    DexMethod newMethod = itemFactory.createMethod(holder.type, method.proto, method.name);
+    Invoke.Type type = accessFlags.isStatic() ? Invoke.Type.STATIC : Invoke.Type.SUPER;
+    Builder builder = builder(this);
+    builder.setMethod(newMethod);
+    if (accessFlags.isAbstract()) {
+      // If the forwarding target is abstract, we can just create an abstract method. While it
+      // will not actually forward, it will create the same exception when hit at runtime.
+      builder.accessFlags.setAbstract();
+    } else {
+      // Create code that forwards the call to the target.
+      builder.setCode(new SynthesizedCode(
+          new ForwardMethodSourceCode(
+              accessFlags.isStatic() ? null : holder.type,
+              method.proto,
+              accessFlags.isStatic() ? null : method.holder,
+              method,
+              type),
+          registry -> {
+            if (accessFlags.isStatic()) {
+              registry.registerInvokeStatic(method);
+            } else {
+              registry.registerInvokeSuper(method);
+            }
+          }));
+    }
+    builder.accessFlags.setSynthetic();
+    accessFlags.unsetFinal();
+    return builder.build();
+  }
+
   public String codeToString() {
     return code == null ? "<no code>" : code.toString();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 368cb22..6713083 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -52,6 +52,7 @@
     }
   }
 
+  @Override
   public void addDependencies(MixedSectionCollection collector) {
     // We only have a class data item if there are methods or fields.
     if (hasMethodsOrFields()) {
@@ -119,4 +120,20 @@
   public DexEncodedArray getStaticValues() {
     return staticValues;
   }
+
+  public void addVirtualMethod(DexEncodedMethod virtualMethod) {
+    assert !virtualMethod.accessFlags.isStatic();
+    assert !virtualMethod.accessFlags.isPrivate();
+    assert !virtualMethod.accessFlags.isConstructor();
+    virtualMethods = Arrays.copyOf(virtualMethods, virtualMethods.length + 1);
+    virtualMethods[virtualMethods.length - 1] = virtualMethod;
+  }
+
+  public void addStaticMethod(DexEncodedMethod staticMethod) {
+    assert staticMethod.accessFlags.isStatic();
+    assert !staticMethod.accessFlags.isPrivate();
+    assert !staticMethod.accessFlags.isConstructor();
+    directMethods = Arrays.copyOf(directMethods, directMethods.length + 1);
+    directMethods[directMethods.length - 1] = staticMethod;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
index bee210c..c957b58 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
@@ -18,6 +18,7 @@
 
 // Source code representing synthesized accessor method.
 final class AccessorMethodSourceCode extends SynthesizedLambdaSourceCode {
+
   AccessorMethodSourceCode(LambdaClass lambda) {
     super(/* no receiver for static method */ null, lambda, lambda.target.callTarget);
     // We should never need an accessor for interface methods since
@@ -81,7 +82,7 @@
   }
 
   @Override
-  void prepareInstructions() {
+  protected void prepareInstructions() {
     DexMethod implMethod = descriptor().implHandle.asMethod();
     DexType[] accessorParams = proto.parameters.values;
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index ecda01e..236c9e5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.IdentityHashMap;
@@ -22,6 +24,7 @@
 // Default and static method interface desugaring processor for classes.
 // Adds default interface methods into the class when needed.
 final class ClassProcessor {
+
   private final InterfaceMethodRewriter rewriter;
   // Set of already processed classes.
   private final Set<DexClass> processedClasses = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
index d35566a..cc4f1f2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
@@ -14,6 +14,7 @@
 
 // Source code representing synthesized lambda bridge method.
 final class LambdaBridgeMethodSourceCode extends SynthesizedLambdaSourceCode {
+
   private final DexMethod mainMethod;
 
   LambdaBridgeMethodSourceCode(LambdaClass lambda, DexMethod mainMethod, DexMethod bridgeMethod) {
@@ -22,7 +23,7 @@
   }
 
   @Override
-  void prepareInstructions() {
+  protected void prepareInstructions() {
     DexType[] currentParams = proto.parameters.values;
     DexType[] enforcedParams = descriptor().enforcedProto.parameters.values;
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index e92f78f..a4801c9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -12,8 +12,8 @@
 import com.android.tools.r8.graph.DexAnnotationSetRefList;
 import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexClassPromise;
+import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -27,6 +27,7 @@
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -49,6 +50,7 @@
  * separate lambda classes.
  */
 final class LambdaClass {
+
   final LambdaRewriter rewriter;
   final DexType type;
   final LambdaDescriptor descriptor;
@@ -370,6 +372,7 @@
   // be the same method as specified in lambda descriptor or a newly synthesized accessor.
   // Also provides action for ensuring accessibility of the referenced symbols.
   abstract class Target {
+
     final DexMethod callTarget;
     final Invoke.Type invokeType;
 
@@ -386,6 +389,7 @@
 
   // Used for targeting methods referenced directly without creating accessors.
   private final class NoAccessorMethodTarget extends Target {
+
     NoAccessorMethodTarget(Invoke.Type invokeType) {
       super(descriptor.implHandle.asMethod(), invokeType);
     }
@@ -398,6 +402,7 @@
 
   // Used for static private lambda$ methods. Only needs access relaxation.
   private final class StaticLambdaImplTarget extends Target {
+
     StaticLambdaImplTarget() {
       super(descriptor.implHandle.asMethod(), Invoke.Type.STATIC);
     }
@@ -420,6 +425,7 @@
   // Used for instance private lambda$ methods. Needs to be converted to
   // a package-private static method.
   private class InstanceLambdaImplTarget extends Target {
+
     InstanceLambdaImplTarget(DexMethod staticMethod) {
       super(staticMethod, Invoke.Type.STATIC);
     }
@@ -452,7 +458,7 @@
           dexCode.setDebugInfo(dexCode.debugInfoWithAdditionalFirstParameter(null));
           assert (dexCode.getDebugInfo() == null)
               || (callTarget.proto.parameters.values.length
-                  == dexCode.getDebugInfo().parameters.length);
+              == dexCode.getDebugInfo().parameters.length);
           directMethods[i] = newMethod;
           return true;
         }
@@ -464,6 +470,7 @@
   // Used for instance/static methods or constructors accessed via
   // synthesized accessor method. Needs accessor method to be created.
   private class ClassMethodWithAccessorTarget extends Target {
+
     ClassMethodWithAccessorTarget(DexMethod accessorMethod) {
       super(accessorMethod, Invoke.Type.STATIC);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
index db8e1f5..539fcf0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
@@ -13,13 +13,14 @@
 // Source code representing synthesized lambda class constructor.
 // Used for stateless lambdas to instantiate singleton instance.
 final class LambdaClassConstructorSourceCode extends SynthesizedLambdaSourceCode {
+
   LambdaClassConstructorSourceCode(LambdaClass lambda) {
     super(null /* Class initializer is static */, lambda, lambda.classConstructor);
     assert lambda.instanceField != null;
   }
 
   @Override
-  void prepareInstructions() {
+  protected void prepareInstructions() {
     // Create and initialize an instance.
     int instance = nextRegister(MoveType.OBJECT);
     add(builder -> builder.addNewInstance(instance, lambda.type));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
index b4aef78..b736403 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
@@ -14,12 +14,13 @@
 
 // Source code representing synthesized lambda constructor.
 final class LambdaConstructorSourceCode extends SynthesizedLambdaSourceCode {
+
   LambdaConstructorSourceCode(LambdaClass lambda) {
     super(lambda, lambda.constructor);
   }
 
   @Override
-  void prepareInstructions() {
+  protected void prepareInstructions() {
     // Super constructor call (always java.lang.Object.<init>()).
     DexMethod objectInitMethod = lambda.rewriter.objectInitMethod;
     add(builder -> builder.addInvoke(Invoke.Type.DIRECT, objectInitMethod,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index 9e4c570..5eb4c30 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -25,6 +25,7 @@
 
 // Source code representing synthesized lambda main method
 final class LambdaMainMethodSourceCode extends SynthesizedLambdaSourceCode {
+
   LambdaMainMethodSourceCode(LambdaClass lambda, DexMethod mainMethod) {
     super(lambda, mainMethod);
   }
@@ -177,7 +178,7 @@
   }
 
   @Override
-  void prepareInstructions() {
+  protected void prepareInstructions() {
     DexType[] capturedTypes = captures();
     DexType[] erasedParams = descriptor().erasedProto.parameters.values;
     DexType erasedReturnType = descriptor().erasedProto.returnType;
@@ -462,7 +463,7 @@
   private int addPrimitiveBoxing(int register, DexType primitiveType, DexType boxType) {
     // Generate factory method fo boxing.
     DexItemFactory factory = factory();
-    DexProto proto = factory.createProto(boxType, new DexType[] { primitiveType });
+    DexProto proto = factory.createProto(boxType, new DexType[]{primitiveType});
     DexMethod method = factory.createMethod(boxType, proto, factory.valueOfMethodName);
 
     MoveType moveType = MoveType.fromDexType(primitiveType);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java
index 7a63c32..9a3531f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedLambdaSourceCode.java
@@ -8,9 +8,11 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.ir.synthetic.SingleBlockSourceCode;
 
 // Represents source code of synthesized lambda class methods.
 abstract class SynthesizedLambdaSourceCode extends SingleBlockSourceCode {
+
   final DexMethod currentMethod;
   final LambdaClass lambda;
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/ir/desugar/ForwardMethodSourceCode.java
rename to src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index 808456b..bcc9462 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -2,7 +2,7 @@
 // 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.ir.desugar;
+package com.android.tools.r8.ir.synthetic;
 
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.DexMethod;
@@ -16,12 +16,13 @@
 import java.util.List;
 
 // Source code representing simple forwarding method.
-final class ForwardMethodSourceCode extends SingleBlockSourceCode {
+public final class ForwardMethodSourceCode extends SingleBlockSourceCode {
+
   private final DexType targetReceiver;
   private final DexMethod target;
   private final Invoke.Type invokeType;
 
-  ForwardMethodSourceCode(DexType receiver, DexProto proto,
+  public ForwardMethodSourceCode(DexType receiver, DexProto proto,
       DexType targetReceiver, DexMethod target, Invoke.Type invokeType) {
     super(receiver, proto);
     assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
@@ -31,8 +32,14 @@
     this.invokeType = invokeType;
     assert checkSignatures();
 
-    if (invokeType != Invoke.Type.STATIC) {
-      throw new Unimplemented("Invoke type " + invokeType + " is not yet supported.");
+    switch (invokeType) {
+      case STATIC:
+      case SUPER:
+      case INTERFACE:
+      case VIRTUAL:
+        break;
+      default:
+        throw new Unimplemented("Invoke type " + invokeType + " is not yet supported.");
     }
   }
 
@@ -65,7 +72,7 @@
   }
 
   @Override
-  void prepareInstructions() {
+  protected void prepareInstructions() {
     // Prepare call arguments.
     List<MoveType> argMoveTypes = new ArrayList<>();
     List<Integer> argRegisters = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/SingleBlockSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/ir/desugar/SingleBlockSourceCode.java
rename to src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
index 32631c2..8c97f8f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/SingleBlockSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
@@ -2,7 +2,7 @@
 // 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.ir.desugar;
+package com.android.tools.r8.ir.synthetic;
 
 import static com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo.NO_THROW;
 
@@ -21,9 +21,10 @@
 import java.util.List;
 import java.util.function.Consumer;
 
-abstract class SingleBlockSourceCode implements SourceCode {
-  final DexType receiver;
-  final DexProto proto;
+public abstract class SingleBlockSourceCode implements SourceCode {
+
+  protected final DexType receiver;
+  protected final DexProto proto;
 
   // The next free register, note that we always
   // assign each value a new (next available) register.
@@ -40,7 +41,7 @@
   // Instruction constructors
   private List<Consumer<IRBuilder>> constructors = new ArrayList<>();
 
-  SingleBlockSourceCode(DexType receiver, DexProto proto) {
+  protected SingleBlockSourceCode(DexType receiver, DexProto proto) {
     assert proto != null;
     this.receiver = receiver;
     this.proto = proto;
@@ -57,45 +58,45 @@
     }
   }
 
-  final void add(Consumer<IRBuilder> constructor) {
+  protected final void add(Consumer<IRBuilder> constructor) {
     constructors.add(constructor);
   }
 
-  final int nextRegister(MoveType type) {
+  protected final int nextRegister(MoveType type) {
     int value = nextRegister;
     nextRegister += type == MoveType.WIDE ? 2 : 1;
     return value;
   }
 
-  final Value getReceiverValue() {
+  protected final Value getReceiverValue() {
     assert receiver != null;
     assert receiverValue != null;
     return receiverValue;
   }
 
-  final int getReceiverRegister() {
+  protected final int getReceiverRegister() {
     assert receiver != null;
     assert receiverRegister >= 0;
     return receiverRegister;
   }
 
-  final Value getParamValue(int paramIndex) {
+  protected final Value getParamValue(int paramIndex) {
     assert paramIndex >= 0;
     assert paramIndex < paramValues.length;
     return paramValues[paramIndex];
   }
 
-  final int getParamCount() {
+  protected final int getParamCount() {
     return paramValues.length;
   }
 
-  final int getParamRegister(int paramIndex) {
+  protected final int getParamRegister(int paramIndex) {
     assert paramIndex >= 0;
     assert paramIndex < paramRegisters.length;
     return paramRegisters[paramIndex];
   }
 
-  abstract void prepareInstructions();
+  protected abstract void prepareInstructions();
 
   @Override
   public final boolean needsPrelude() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
similarity index 73%
rename from src/main/java/com/android/tools/r8/ir/desugar/SynthesizedCode.java
rename to src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index 3a07ef4..7716663 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -2,7 +2,7 @@
 // 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.ir.desugar;
+package com.android.tools.r8.ir.synthetic;
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.Code;
@@ -13,12 +13,21 @@
 import com.android.tools.r8.ir.conversion.SourceCode;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.InternalOptions;
+import java.util.function.Consumer;
 
 public final class SynthesizedCode extends Code {
+
   private final SourceCode sourceCode;
+  private final Consumer<UseRegistry> registryCallback;
 
   public SynthesizedCode(SourceCode sourceCode) {
     this.sourceCode = sourceCode;
+    this.registryCallback = SynthesizedCode::registerReachableDefinitionsDefault;
+  }
+
+  public SynthesizedCode(SourceCode sourceCode, Consumer<UseRegistry> callback) {
+    this.sourceCode = sourceCode;
+    this.registryCallback = callback;
   }
 
   @Override
@@ -31,12 +40,16 @@
     return toString(null);
   }
 
-  @Override
-  public final void registerReachableDefinitions(UseRegistry registry) {
+  private static void registerReachableDefinitionsDefault(UseRegistry registry) {
     throw new Unreachable();
   }
 
   @Override
+  public void registerReachableDefinitions(UseRegistry registry) {
+    registryCallback.accept(registry);
+  }
+
+  @Override
   protected final int computeHashCode() {
     return sourceCode.hashCode();
   }
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 4e68d0f..ee0614f 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -3,21 +3,25 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize;
 
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.Descriptor;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 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.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.google.common.collect.Sets;
 import java.util.Set;
+import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
 public class MemberRebindingAnalysis {
+
   private final AppInfoWithLiveness appInfo;
   private final GraphLense lense;
   private final GraphLense.Builder builder = GraphLense.builder();
@@ -109,21 +113,77 @@
 
   private void computeMethodRebinding(Set<DexMethod> methods,
       Function<DexMethod, DexEncodedMethod> lookupTarget,
-      BiFunction<DexClass, DexMethod, DexEncodedMethod> lookupTargetOnClass) {
+      BiFunction<DexClass, DexMethod, DexEncodedMethod> lookupTargetOnClass,
+      BiConsumer<DexProgramClass, DexEncodedMethod> addMethod) {
     for (DexMethod method : methods) {
       method = lense.lookupMethod(method, null);
       // We can safely ignore array types, as the corresponding methods are defined in a library.
       if (!method.getHolder().isClassType()) {
         continue;
       }
+      DexClass originalClass = appInfo.definitionFor(method.holder);
+      // We can safely ignore calls to library classes, as those cannot be rebound.
+      if (originalClass == null || originalClass.isLibraryClass()) {
+        continue;
+      }
       DexEncodedMethod target = lookupTarget.apply(method);
       // Rebind to the lowest library class or program class.
       if (target != null && target.method != method) {
+        DexClass targetClass = appInfo.definitionFor(target.method.holder);
+        // If the targetclass is not public but the targeted method is, we might run into
+        // visibility problems when rebinding.
+        if (!targetClass.accessFlags.isPublic() && target.accessFlags.isPublic()) {
+          // If the original class is public and this method is public, it might have been called
+          // from anywhere, so we need a bridge. Likewise, if the original is in a different
+          // package, we might need a bridge, too.
+          String packageDescriptor =
+              originalClass.accessFlags.isPublic() ? null : method.holder.getPackageDescriptor();
+          if (packageDescriptor == null
+              || !packageDescriptor.equals(targetClass.type.getPackageDescriptor())) {
+            DexProgramClass bridgeHolder = findBridgeMethodHolder(originalClass, targetClass,
+                packageDescriptor);
+            assert bridgeHolder != null;
+            DexEncodedMethod bridgeMethod = target
+                .toForwardingMethod(bridgeHolder, appInfo.dexItemFactory);
+            addMethod.accept(bridgeHolder, bridgeMethod);
+            assert lookupTarget.apply(method) == bridgeMethod;
+            target = bridgeMethod;
+          }
+        }
         builder.map(method, validTargetFor(target.method, method, lookupTargetOnClass));
       }
     }
   }
 
+  private DexProgramClass findBridgeMethodHolder(DexClass originalClass, DexClass targetClass,
+      String packageDescriptor) {
+    if (originalClass == targetClass || originalClass.isLibraryClass()) {
+      return null;
+    }
+    DexProgramClass newHolder = null;
+    // Recurse through supertype chain.
+    if (originalClass.superType.isSubtypeOf(targetClass.getType(), appInfo)) {
+      DexClass superClass = appInfo.definitionFor(originalClass.superType);
+      newHolder = findBridgeMethodHolder(superClass, targetClass, packageDescriptor);
+    } else {
+      for (DexType iface : originalClass.interfaces.values) {
+        if (iface.isSubtypeOf(targetClass.getType(), appInfo)) {
+          DexClass interfaceClass = appInfo.definitionFor(iface);
+          newHolder = findBridgeMethodHolder(interfaceClass, targetClass, packageDescriptor);
+        }
+      }
+    }
+    if (newHolder != null) {
+      // A supertype fulfills the visibility requirements.
+      return newHolder;
+    } else if (originalClass.accessFlags.isPublic()
+        || originalClass.type.getPackageDescriptor().equals(packageDescriptor)) {
+      // This class is visible. Return it if it is a program class, otherwise null.
+      return originalClass.asProgramClass();
+    }
+    return null;
+  }
+
   private void computeFieldRebinding(Set<DexField> fields,
       BiFunction<DexType, DexField, DexEncodedField> lookup,
       BiFunction<DexClass, DexField, DexEncodedField> lookupTargetOnClass) {
@@ -137,14 +197,19 @@
     }
   }
 
+  private static void privateMethodsCheck(DexProgramClass clazz, DexEncodedMethod method) {
+    throw new Unreachable("Direct invokes should not require forwarding.");
+  }
+
   public GraphLense run() {
     computeMethodRebinding(appInfo.virtualInvokes, this::virtualLookup,
-        DexClass::findVirtualTarget);
-    computeMethodRebinding(appInfo.superInvokes, this::superLookup, DexClass::findVirtualTarget);
+        DexClass::findVirtualTarget, DexProgramClass::addVirtualMethod);
+    computeMethodRebinding(appInfo.superInvokes, this::superLookup, DexClass::findVirtualTarget,
+        DexProgramClass::addVirtualMethod);
     computeMethodRebinding(appInfo.directInvokes, appInfo::lookupDirectTarget,
-        DexClass::findDirectTarget);
+        DexClass::findDirectTarget, MemberRebindingAnalysis::privateMethodsCheck);
     computeMethodRebinding(appInfo.staticInvokes, appInfo::lookupStaticTarget,
-        DexClass::findDirectTarget);
+        DexClass::findDirectTarget, DexProgramClass::addStaticMethod);
 
     computeFieldRebinding(Sets.union(appInfo.staticFieldsRead, appInfo.staticFieldsWritten),
         appInfo::lookupStaticTarget, DexClass::findStaticTarget);
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index e038f6a..ec430fd 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -221,4 +221,5 @@
         return false;
     }
   }
+
 }
diff --git a/src/test/examples/memberrebinding/Test.java b/src/test/examples/memberrebinding/Test.java
index ba5e2f0..62a2440 100644
--- a/src/test/examples/memberrebinding/Test.java
+++ b/src/test/examples/memberrebinding/Test.java
@@ -23,6 +23,7 @@
     System.out.println(classExtendsLibraryClass.get(2));
     PublicClass instance = new PublicClass();
     instance.aMethod();
+    PublicClass.aStaticMethod();
     ClassExtendsOtherLibraryClass classExtendsOther = new ClassExtendsOtherLibraryClass();
     System.out.println(classExtendsOther.aMethodThatReturnsOne());
     System.out.println(classExtendsOther.aMethodThatReturnsTwo());
diff --git a/src/test/examples/memberrebinding/subpackage/PackagePrivateClass.java b/src/test/examples/memberrebinding/subpackage/PackagePrivateClass.java
index d749fb1..89e1cea 100644
--- a/src/test/examples/memberrebinding/subpackage/PackagePrivateClass.java
+++ b/src/test/examples/memberrebinding/subpackage/PackagePrivateClass.java
@@ -8,4 +8,8 @@
   public final void aMethod() {
     System.out.println("Hello, I am aMethod");
   }
+
+  public final static void aStaticMethod() {
+    System.out.println("Hello, I am aStaticMethod");
+  }
 }
diff --git a/src/test/examples/memberrebinding/subpackage/PublicClass.java b/src/test/examples/memberrebinding/subpackage/PublicClass.java
index df3a92d..6c0a270 100644
--- a/src/test/examples/memberrebinding/subpackage/PublicClass.java
+++ b/src/test/examples/memberrebinding/subpackage/PublicClass.java
@@ -3,6 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package memberrebinding.subpackage;
 
-public class PublicClass extends PackagePrivateClass {
+public class PublicClass extends PublicClassInTheMiddle {
   // Intentionally left empty.
 }
diff --git a/src/test/examples/memberrebinding/subpackage/PublicClassInTheMiddle.java b/src/test/examples/memberrebinding/subpackage/PublicClassInTheMiddle.java
new file mode 100644
index 0000000..6ce8cad
--- /dev/null
+++ b/src/test/examples/memberrebinding/subpackage/PublicClassInTheMiddle.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, 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 memberrebinding.subpackage;
+
+public class PublicClassInTheMiddle extends PackagePrivateClass {
+  // Intentionally left empty.
+}
diff --git a/src/test/examplesAndroidN/memberrebinding4/Test.java b/src/test/examplesAndroidN/memberrebinding4/Test.java
new file mode 100644
index 0000000..6fc2ad5
--- /dev/null
+++ b/src/test/examplesAndroidN/memberrebinding4/Test.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2017, 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 memberrebinding4;
+
+import memberrebinding4.subpackage.PublicInterface;
+
+public class Test {
+
+  static class Inner implements PublicInterface {
+
+  }
+
+  public static void main(String[] args) {
+    test();
+  }
+
+  public static void test() {
+    new Inner().dump();
+  }
+}
diff --git a/src/test/examplesAndroidN/memberrebinding4/subpackage/PackagePrivateInterface.java b/src/test/examplesAndroidN/memberrebinding4/subpackage/PackagePrivateInterface.java
new file mode 100644
index 0000000..4bbb70d
--- /dev/null
+++ b/src/test/examplesAndroidN/memberrebinding4/subpackage/PackagePrivateInterface.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2017, 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 memberrebinding4.subpackage;
+
+interface PackagePrivateInterface {
+
+  default void dump() {
+    System.out.println("I3");
+  }
+}
+
diff --git a/src/test/examplesAndroidN/memberrebinding4/subpackage/PublicInterface.java b/src/test/examplesAndroidN/memberrebinding4/subpackage/PublicInterface.java
new file mode 100644
index 0000000..8f2e1bb
--- /dev/null
+++ b/src/test/examplesAndroidN/memberrebinding4/subpackage/PublicInterface.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, 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 memberrebinding4.subpackage;
+
+public interface PublicInterface extends PackagePrivateInterface {
+
+}
+
diff --git a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
index d2aa592..26067c7 100644
--- a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
+++ b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
@@ -16,7 +16,6 @@
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -33,7 +32,6 @@
   @Rule
   public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
 
-  @Ignore("b/38187737")
   @Test
   public void splitMemberRebindingTwoFiles()
       throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 7c75610..115aabd 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -37,9 +37,9 @@
 import com.android.tools.r8.ir.code.Switch.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.ir.desugar.SynthesizedCode;
 import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.AndroidApp;
@@ -82,6 +82,7 @@
   private static final int MANY_CLASSES_COUNT = 1000;
   private static final List<String> MANY_CLASSES;
   private static final String MANY_CLASSES_APP = "many-classes.zip";
+
   static {
     ImmutableList.Builder<String> builder = ImmutableList.builder();
     for (int i = 0; i < MANY_CLASSES_COUNT; ++i) {
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
index e45b639..55bd373 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingTest.java
@@ -7,9 +7,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.CompilationException;
-import com.android.tools.r8.R8;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.DexInspector;
@@ -22,16 +22,12 @@
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Consumer;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -63,23 +59,22 @@
   private final Path programFile;
   private final Consumer<DexInspector> inspection;
   private final Consumer<DexInspector> originalInspection;
+  private final int minApiLevel;
 
   @Rule
   public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
 
-  public MemberRebindingTest(
-      String test, Frontend kind,
-      Consumer<DexInspector> inspection,
-      Consumer<DexInspector> originalInspection) {
-    this.kind = kind;
-    originalDex = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + test + "/classes.dex");
+  public MemberRebindingTest(TestConfiguration configuration) {
+    this.kind = configuration.kind;
+    originalDex = configuration.getDexPath();
     if (kind == Frontend.DEX) {
       this.programFile = originalDex;
     } else {
-      this.programFile = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + test + ".jar");
+      this.programFile = configuration.getJarPath();
     }
-    this.inspection = inspection;
-    this.originalInspection = originalInspection;
+    this.inspection = configuration.processedInspection;
+    this.originalInspection = configuration.originalInspection;
+    this.minApiLevel = configuration.getMinApiLevel();
   }
 
   @Before
@@ -95,12 +90,14 @@
             .setOutputPath(Paths.get(out))
             .addProgramFiles(programFile)
             .addLibraryFiles(ListUtils.map(libs, Paths::get))
+            .setMinApiLevel(minApiLevel)
             .build(),
         options -> options.inlineAccessors = false);
   }
 
   private static boolean coolInvokes(InstructionSubject instruction) {
-    if (!instruction.isInvokeVirtual() && !instruction.isInvokeInterface()) {
+    if (!instruction.isInvokeVirtual() && !instruction.isInvokeInterface() &&
+        !instruction.isInvokeStatic()) {
       return false;
     }
     InvokeInstructionSubject invoke = (InvokeInstructionSubject) instruction;
@@ -121,6 +118,7 @@
     assertTrue(iterator.next().holder().is("memberrebinding.ClassExtendsLibraryClass"));
     assertTrue(iterator.next().holder().is("memberrebinding.ClassExtendsLibraryClass"));
     assertTrue(iterator.next().holder().is("memberrebinding.subpackage.PublicClass"));
+    assertTrue(iterator.next().holder().is("memberrebinding.subpackage.PublicClass"));
     assertTrue(iterator.next().holder().is("memberrebinding.ClassExtendsOtherLibraryClass"));
     assertTrue(iterator.next().holder().is("memberrebinding.ClassExtendsOtherLibraryClass"));
     assertTrue(iterator.next().holder().is("memberrebinding.ClassExtendsOtherLibraryClass"));
@@ -147,7 +145,8 @@
     assertTrue(iterator.next().holder().is("java.util.ArrayList"));
     assertTrue(iterator.next().holder().is("java.util.ArrayList"));
     assertTrue(iterator.next().holder().is("java.util.ArrayList"));
-    assertTrue(iterator.next().holder().is("memberrebinding.subpackage.PackagePrivateClass"));
+    assertTrue(iterator.next().holder().is("memberrebinding.subpackage.PublicClassInTheMiddle"));
+    assertTrue(iterator.next().holder().is("memberrebinding.subpackage.PublicClassInTheMiddle"));
     // For the next three - test that we re-bind to the lowest library class.
     assertTrue(iterator.next().holder().is("memberrebindinglib.SubClass"));
     assertTrue(iterator.next().holder().is("memberrebindinglib.SubClass"));
@@ -173,6 +172,8 @@
       assertTrue(iterator.next().holder().is("memberrebinding2.ClassAtBottomOfChain"));
       assertTrue(iterator.next().holder().is("memberrebinding2.subpackage.PublicClass"));
     }
+    assertTrue(iterator.next().holder().is("java.lang.System"));
+    assertFalse(iterator.hasNext());
   }
 
   private static void inspectMain2(DexInspector inspector) {
@@ -186,6 +187,8 @@
       assertTrue(iterator.next().holder().is("memberrebinding2.SuperClassOfAll"));
       assertTrue(iterator.next().holder().is("memberrebinding2.subpackage.PackagePrivateClass"));
     }
+    assertTrue(iterator.next().holder().is("java.lang.System"));
+    assertFalse(iterator.hasNext());
   }
 
   public static MethodSignature TEST =
@@ -198,6 +201,7 @@
     assertTrue(iterator.next().holder().is("memberrebinding3.ClassAtBottomOfChain"));
     assertTrue(iterator.next().holder().is("memberrebinding3.ClassAtBottomOfChain"));
     assertTrue(iterator.next().holder().is("memberrebinding3.ClassAtBottomOfChain"));
+    assertFalse(iterator.hasNext());
   }
 
   private static void inspect3(DexInspector inspector) {
@@ -207,38 +211,114 @@
     assertTrue(iterator.next().holder().is("memberrebinding3.ClassAtBottomOfChain"));
     assertTrue(iterator.next().holder().is("memberrebinding3.ClassInMiddleOfChain"));
     assertTrue(iterator.next().holder().is("memberrebinding3.SuperClassOfAll"));
+    assertFalse(iterator.hasNext());
   }
 
-  @Parameters(name = "{0}{1}")
-  public static Collection<Object[]> data() {
-    List<String> tests =
-        ImmutableList.of("memberrebinding", "memberrebinding2", "memberrebinding3");
+  private static void inspectOriginal4(DexInspector inspector) {
+    MethodSubject main = inspector.clazz("memberrebinding4.Test").method(TEST);
+    Iterator<InvokeInstructionSubject> iterator =
+        main.iterateInstructions(InstructionSubject::isInvoke);
+    assertTrue(iterator.next().holder().is("memberrebinding4.Test$Inner"));
+    assertTrue(iterator.next().holder().is("memberrebinding4.subpackage.PublicInterface"));
+    assertFalse(iterator.hasNext());
+  }
 
-    Map<String, List<Consumer<DexInspector>>> inspections = new HashMap<>();
-    inspections.put("memberrebinding", ImmutableList.of(
-        MemberRebindingTest::inspectMain,
-        MemberRebindingTest::inspectOriginalMain));
-    inspections.put("memberrebinding2", ImmutableList.of(
-        MemberRebindingTest::inspectMain2,
-        MemberRebindingTest::inspectOriginalMain2));
-    inspections.put("memberrebinding3", ImmutableList.of(
-        MemberRebindingTest::inspect3,
-        MemberRebindingTest::inspectOriginal3));
+  private static void inspect4(DexInspector inspector) {
+    MethodSubject main = inspector.clazz("memberrebinding4.Test").method(TEST);
+    Iterator<InvokeInstructionSubject> iterator =
+        main.iterateInstructions(InstructionSubject::isInvoke);
+    assertTrue(iterator.next().holder().is("memberrebinding4.Test$Inner"));
+    assertTrue(iterator.next().holder().is("memberrebinding4.subpackage.PublicInterface"));
+    assertFalse(iterator.hasNext());
+  }
 
-    List<Object[]> testCases = new ArrayList<>();
-    Set<String> usedInspections = new HashSet<>();
+  private static class TestConfiguration {
 
-    for (String test : tests) {
-      List<Consumer<DexInspector>> inspection = inspections.get(test);
-      assert inspection != null;
-      usedInspections.add(test);
-      testCases.add(new Object[]{test, Frontend.JAR, inspection.get(0), inspection.get(1)});
-      testCases.add(new Object[]{test, Frontend.DEX, inspection.get(0), inspection.get(1)});
+    private enum AndroidVersion {
+      PRE_N,
+      N
     }
 
-    assert usedInspections.size() == inspections.size();
+    final String name;
+    final Frontend kind;
+    final AndroidVersion version;
+    final Consumer<DexInspector> originalInspection;
+    final Consumer<DexInspector> processedInspection;
 
-    return testCases;
+    private TestConfiguration(String name,
+        Frontend kind,
+        AndroidVersion version,
+        Consumer<DexInspector> originalInspection,
+        Consumer<DexInspector> processedInspection) {
+      this.name = name;
+      this.kind = kind;
+      this.version = version;
+      this.originalInspection = originalInspection;
+      this.processedInspection = processedInspection;
+    }
+
+    public static void add(ImmutableList.Builder<TestConfiguration> builder,
+        String name,
+        AndroidVersion version,
+        Consumer<DexInspector> originalInspection,
+        Consumer<DexInspector> processedInspection) {
+      if (version == AndroidVersion.PRE_N) {
+        builder.add(new TestConfiguration(name, Frontend.DEX, version, originalInspection,
+            processedInspection));
+      }
+      builder.add(new TestConfiguration(name, Frontend.JAR, version, originalInspection,
+          processedInspection));
+    }
+
+    public Path getDexPath() {
+      return getBuildPath().resolve(name).resolve("classes.dex");
+    }
+
+    public Path getJarPath() {
+      return getBuildPath().resolve(name + ".jar");
+    }
+
+    public Path getBuildPath() {
+      switch (version) {
+        case PRE_N:
+          return Paths.get(ToolHelper.EXAMPLES_BUILD_DIR);
+        case N:
+          return Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR);
+        default:
+          Assert.fail();
+          return null;
+      }
+    }
+
+    public int getMinApiLevel() {
+      switch (version) {
+        case PRE_N:
+          return Constants.DEFAULT_ANDROID_API;
+        case N:
+          return Constants.ANDROID_N_API;
+        default:
+          Assert.fail();
+          return -1;
+      }
+    }
+
+    public String toString() {
+      return name + " " + kind;
+    }
+  }
+
+  @Parameters(name = "{0}")
+  public static Collection<TestConfiguration> data() {
+    ImmutableList.Builder<TestConfiguration> builder = ImmutableList.builder();
+    TestConfiguration.add(builder, "memberrebinding", TestConfiguration.AndroidVersion.PRE_N,
+        MemberRebindingTest::inspectOriginalMain, MemberRebindingTest::inspectMain);
+    TestConfiguration.add(builder, "memberrebinding2", TestConfiguration.AndroidVersion.PRE_N,
+        MemberRebindingTest::inspectOriginalMain2, MemberRebindingTest::inspectMain2);
+    TestConfiguration.add(builder, "memberrebinding3", TestConfiguration.AndroidVersion.PRE_N,
+        MemberRebindingTest::inspectOriginal3, MemberRebindingTest::inspect3);
+    TestConfiguration.add(builder, "memberrebinding4", TestConfiguration.AndroidVersion.N,
+        MemberRebindingTest::inspectOriginal4, MemberRebindingTest::inspect4);
+    return builder.build();
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/utils/DexInspector.java b/src/test/java/com/android/tools/r8/utils/DexInspector.java
index 694ccc5..39e7dd2 100644
--- a/src/test/java/com/android/tools/r8/utils/DexInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/DexInspector.java
@@ -886,6 +886,12 @@
       if (instruction instanceof InvokeDirectRange) {
         return ((InvokeDirectRange) instruction).getMethod();
       }
+      if (instruction instanceof InvokeStatic) {
+        return ((InvokeStatic) instruction).getMethod();
+      }
+      if (instruction instanceof InvokeStaticRange) {
+        return ((InvokeStaticRange) instruction).getMethod();
+      }
       assert false;
       return null;
     }