boolean (@NotNull ControlFlow flow, final int startOffset, final int endOffset) { class MyVisitor extends InstructionClientVisitor<Boolean> { // false if control flow at this offset terminates abruptly private final boolean[] canCompleteNormally = new boolean[flow.getSize() + 1]; @Override public void visitConditionalGoToInstruction(ConditionalGoToInstruction instruction, int offset, int nextOffset) { checkInstruction(offset, nextOffset, false); } @Override public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { checkInstruction(offset, nextOffset, instruction.isReturn); } private void checkInstruction(int offset, int nextOffset, boolean isReturn) { if (offset > endOffset) return; if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean isNormal = nextOffset <= endOffset && !isReturn && (nextOffset == endOffset || canCompleteNormally[nextOffset]); if (isNormal && nextOffset == endOffset) { PsiElement element = flow.getElement(offset); if (element instanceof PsiBreakStatement) { PsiStatement exitedStatement = ((PsiBreakStatement)element).findExitedStatement(); if (exitedStatement == null || flow.getStartOffset(exitedStatement) < startOffset) { isNormal = false; } } else if (element instanceof PsiContinueStatement) { PsiStatement continuedStatement = ((PsiContinueStatement)element).findContinuedStatement(); if (continuedStatement == null || flow.getStartOffset(continuedStatement) < startOffset) { isNormal = false; } } } canCompleteNormally[offset] |= isNormal; } @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; int throwToOffset = instruction.offset; boolean isNormal; if (throwToOffset == nextOffset) { isNormal = throwToOffset <= endOffset && !isLeaf(nextOffset) && canCompleteNormally[nextOffset]; } else { isNormal = canCompleteNormally[nextOffset]; } canCompleteNormally[offset] |= isNormal; } @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; if (nextOffset <= endOffset) { boolean isNormal = !isLeaf(nextOffset) && canCompleteNormally[nextOffset]; canCompleteNormally[offset] |= isNormal; } } @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; if (nextOffset > endOffset && nextOffset != offset + 1) { return; } boolean isNormal = canCompleteNormally[nextOffset]; canCompleteNormally[offset] |= isNormal; } @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { checkInstruction(offset, nextOffset, false); } @Override @NotNull public Boolean getResult() { return canCompleteNormally[startOffset]; } } final MyVisitor visitor = new MyVisitor(); depthFirstSearch(flow, visitor, startOffset, endOffset); return visitor.getResult().booleanValue(); }