public static void removeBasicBlockMatch(
      final GraphsContainer graphs, final CombinedDiffNode oldCombinedDiffNode)
      throws GraphLayoutException {
    // TODO(cblichmann): On cancel, restore FunctionDiffData (reload from database) in order to
    //                   update the workspace counts.
    // TODO(cblichmann): Update the open call graph view if a basic block has been removed (or
    //                   added)
    // - change node color if necessary
    // - change calls from matched to unmatched color
    // - change proximity nodes of combined
    // - change calls from unmatched to matched color (as soon as newly assigned basic block
    //   comments can be diffed)
    graphs.getCombinedGraph().getIntermediateListeners().blockZyLibVisibilityListeners();
    graphs.getCombinedGraph().getIntermediateListeners().blockZyLibSelectionListeners();

    try {
      final SuperDiffNode oldSuperDiffNode = oldCombinedDiffNode.getSuperDiffNode();
      final SingleDiffNode oldPrimaryDiffNode = oldCombinedDiffNode.getPrimaryDiffNode();
      final SingleDiffNode oldSecondaryDiffNode = oldCombinedDiffNode.getSecondaryDiffNode();

      final RawCombinedBasicBlock oldRawCombinedBasicBlock =
          (RawCombinedBasicBlock) oldCombinedDiffNode.getRawNode();
      final SuperViewNode oldRawSuperBasicBlock = oldSuperDiffNode.getRawNode();
      final RawBasicBlock oldRawPrimaryBasicBlock = (RawBasicBlock) oldPrimaryDiffNode.getRawNode();
      final RawBasicBlock oldRawSecondaryBasicBlock =
          (RawBasicBlock) oldSecondaryDiffNode.getRawNode();

      final RawCombinedFlowGraph<RawCombinedBasicBlock, RawCombinedJump<RawCombinedBasicBlock>>
          combinedRawFlowGraph = getRawCombinedFlowgraph(graphs, oldCombinedDiffNode);
      final RawFlowGraph priRawFlowGraph = combinedRawFlowGraph.getPrimaryFlowgraph();
      final RawFlowGraph secRawFlowGraph = combinedRawFlowGraph.getSecondaryFlowgraph();

      // Sync visibility in async view mode
      syncBasicBlockVisibility(graphs, oldCombinedDiffNode);

      // Store old incoming and outgoing super jumps
      final Set<SuperViewEdge<? extends SuperViewNode>> oldRawSuperJumps = new HashSet<>();
      oldRawSuperJumps.addAll(oldRawSuperBasicBlock.getIncomingEdges());
      oldRawSuperJumps.addAll(oldRawSuperBasicBlock.getOutgoingEdges());

      // Delete raw nodes and edges
      combinedRawFlowGraph.removeNode(oldRawCombinedBasicBlock);
      oldRawSuperBasicBlock.removeNode();
      priRawFlowGraph.removeNode(oldRawPrimaryBasicBlock);
      secRawFlowGraph.removeNode(oldRawSecondaryBasicBlock);

      // Delete diff nodes and edges including possibly affected proximity nodes
      graphs.getCombinedGraph().deleteNode(oldCombinedDiffNode);
      graphs.getSuperGraph().deleteNode(oldSuperDiffNode);
      graphs.getPrimaryGraph().deleteNode(oldPrimaryDiffNode);
      graphs.getSecondaryGraph().deleteNode(oldSecondaryDiffNode);

      // Create new raw basic blocks
      final RawBasicBlock newRawPrimaryBasicBlock =
          oldRawPrimaryBasicBlock.clone(EMatchState.PRIMARY_UNMATCHED);
      final RawBasicBlock newRawSecondaryBasicBlock =
          oldRawSecondaryBasicBlock.clone(EMatchState.SECONDRAY_UNMATCHED);
      final RawCombinedBasicBlock newRawCombinedPriUnmatchedBasicBlock =
          new RawCombinedBasicBlock(
              newRawPrimaryBasicBlock, null, null, oldRawPrimaryBasicBlock.getFunctionAddr(), null);
      final RawCombinedBasicBlock newRawCombinedSecUnmatchedBasicBlock =
          new RawCombinedBasicBlock(
              null,
              newRawSecondaryBasicBlock,
              null,
              null,
              oldRawSecondaryBasicBlock.getFunctionAddr());
      final SuperViewNode newRawSuperPriUnmatchedBasicBlock =
          new SuperViewNode(newRawCombinedPriUnmatchedBasicBlock);
      final SuperViewNode newRawSuperSecUnmatchedBasicBlock =
          new SuperViewNode(newRawCombinedSecUnmatchedBasicBlock);

      // Add new raw basic blocks to raw graphs
      // Create new raw jumps and add jumps to raw graph
      // New primary unmatched nodes and edges
      insertNewRawNodes(
          combinedRawFlowGraph,
          priRawFlowGraph,
          oldRawSuperJumps,
          oldRawSuperBasicBlock,
          newRawPrimaryBasicBlock,
          newRawCombinedPriUnmatchedBasicBlock,
          newRawSuperPriUnmatchedBasicBlock);
      // New secondary unmatched nodes and edges
      insertNewRawNodes(
          combinedRawFlowGraph,
          secRawFlowGraph,
          oldRawSuperJumps,
          oldRawSuperBasicBlock,
          newRawSecondaryBasicBlock,
          newRawCombinedSecUnmatchedBasicBlock,
          newRawSuperSecUnmatchedBasicBlock);

      // Remove diff basic block match from function match data
      removeBasicBlockMatch(graphs, oldRawCombinedBasicBlock);

      // Create new diff nodes and add to diff graphs
      // Create new diff edges and add to diff graphs
      // New primary unmatched nodes and edges
      insertNewDiffNodes(graphs, combinedRawFlowGraph, newRawSuperPriUnmatchedBasicBlock);
      // New secondary unmatched nodes and edges
      insertNewDiffNodes(graphs, combinedRawFlowGraph, newRawSuperSecUnmatchedBasicBlock);

      // Notify intermediate listener to update graph node tree, selection history and main menu of
      // this view
      graphs
          .getDiff()
          .getMatches()
          .notifyBasicBlockMatchRemovedListener(
              newRawPrimaryBasicBlock.getFunctionAddr(),
                  newRawSecondaryBasicBlock.getFunctionAddr(),
              newRawPrimaryBasicBlock.getAddress(), newRawSecondaryBasicBlock.getAddress());
    } finally {
      graphs.getCombinedGraph().getIntermediateListeners().freeZyLibVisibilityListeners();
      graphs.getCombinedGraph().getIntermediateListeners().freeZyLibSelectionListeners();
    }

    // Layout graphs
    doSynchronizedLayout(graphs.getCombinedGraph());
  }
Utility class to remove basic block matches from BinDiff graphs.
java/ui/src/main/java/com/google/security/zynamics/bindiff/graph/helpers/BasicBlockMatchRemover.java