Extend InstructionSubject classes to CF, enable CF on ApplyMappingTest.

Change-Id: Ia5efcc468836db0f34a9f00c054fd2d0f5239eee
diff --git a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
index 876a758..39d7f0b 100644
--- a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -15,8 +16,6 @@
 import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.NewInstance;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
@@ -26,14 +25,21 @@
 import com.android.tools.r8.utils.dexinspector.InstructionSubject;
 import com.android.tools.r8.utils.dexinspector.InvokeInstructionSubject;
 import com.android.tools.r8.utils.dexinspector.MethodSubject;
+import com.android.tools.r8.utils.dexinspector.NewInstanceInstructionSubject;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class ApplyMappingTest extends TestBase {
 
   private static final String MAPPING = "test-mapping.txt";
@@ -52,9 +58,20 @@
 
   private Path out;
 
+  private Backend backend;
+
+  @Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public ApplyMappingTest(Backend backend) {
+    this.backend = backend;
+  }
+
   @Before
   public void setup() throws IOException {
-    out = temp.newFolder("outdex").toPath();
+    out = temp.newFolder("out").toPath();
   }
 
   @Test
@@ -97,7 +114,7 @@
                     pgConfig -> pgConfig.setApplyMappingFile(proguardMap))
                 .build());
 
-    DexInspector inspector = new DexInspector(instrApp);
+    DexInspector inspector = createDexInspector(instrApp);
     MethodSubject main = inspector.clazz("applymapping044.Main").method(DexInspector.MAIN);
     Iterator<InvokeInstructionSubject> iterator =
         main.iterateInstructions(InstructionSubject::isInvoke);
@@ -152,7 +169,7 @@
                 .build());
 
     // Make sure the given proguard map is indeed applied.
-    DexInspector inspector = new DexInspector(outputApp);
+    DexInspector inspector = createDexInspector(outputApp);
     MethodSubject main = inspector.clazz("applymapping044.Main").method(DexInspector.MAIN);
     Iterator<InvokeInstructionSubject> iterator =
         main.iterateInstructions(InstructionSubject::isInvoke);
@@ -194,6 +211,15 @@
     assertEquals("p", original_f.invokedMethod().name.toString());
   }
 
+  private static DexInspector createDexInspector(AndroidApp outputApp)
+      throws IOException, ExecutionException {
+    return new DexInspector(
+        outputApp,
+        o -> {
+          o.enableCfFrontend = true;
+        });
+  }
+
   @Test
   public void test_naming001_rule105() throws Exception {
     // keep rules to reserve D and E, along with a proguard map.
@@ -210,7 +236,7 @@
                 .build());
 
     // Make sure the given proguard map is indeed applied.
-    DexInspector inspector = new DexInspector(outputApp);
+    DexInspector inspector = createDexInspector(outputApp);
     MethodSubject main = inspector.clazz("naming001.D").method(DexInspector.MAIN);
     Iterator<InvokeInstructionSubject> iterator =
         main.iterateInstructions(InstructionSubject::isInvoke);
@@ -242,13 +268,20 @@
                 .build());
 
     // Make sure the given proguard map is indeed applied.
-    DexInspector inspector = new DexInspector(outputApp);
+    DexInspector inspector = createDexInspector(outputApp);
     MethodSubject main = inspector.clazz("naming001.D").method(DexInspector.MAIN);
 
+    Iterator<InstructionSubject> iterator = main.iterateInstructions();
     // naming001.E is renamed to a.a, so first instruction must be: new-instance La/a;
-    Instruction[] instructions = main.getMethod().getCode().asDexCode().instructions;
-    assertTrue(instructions[0] instanceof NewInstance);
-    NewInstance newInstance = (NewInstance) instructions[0];
+    NewInstanceInstructionSubject newInstance = null;
+    while (iterator.hasNext()) {
+      InstructionSubject instruction = iterator.next();
+      if (instruction.isNewInstance()) {
+        newInstance = (NewInstanceInstructionSubject) instruction;
+        break;
+      }
+    }
+    assertNotNull(newInstance);
     assertEquals( "La/a;", newInstance.getType().toSmaliString());
   }
 
@@ -269,7 +302,7 @@
     return R8Command.builder()
         .addLibraryFiles(ToolHelper.getDefaultAndroidJar(), mainApp)
         .addProgramFiles(instrApp)
-        .setOutput(out, OutputMode.DexIndexed)
+        .setOutput(out, backend == Backend.DEX ? OutputMode.DexIndexed : OutputMode.ClassFile)
         .addProguardConfigurationFiles(flag);
   }
 
@@ -278,15 +311,17 @@
     return R8Command.builder()
         .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
         .addProgramFiles(jars)
-        .setOutput(out, OutputMode.DexIndexed)
+        .setOutput(out, backend == Backend.DEX ? OutputMode.DexIndexed : OutputMode.ClassFile)
         .addProguardConfigurationFiles(flag);
   }
 
   private static AndroidApp runR8(R8Command command)
       throws ProguardRuleParserException, ExecutionException, IOException {
-    return ToolHelper.runR8(command, options -> {
-      // Disable inlining to make this test not depend on inlining decisions.
-      options.enableInlining = false;
-    });
+    return ToolHelper.runR8(
+        command,
+        options -> {
+          // Disable inlining to make this test not depend on inlining decisions.
+          options.enableInlining = false;
+        });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java
index 7213a54..e2fa906 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java
@@ -10,12 +10,6 @@
 
 public class AbsentClassSubject extends ClassSubject {
 
-  private DexInspector dexInspector;
-
-  public AbsentClassSubject(DexInspector dexInspector) {
-    this.dexInspector = dexInspector;
-  }
-
   @Override
   public boolean isPresent() {
     return false;
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionIterator.java
new file mode 100644
index 0000000..d000250
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionIterator.java
@@ -0,0 +1,33 @@
+// 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.graph.Code;
+import java.util.Iterator;
+
+class CfInstructionIterator implements InstructionIterator {
+
+  private final DexInspector dexInspector;
+  private final Iterator<CfInstruction> iterator;
+
+  CfInstructionIterator(DexInspector dexInspector, MethodSubject method) {
+    this.dexInspector = dexInspector;
+    assert method.isPresent();
+    Code code = method.getMethod().getCode();
+    assert code != null && code.isCfCode();
+    iterator = code.asCfCode().getInstructions().iterator();
+  }
+
+  @Override
+  public boolean hasNext() {
+    return iterator.hasNext();
+  }
+
+  @Override
+  public InstructionSubject next() {
+    return dexInspector.createInstructionSubject(iterator.next());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
new file mode 100644
index 0000000..ae900f3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
@@ -0,0 +1,118 @@
+// 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfConstString;
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfGoto;
+import com.android.tools.r8.cf.code.CfIf;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfNop;
+import com.android.tools.r8.cf.code.CfPosition;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.CfThrow;
+import org.objectweb.asm.Opcodes;
+
+public class CfInstructionSubject implements InstructionSubject {
+  protected final CfInstruction instruction;
+
+  public CfInstructionSubject(CfInstruction instruction) {
+    this.instruction = instruction;
+  }
+
+  @Override
+  public boolean isFieldAccess() {
+    return instruction instanceof CfFieldInstruction;
+  }
+
+  @Override
+  public boolean isInvokeVirtual() {
+    return instruction instanceof CfInvoke
+        && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKEVIRTUAL;
+  }
+
+  @Override
+  public boolean isInvokeInterface() {
+    return instruction instanceof CfInvoke
+        && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKEINTERFACE;
+  }
+
+  @Override
+  public boolean isInvokeStatic() {
+    return instruction instanceof CfInvoke
+        && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKESTATIC;
+  }
+
+  @Override
+  public boolean isNop() {
+    return instruction instanceof CfNop;
+  }
+
+  @Override
+  public boolean isConstString() {
+    return instruction instanceof CfConstString;
+  }
+
+  @Override
+  public boolean isConstString(String value) {
+    return isConstString() && ((CfConstString) instruction).getString().toString().equals(value);
+  }
+
+  @Override
+  public boolean isGoto() {
+    return instruction instanceof CfGoto;
+  }
+
+  @Override
+  public boolean isIfNez() {
+    return instruction instanceof CfIf && ((CfIf) instruction).getOpcode() == Opcodes.IFNE;
+  }
+
+  @Override
+  public boolean isIfEqz() {
+    return instruction instanceof CfIf && ((CfIf) instruction).getOpcode() == Opcodes.IFEQ;
+  }
+
+  @Override
+  public boolean isReturnVoid() {
+    return instruction instanceof CfReturnVoid;
+  }
+
+  @Override
+  public boolean isThrow() {
+    return instruction instanceof CfThrow;
+  }
+
+  @Override
+  public boolean isInvoke() {
+    return instruction instanceof CfInvoke || instruction instanceof CfInvokeDynamic;
+  }
+
+  @Override
+  public boolean isNewInstance() {
+    return instruction instanceof CfNew;
+  }
+
+  public boolean isInvokeSpecial() {
+    return instruction instanceof CfInvoke
+        && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKESPECIAL;
+  }
+
+  public boolean isInvokeDynamic() {
+    return instruction instanceof CfInvokeDynamic;
+  }
+
+  public boolean isLabel() {
+    return instruction instanceof CfLabel;
+  }
+
+  public boolean isPosition() {
+    return instruction instanceof CfPosition;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java
index 51e4ce2..c67a560 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java
@@ -6,8 +6,10 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.StringResource;
+import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationElement;
@@ -205,7 +207,7 @@
     }
     DexClass clazz = application.definitionFor(toDexTypeIgnorePrimitives(name));
     if (clazz == null) {
-      return new AbsentClassSubject(this);
+      return new AbsentClassSubject();
     }
     return new FoundClassSubject(this, clazz, naming);
   }
@@ -250,15 +252,36 @@
       return new InvokeDexInstructionSubject(this, instruction);
     } else if (dexInst.isFieldAccess()) {
       return new FieldAccessDexInstructionSubject(this, instruction);
+    } else if (dexInst.isNewInstance()) {
+      return new NewInstanceDexInstructionSubject(instruction);
     } else {
       return dexInst;
     }
   }
 
+  InstructionSubject createInstructionSubject(CfInstruction instruction) {
+    CfInstructionSubject cfInst = new CfInstructionSubject(instruction);
+    if (cfInst.isInvoke()) {
+      return new InvokeCfInstructionSubject(this, instruction);
+    } else if (cfInst.isFieldAccess()) {
+      return new FieldAccessCfInstructionSubject(this, instruction);
+    } else if (cfInst.isNewInstance()) {
+      return new NewInstanceCfInstructionSubject(instruction);
+    } else {
+      return cfInst;
+    }
+  }
+
   InstructionIterator createInstructionIterator(MethodSubject method) {
     Code code = method.getMethod().getCode();
-    assert code != null && code.isDexCode();
-    return new DexInstructionIterator(this, method);
+    assert code != null;
+    if (code.isDexCode()) {
+      return new DexInstructionIterator(this, method);
+    } else if (code.isCfCode()) {
+      return new CfInstructionIterator(this, method);
+    } else {
+      throw new Unimplemented("InstructionIterator is implemented for DexCode and CfCode only.");
+    }
   }
 
   // Build the generic signature using the current mapping if any.
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java
index eaff010..9ed4de1 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java
@@ -10,7 +10,7 @@
 
 class DexInstructionIterator implements InstructionIterator {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
   private final DexCode code;
   private int index;
 
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java
index b2320d3..82d725a 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java
@@ -34,6 +34,7 @@
 import com.android.tools.r8.code.IputObject;
 import com.android.tools.r8.code.IputShort;
 import com.android.tools.r8.code.IputWide;
+import com.android.tools.r8.code.NewInstance;
 import com.android.tools.r8.code.Nop;
 import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.code.Sget;
@@ -53,7 +54,7 @@
 import com.android.tools.r8.code.Throw;
 
 public class DexInstructionSubject implements InstructionSubject {
-  protected Instruction instruction;
+  protected final Instruction instruction;
 
   public DexInstructionSubject(Instruction instruction) {
     this.instruction = instruction;
@@ -75,16 +76,6 @@
   }
 
   @Override
-  public boolean isInvokeDirect() {
-    return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
-  }
-
-  @Override
-  public boolean isInvokeSuper() {
-    return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
-  }
-
-  @Override
   public boolean isInvokeStatic() {
     return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
   }
@@ -131,6 +122,28 @@
     return instruction instanceof Throw;
   }
 
+  @Override
+  public boolean isInvoke() {
+    return isInvokeVirtual()
+        || isInvokeInterface()
+        || isInvokeDirect()
+        || isInvokeSuper()
+        || isInvokeStatic();
+  }
+
+  @Override
+  public boolean isNewInstance() {
+    return instruction instanceof NewInstance;
+  }
+
+  public boolean isInvokeSuper() {
+    return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
+  }
+
+  public boolean isInvokeDirect() {
+    return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
+  }
+
   public boolean isConst4() {
     return instruction instanceof Const4;
   }
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessCfInstructionSubject.java
new file mode 100644
index 0000000..a2103e6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessCfInstructionSubject.java
@@ -0,0 +1,23 @@
+// 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstruction;
+
+public class FieldAccessCfInstructionSubject extends CfInstructionSubject
+    implements FieldAccessInstructionSubject {
+  private final DexInspector dexInspector;
+
+  public FieldAccessCfInstructionSubject(DexInspector dexInspector, CfInstruction instruction) {
+    super(instruction);
+    this.dexInspector = dexInspector;
+    assert isFieldAccess();
+  }
+
+  public TypeSubject holder() {
+    return new TypeSubject(dexInspector, ((CfFieldInstruction) instruction).getField().getHolder());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java
index c3ea3fc..ed54f90 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java
@@ -9,7 +9,7 @@
 public class FieldAccessDexInstructionSubject extends DexInstructionSubject
     implements FieldAccessInstructionSubject {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
 
   public FieldAccessDexInstructionSubject(DexInspector dexInspector, Instruction instruction) {
     super(instruction);
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java
index 33ac77f..5f3c078 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java
@@ -10,14 +10,12 @@
 
 class FilteredInstructionIterator<T extends InstructionSubject> implements Iterator<T> {
 
-  private DexInspector dexInspector;
   private final InstructionIterator iterator;
   private final Predicate<InstructionSubject> predicate;
   private InstructionSubject pendingNext = null;
 
   FilteredInstructionIterator(
       DexInspector dexInspector, MethodSubject method, Predicate<InstructionSubject> predicate) {
-    this.dexInspector = dexInspector;
     this.iterator = dexInspector.createInstructionIterator(method);
     this.predicate = predicate;
     hasNext();
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java
index 12dbaeb..2202f89 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java
@@ -25,7 +25,7 @@
 
 public class FoundClassSubject extends ClassSubject {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
   private final DexClass dexClass;
   final ClassNamingForNameMapper naming;
 
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java
index 52aa0ce..5dfa4f1 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java
@@ -12,7 +12,7 @@
 
 public class FoundFieldSubject extends FieldSubject {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
   private final FoundClassSubject clazz;
   private final DexEncodedField dexField;
 
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java
index e245258..6eb3858 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java
@@ -13,7 +13,7 @@
 
 public class FoundMethodSubject extends MethodSubject {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
   private final FoundClassSubject clazz;
   private final DexEncodedMethod dexMethod;
 
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java
index 00102e5..b6f1e52 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java
@@ -11,10 +11,6 @@
 
   boolean isInvokeInterface();
 
-  boolean isInvokeDirect();
-
-  boolean isInvokeSuper();
-
   boolean isInvokeStatic();
 
   boolean isNop();
@@ -33,11 +29,7 @@
 
   boolean isThrow();
 
-  default boolean isInvoke() {
-    return isInvokeVirtual()
-        || isInvokeInterface()
-        || isInvokeDirect()
-        || isInvokeSuper()
-        || isInvokeStatic();
-  }
+  boolean isInvoke();
+
+  boolean isNewInstance();
 }
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeCfInstructionSubject.java
new file mode 100644
index 0000000..4d245b2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeCfInstructionSubject.java
@@ -0,0 +1,33 @@
+// 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.graph.DexMethod;
+
+public class InvokeCfInstructionSubject extends CfInstructionSubject
+    implements InvokeInstructionSubject {
+  private final DexInspector dexInspector;
+
+  public InvokeCfInstructionSubject(DexInspector dexInspector, CfInstruction instruction) {
+    super(instruction);
+    assert isInvoke();
+    this.dexInspector = dexInspector;
+  }
+
+  public TypeSubject holder() {
+    return new TypeSubject(dexInspector, invokedMethod().getHolder());
+  }
+
+  public DexMethod invokedMethod() {
+    if (isInvokeDynamic()) {
+      throw new Unimplemented(
+          "invokeMethod is not implemented for the INVOKEDYNAMIC CF instruction.");
+    }
+    return ((CfInvoke) instruction).getMethod();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java
index a4f5636..51d0767 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java
@@ -10,7 +10,7 @@
 public class InvokeDexInstructionSubject extends DexInstructionSubject
     implements InvokeInstructionSubject {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
 
   public InvokeDexInstructionSubject(DexInspector dexInspector, Instruction instruction) {
     super(instruction);
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceCfInstructionSubject.java
new file mode 100644
index 0000000..71a1dfc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceCfInstructionSubject.java
@@ -0,0 +1,17 @@
+package com.android.tools.r8.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.graph.DexType;
+
+public class NewInstanceCfInstructionSubject extends CfInstructionSubject
+    implements NewInstanceInstructionSubject {
+  public NewInstanceCfInstructionSubject(CfInstruction instruction) {
+    super(instruction);
+  }
+
+  @Override
+  public DexType getType() {
+    return ((CfNew) instruction).getType();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceDexInstructionSubject.java
new file mode 100644
index 0000000..675ded2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceDexInstructionSubject.java
@@ -0,0 +1,17 @@
+package com.android.tools.r8.utils.dexinspector;
+
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.code.NewInstance;
+import com.android.tools.r8.graph.DexType;
+
+public class NewInstanceDexInstructionSubject extends DexInstructionSubject
+    implements NewInstanceInstructionSubject {
+  public NewInstanceDexInstructionSubject(Instruction instruction) {
+    super(instruction);
+  }
+
+  @Override
+  public DexType getType() {
+    return ((NewInstance) instruction).getType();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceInstructionSubject.java
new file mode 100644
index 0000000..98a10ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceInstructionSubject.java
@@ -0,0 +1,7 @@
+package com.android.tools.r8.utils.dexinspector;
+
+import com.android.tools.r8.graph.DexType;
+
+public interface NewInstanceInstructionSubject extends InstructionSubject {
+  DexType getType();
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java
index 6a911eb..5b21c41 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java
@@ -8,7 +8,7 @@
 
 public class TypeSubject extends Subject {
 
-  private DexInspector dexInspector;
+  private final DexInspector dexInspector;
   private final DexType dexType;
 
   TypeSubject(DexInspector dexInspector, DexType dexType) {