int (@NotNull ControlFlow flow, final int offset, final int endOffset) { class MyVisitor extends InstructionClientVisitor<Integer> { private final boolean[] normalCompletion = new boolean[endOffset]; private final boolean[] returnCalled = new boolean[endOffset]; @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { boolean ret = nextOffset < endOffset && returnCalled[nextOffset]; boolean normal = nextOffset < endOffset && normalCompletion[nextOffset]; final PsiElement element = flow.getElement(offset); boolean goToReturn = instruction instanceof GoToInstruction && ((GoToInstruction)instruction).isReturn; if (goToReturn || isInsideReturnStatement(element)) { ret = true; } else if (instruction instanceof ConditionalThrowToInstruction) { final int throwOffset = ((ConditionalThrowToInstruction)instruction).offset; boolean normalWhenThrow = throwOffset < endOffset && normalCompletion[throwOffset]; boolean normalWhenNotThrow = offset == endOffset - 1 || normalCompletion[offset + 1]; normal = normalWhenThrow || normalWhenNotThrow; } else if (!(instruction instanceof ThrowToInstruction) && nextOffset >= endOffset) { normal = true; } returnCalled[offset] |= ret; normalCompletion[offset] |= normal; } @Override @NotNull public Integer getResult() { return (returnCalled[offset] ? RETURN_COMPLETION_REASON : 0) | (normalCompletion[offset] ? NORMAL_COMPLETION_REASON : 0); } } MyVisitor visitor = new MyVisitor(); depthFirstSearch(flow, visitor, offset, endOffset); return visitor.getResult().intValue(); }