public PsiStatement getExitStatementCopy(
      PsiElement returnStatement, final PsiElement[] elements) {
    PsiStatement exitStatementCopy = null;
    // replace all exit-statements such as break's or continue's with appropriate return
    for (PsiStatement exitStatement : myExitStatements) {
      if (exitStatement instanceof PsiReturnStatement) {
        if (!myGenerateConditionalExit) continue;
      } else if (exitStatement instanceof PsiBreakStatement) {
        PsiStatement statement = ((PsiBreakStatement) exitStatement).findExitedStatement();
        if (statement == null) continue;
        int startOffset = myControlFlow.getStartOffset(statement);
        int endOffset = myControlFlow.getEndOffset(statement);
        if (myFlowStart <= startOffset && endOffset <= myFlowEnd) continue;
      } else if (exitStatement instanceof PsiContinueStatement) {
        PsiStatement statement = ((PsiContinueStatement) exitStatement).findContinuedStatement();
        if (statement == null) continue;
        int startOffset = myControlFlow.getStartOffset(statement);
        int endOffset = myControlFlow.getEndOffset(statement);
        if (myFlowStart <= startOffset && endOffset <= myFlowEnd) continue;
      } else {
        LOG.error(String.valueOf(exitStatement));
        continue;
      }

      int index = -1;
      for (int j = 0; j < elements.length; j++) {
        if (exitStatement.equals(elements[j])) {
          index = j;
          break;
        }
      }
      if (exitStatementCopy == null) {
        if (needExitStatement(exitStatement)) {
          exitStatementCopy = (PsiStatement) exitStatement.copy();
        }
      }
      PsiElement result = exitStatement.replace(returnStatement);
      if (index >= 0) {
        elements[index] = result;
      }
    }
    return exitStatementCopy;
  }
 private boolean needExitStatement(final PsiStatement exitStatement) {
   if (exitStatement instanceof PsiContinueStatement) {
     // IDEADEV-11748
     PsiStatement statement = ((PsiContinueStatement) exitStatement).findContinuedStatement();
     if (statement == null) return true;
     if (statement instanceof PsiLoopStatement)
       statement = ((PsiLoopStatement) statement).getBody();
     int endOffset = myControlFlow.getEndOffset(statement);
     return endOffset > myFlowEnd;
   }
   return true;
 }
  public ControlFlowWrapper(Project project, PsiElement codeFragment, PsiElement[] elements)
      throws PrepareFailedException {
    try {
      myControlFlow =
          ControlFlowFactory.getInstance(project)
              .getControlFlow(
                  codeFragment, new LocalsControlFlowPolicy(codeFragment), false, false);
    } catch (AnalysisCanceledException e) {
      throw new PrepareFailedException(
          RefactoringBundle.message("extract.method.control.flow.analysis.failed"),
          e.getErrorElement());
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug(myControlFlow.toString());
    }

    int flowStart = -1;
    int index = 0;
    while (index < elements.length) {
      flowStart = myControlFlow.getStartOffset(elements[index]);
      if (flowStart >= 0) break;
      index++;
    }
    int flowEnd;
    if (flowStart < 0) {
      // no executable code
      flowStart = 0;
      flowEnd = 0;
    } else {
      index = elements.length - 1;
      while (true) {
        flowEnd = myControlFlow.getEndOffset(elements[index]);
        if (flowEnd >= 0) break;
        index--;
      }
    }
    myFlowStart = flowStart;
    myFlowEnd = flowEnd;
    if (LOG.isDebugEnabled()) {
      LOG.debug("start offset:" + myFlowStart);
      LOG.debug("end offset:" + myFlowEnd);
    }
  }
 @Override
 public boolean isVoidCompatible() {
   final PsiElement body = getBody();
   if (body != null) {
     try {
       ControlFlow controlFlow =
           ControlFlowFactory.getInstance(getProject())
               .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
       int startOffset = controlFlow.getStartOffset(body);
       int endOffset = controlFlow.getEndOffset(body);
       return startOffset != -1
           && endOffset != -1
           && !ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset);
     } catch (AnalysisCanceledException e) {
       return true;
     }
   }
   return true;
 }
  public Collection<PsiStatement> prepareExitStatements(
      final @NotNull PsiElement[] elements, final @NotNull PsiElement enclosingCodeFragment)
      throws ExitStatementsNotSameException {
    myExitPoints = new IntArrayList();
    myExitStatements =
        ControlFlowUtil.findExitPointsAndStatements(
            myControlFlow,
            myFlowStart,
            myFlowEnd,
            myExitPoints,
            ControlFlowUtil.DEFAULT_EXIT_STATEMENTS_CLASSES);
    if (ControlFlowUtil.hasObservableThrowExitPoints(
        myControlFlow, myFlowStart, myFlowEnd, elements, enclosingCodeFragment)) {
      throw new ExitStatementsNotSameException();
    }
    if (LOG.isDebugEnabled()) {
      LOG.debug("exit points:");
      for (int i = 0; i < myExitPoints.size(); i++) {
        LOG.debug("  " + myExitPoints.get(i));
      }
      LOG.debug("exit statements:");
      for (PsiStatement exitStatement : myExitStatements) {
        LOG.debug("  " + exitStatement);
      }
    }
    if (myExitPoints.isEmpty()) {
      // if the fragment never exits assume as if it exits in the end
      myExitPoints.add(myControlFlow.getEndOffset(elements[elements.length - 1]));
    }

    if (myExitPoints.size() != 1) {
      myGenerateConditionalExit = true;
      areExitStatementsTheSame();
    }
    return myExitStatements;
  }