boolean (ControlFlowGraph graph, BasicBlock block, boolean merging) { boolean deletedRanges = false; if (block.getSeq().isEmpty()) { if (block.getSuccessors().size() > 1) { if (block.getPredecessors().size() > 1) { // ambiguous block throw new RuntimeException("ERROR: empty block with multiple predecessors and successors found"); } else if (!merging) { throw new RuntimeException("ERROR: empty block with multiple successors found"); } } Set<BasicBlock> setExits = new HashSet<>(graph.getLast().getPredecessors()); if (block.getPredecessorExceptions().isEmpty() && (!setExits.contains(block) || block.getPredecessors().size() == 1)) { if (setExits.contains(block)) { BasicBlock predecessor = block.getPredecessors().get(0); // FIXME: flag in the basic block if (predecessor.getSuccessors().size() != 1 || (!predecessor.getSeq().isEmpty() && predecessor.getSeq().getLastInstr().group == CodeConstants.GROUP_SWITCH)) { return false; } } Set<BasicBlock> predecessors = new HashSet<>(block.getPredecessors()); Set<BasicBlock> successors = new HashSet<>(block.getSuccessors()); // collecting common exception ranges of predecessors and successors Set<BasicBlock> setCommonExceptionHandlers = null; for (int i = 0; i < 2; ++i) { for (BasicBlock adjacent : i == 0 ? predecessors : successors) { if (setCommonExceptionHandlers == null) { setCommonExceptionHandlers = new HashSet<>(adjacent.getSuccessorExceptions()); } else { setCommonExceptionHandlers.retainAll(adjacent.getSuccessorExceptions()); } } } // check the block to be in each of the common ranges if (setCommonExceptionHandlers != null && !setCommonExceptionHandlers.isEmpty()) { for (BasicBlock handler : setCommonExceptionHandlers) { if (!block.getSuccessorExceptions().contains(handler)) { return false; } } } // remove ranges consisting of this one block List<ExceptionRangeCFG> lstRanges = graph.getExceptions(); for (int i = lstRanges.size() - 1; i >= 0; i--) { ExceptionRangeCFG range = lstRanges.get(i); List<BasicBlock> lst = range.getProtectedRange(); if (lst.size() == 1 && lst.get(0) == block) { if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) { block.removeSuccessorException(range.getHandler()); lstRanges.remove(i); deletedRanges = true; } else { return false; } } } // connect remaining nodes if (merging) { BasicBlock predecessor = block.getPredecessors().get(0); predecessor.removeSuccessor(block); List<BasicBlock> successorList = new ArrayList<>(block.getSuccessors()); for (BasicBlock successor : successorList) { block.removeSuccessor(successor); predecessor.addSuccessor(successor); } } else { for (BasicBlock predecessor : predecessors) { for (BasicBlock successor : successors) { predecessor.replaceSuccessor(block, successor); } } } // finally exit edges Set<BasicBlock> setFinallyExits = graph.getFinallyExits(); if (setFinallyExits.contains(block)) { setFinallyExits.remove(block); setFinallyExits.add(predecessors.iterator().next()); } // replace first if necessary if (graph.getFirst() == block) { if (successors.size() != 1) { throw new RuntimeException("multiple or no entry blocks!"); } else { graph.setFirst(successors.iterator().next()); } } // remove this block graph.removeBlock(block); if (deletedRanges) { removeDeadBlocks(graph); } } } return deletedRanges; }