Skeleton for open/closed interfaces analysis on cf code

Change-Id: I39d08bb93352e3a82ef95b3e737a1d05d8e32995
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
index 9156bc4..4cf9e5e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
@@ -57,6 +57,10 @@
     return blocks.get(blockEntry);
   }
 
+  public CfBlock getEntryBlock() {
+    return getBlock(code.getInstructions().get(0));
+  }
+
   @Override
   public <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
       CfBlock block,
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
new file mode 100644
index 0000000..789881b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2022, 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.optimize.interfaces.analysis;
+
+public class BottomCfFrameState extends CfFrameState {
+
+  private static final BottomCfFrameState INSTANCE = new BottomCfFrameState();
+
+  private BottomCfFrameState() {}
+
+  static BottomCfFrameState getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    return this == other;
+  }
+
+  @Override
+  public int hashCode() {
+    return System.identityHashCode(this);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
new file mode 100644
index 0000000..ac4ce53
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, 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.optimize.interfaces.analysis;
+
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
+
+public abstract class CfFrameState extends AbstractState<CfFrameState> {
+
+  public static CfFrameState bottom() {
+    return BottomCfFrameState.getInstance();
+  }
+
+  public static ErroneousCfFrameState error() {
+    return ErroneousCfFrameState.getInstance();
+  }
+
+  @Override
+  public CfFrameState asAbstractState() {
+    return this;
+  }
+
+  @Override
+  public final CfFrameState join(CfFrameState state) {
+    // TODO(b/214496607): Implement join.
+    throw new Unimplemented();
+  }
+
+  @Override
+  public abstract boolean equals(Object other);
+
+  @Override
+  public abstract int hashCode();
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
new file mode 100644
index 0000000..2e9b913
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, 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.optimize.interfaces.analysis;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractTransferFunction;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.DataflowAnalysisResult;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.TransferFunctionResult;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfBlock;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfControlFlowGraph;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfIntraproceduralDataflowAnalysis;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class CfOpenClosedInterfacesAnalysis {
+
+  private final AppView<AppInfoWithLiveness> appView;
+
+  public CfOpenClosedInterfacesAnalysis(AppView<AppInfoWithLiveness> appView) {
+    this.appView = appView;
+  }
+
+  public void run() {
+    // TODO(b/214496607): Parallelize the analysis.
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      clazz.forEachProgramMethodMatching(DexEncodedMethod::hasCode, this::processMethod);
+    }
+  }
+
+  private void processMethod(ProgramMethod method) {
+    Code code = method.getDefinition().getCode();
+    if (!code.isCfCode()) {
+      assert code.isDefaultInstanceInitializerCode() || code.isThrowNullCode();
+      return;
+    }
+
+    CfCode cfCode = code.asCfCode();
+    CfControlFlowGraph cfg = CfControlFlowGraph.create(cfCode);
+    CfIntraproceduralDataflowAnalysis<CfFrameState> analysis =
+        new CfIntraproceduralDataflowAnalysis<>(
+            CfFrameState.bottom(), cfg, new TransferFunction(method));
+    DataflowAnalysisResult result = analysis.run(cfg.getEntryBlock());
+    // TODO(b/214496607): Determine open interfaces.
+  }
+
+  private class TransferFunction
+      implements AbstractTransferFunction<CfBlock, CfInstruction, CfFrameState> {
+
+    private final ProgramMethod context;
+
+    TransferFunction(ProgramMethod context) {
+      this.context = context;
+    }
+
+    @Override
+    public TransferFunctionResult<CfFrameState> apply(
+        CfInstruction instruction, CfFrameState state) {
+      // TODO(b/214496607): Implement this.
+      throw new Unimplemented();
+    }
+
+    @Override
+    public CfFrameState computeBlockEntryState(
+        CfBlock cfBlock, CfBlock predecessor, CfFrameState predecessorExitState) {
+      // TODO(b/214496607): Implement this.
+      throw new Unimplemented();
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
new file mode 100644
index 0000000..a077574
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, 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.optimize.interfaces.analysis;
+
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Objects;
+
+public class ConcreteCfFrameState extends CfFrameState {
+
+  private final Int2ObjectSortedMap<FrameType> locals;
+  private final Deque<FrameType> stack;
+
+  ConcreteCfFrameState() {
+    this(new Int2ObjectAVLTreeMap<>(), new ArrayDeque<>());
+  }
+
+  ConcreteCfFrameState(Int2ObjectSortedMap<FrameType> locals, Deque<FrameType> stack) {
+    this.locals = locals;
+    this.stack = stack;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    ConcreteCfFrameState that = (ConcreteCfFrameState) o;
+    return locals.equals(that.locals) && stack.equals(that.stack);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(locals, stack);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
new file mode 100644
index 0000000..687cd3b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, 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.optimize.interfaces.analysis;
+
+/** An analysis state representing that the code does not type check. */
+public class ErroneousCfFrameState extends CfFrameState {
+
+  private static final ErroneousCfFrameState INSTANCE = new ErroneousCfFrameState();
+
+  private ErroneousCfFrameState() {}
+
+  static ErroneousCfFrameState getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    return this == other;
+  }
+
+  @Override
+  public int hashCode() {
+    return System.identityHashCode(this);
+  }
+}