in src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java [66:186]
private static boolean removeEmptyBlock(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;
}