boolean (@NotNull GrControlFlowOwner block, @NotNull final ReturnStatus returnStatus) { if (returnStatus == ReturnStatus.shouldNotReturnValue) { return false; } final Ref<Boolean> alwaysHaveReturn = new Ref<>(true); final Ref<Boolean> sometimesHaveReturn = new Ref<>(false); ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() { @Override public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { //don't modify sometimesHaveReturn in this case: // def foo() { // if (cond) throw new RuntimeException() // } if (instruction instanceof ThrowingInstruction) { if (returnStatus == ReturnStatus.mustReturnValue) { sometimesHaveReturn.set(true); } return true; } if (instruction instanceof MaybeReturnInstruction && ((MaybeReturnInstruction)instruction).mayReturnValue()) { sometimesHaveReturn.set(true); return true; } if (instruction.getElement() instanceof GrReturnStatement && returnValue != null) { sometimesHaveReturn.set(true); return true; } if (!(instruction instanceof MaybeYieldInstruction) && !(instruction.getElement() instanceof GrYieldStatement)) { alwaysHaveReturn.set(false); } return true; } }); if (returnStatus == ReturnStatus.mustReturnValue && !sometimesHaveReturn.get()) { return true; } return sometimesHaveReturn.get() && !alwaysHaveReturn.get(); }