private ITypeBinding[] computeTypeVariables(ITypeBinding[] bindings) {
   Selection selection = getSelection();
   Set<ITypeBinding> result = new HashSet<>();
   // first remove all type variables that come from outside of the method
   // or are covered by the selection
   CompilationUnit compilationUnit = (CompilationUnit) fEnclosingBodyDeclaration.getRoot();
   for (int i = 0; i < bindings.length; i++) {
     ASTNode decl = compilationUnit.findDeclaringNode(bindings[i]);
     if (decl == null
         || (!selection.covers(decl) && decl.getParent() instanceof MethodDeclaration))
       result.add(bindings[i]);
   }
   // all all type variables which are needed since a local variable uses it
   for (int i = 0; i < fArguments.length; i++) {
     IVariableBinding arg = fArguments[i];
     ITypeBinding type = arg.getType();
     if (type != null && type.isTypeVariable()) {
       ASTNode decl = compilationUnit.findDeclaringNode(type);
       if (decl == null
           || (!selection.covers(decl) && decl.getParent() instanceof MethodDeclaration))
         result.add(type);
     }
   }
   return result.toArray(new ITypeBinding[result.size()]);
 }
 private IVariableBinding[] removeSelectedDeclarations(IVariableBinding[] bindings) {
   List<IVariableBinding> result = new ArrayList<>(bindings.length);
   Selection selection = getSelection();
   for (int i = 0; i < bindings.length; i++) {
     ASTNode decl =
         ((CompilationUnit) fEnclosingBodyDeclaration.getRoot()).findDeclaringNode(bindings[i]);
     if (!selection.covers(decl)) result.add(bindings[i]);
   }
   return result.toArray(new IVariableBinding[result.size()]);
 }
 @Override
 public boolean visit(MethodDeclaration node) {
   Block body = node.getBody();
   if (body == null) return false;
   Selection selection = getSelection();
   int nodeStart = body.getStartPosition();
   int nodeExclusiveEnd = nodeStart + body.getLength();
   // if selection node inside of the method body ignore method
   if (!(nodeStart < selection.getOffset() && selection.getExclusiveEnd() < nodeExclusiveEnd))
     return false;
   return super.visit(node);
 }
 public static SurroundWithTryCatchRefactoring create(
     ICompilationUnit cu, ITextSelection selection, boolean isMultiCatch) {
   return new SurroundWithTryCatchRefactoring(
       cu,
       Selection.createFromStartLength(selection.getOffset(), selection.getLength()),
       isMultiCatch);
 }
  /* non Java-doc
   * @see IRefactoring#createChange(IProgressMonitor)
   */
  @Override
  public Change createChange(IProgressMonitor pm) throws CoreException {
    final String NN = ""; // $NON-NLS-1$
    if (pm == null) pm = new NullProgressMonitor();
    pm.beginTask(NN, 2);
    try {
      final CompilationUnitChange result = new CompilationUnitChange(getName(), fCUnit);
      if (fLeaveDirty) result.setSaveMode(TextFileChange.LEAVE_DIRTY);
      MultiTextEdit root = new MultiTextEdit();
      result.setEdit(root);
      fRewriter = ASTRewrite.create(fAnalyzer.getEnclosingBodyDeclaration().getAST());
      fRewriter.setTargetSourceRangeComputer(
          new SelectionAwareSourceRangeComputer(
              fAnalyzer.getSelectedNodes(),
              fCUnit.getBuffer(),
              fSelection.getOffset(),
              fSelection.getLength()));
      fImportRewrite = StubUtility.createImportRewrite(fRootNode, true);

      fLinkedProposalModel = new LinkedProposalModel();

      fScope =
          CodeScopeBuilder.perform(fAnalyzer.getEnclosingBodyDeclaration(), fSelection)
              .findScope(fSelection.getOffset(), fSelection.getLength());
      fScope.setCursor(fSelection.getOffset());

      fSelectedNodes = fAnalyzer.getSelectedNodes();

      createTryCatchStatement(fCUnit.getBuffer(), fCUnit.findRecommendedLineSeparator());

      if (fImportRewrite.hasRecordedChanges()) {
        TextEdit edit = fImportRewrite.rewriteImports(null);
        root.addChild(edit);
        result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {edit}));
      }
      TextEdit change = fRewriter.rewriteAST();
      root.addChild(change);
      result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {change}));
      return result;
    } finally {
      pm.done();
    }
  }
  @Override
  public boolean visit(LambdaExpression node) {
    Selection selection = getSelection();
    int selectionStart = selection.getOffset();
    int selectionExclusiveEnd = selection.getExclusiveEnd();
    int lambdaStart = node.getStartPosition();
    int lambdaExclusiveEnd = lambdaStart + node.getLength();
    ASTNode body = node.getBody();
    int bodyStart = body.getStartPosition();
    int bodyExclusiveEnd = bodyStart + body.getLength();

    boolean isValidSelection = false;
    if ((body instanceof Block)
        && (bodyStart < selectionStart && selectionExclusiveEnd <= bodyExclusiveEnd)) {
      // if selection is inside lambda body's block
      isValidSelection = true;
    } else if (body instanceof Expression) {
      try {
        TokenScanner scanner = new TokenScanner(fCUnit);
        int arrowExclusiveEnd =
            scanner.getTokenEndOffset(ITerminalSymbols.TokenNameARROW, lambdaStart);
        if (selectionStart >= arrowExclusiveEnd) {
          isValidSelection = true;
        }
      } catch (CoreException e) {
        // ignore
      }
    }
    if (selectionStart <= lambdaStart && selectionExclusiveEnd >= lambdaExclusiveEnd) {
      // if selection covers the lambda node
      isValidSelection = true;
    }

    if (!isValidSelection) {
      return false;
    }
    return super.visit(node);
  }
  private void computeOutput(RefactoringStatus status) {
    // First find all writes inside the selection.
    FlowContext flowContext = new FlowContext(0, fMaxVariableId + 1);
    flowContext.setConsiderAccessMode(true);
    flowContext.setComputeMode(FlowContext.RETURN_VALUES);
    FlowInfo returnInfo = new InOutFlowAnalyzer(flowContext).perform(getSelectedNodes());
    IVariableBinding[] returnValues =
        returnInfo.get(flowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN);

    // Compute a selection that exactly covers the selected nodes
    IRegion region = getSelectedNodeRange();
    Selection selection = Selection.createFromStartLength(region.getOffset(), region.getLength());

    List<IVariableBinding> localReads = new ArrayList<>();
    flowContext.setComputeMode(FlowContext.ARGUMENTS);
    FlowInfo argInfo =
        new InputFlowAnalyzer(flowContext, selection, true).perform(fEnclosingBodyDeclaration);
    IVariableBinding[] reads =
        argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.UNKNOWN);
    outer:
    for (int i = 0; i < returnValues.length && localReads.size() < returnValues.length; i++) {
      IVariableBinding binding = returnValues[i];
      for (int x = 0; x < reads.length; x++) {
        if (reads[x] == binding) {
          localReads.add(binding);
          fReturnValue = binding;
          continue outer;
        }
      }
    }
    switch (localReads.size()) {
      case 0:
        fReturnValue = null;
        break;
      case 1:
        break;
      default:
        fReturnValue = null;
        StringBuffer affectedLocals = new StringBuffer();
        for (int i = 0; i < localReads.size(); i++) {
          IVariableBinding binding = localReads.get(i);
          String bindingName =
              BindingLabelProvider.getBindingLabel(
                  binding,
                  BindingLabelProvider.DEFAULT_TEXTFLAGS | JavaElementLabels.F_PRE_TYPE_SIGNATURE);
          affectedLocals.append(bindingName);
          if (i != localReads.size() - 1) {
            affectedLocals.append('\n');
          }
        }
        String message =
            MessageFormat.format(
                RefactoringCoreMessages.ExtractMethodAnalyzer_assignments_to_local,
                new Object[] {affectedLocals.toString()});
        status.addFatalError(message, JavaStatusContext.create(fCUnit, getSelection()));
        return;
    }
    List<IVariableBinding> callerLocals = new ArrayList<>(5);
    FlowInfo localInfo =
        new InputFlowAnalyzer(flowContext, selection, false).perform(fEnclosingBodyDeclaration);
    IVariableBinding[] writes =
        localInfo.get(flowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN);
    for (int i = 0; i < writes.length; i++) {
      IVariableBinding write = writes[i];
      if (getSelection().covers(ASTNodes.findDeclaration(write, fEnclosingBodyDeclaration)))
        callerLocals.add(write);
    }
    fCallerLocals = callerLocals.toArray(new IVariableBinding[callerLocals.size()]);
    if (fReturnValue != null
        && getSelection().covers(ASTNodes.findDeclaration(fReturnValue, fEnclosingBodyDeclaration)))
      fReturnLocal = fReturnValue;
  }
  private void createTryCatchStatement(org.eclipse.jdt.core.IBuffer buffer, String lineDelimiter)
      throws CoreException {
    List<Statement> result = new ArrayList<>(1);
    TryStatement tryStatement = getAST().newTryStatement();
    ITypeBinding[] exceptions = fAnalyzer.getExceptions();
    ImportRewriteContext context =
        new ContextSensitiveImportRewriteContext(
            fAnalyzer.getEnclosingBodyDeclaration(), fImportRewrite);

    if (!fIsMultiCatch) {
      for (int i = 0; i < exceptions.length; i++) {
        ITypeBinding exception = exceptions[i];
        CatchClause catchClause = getAST().newCatchClause();
        tryStatement.catchClauses().add(catchClause);
        SingleVariableDeclaration decl = getAST().newSingleVariableDeclaration();
        String varName = StubUtility.getExceptionVariableName(fCUnit.getJavaProject());

        String name = fScope.createName(varName, false);
        decl.setName(getAST().newSimpleName(name));
        Type type = fImportRewrite.addImport(exception, getAST(), context);
        decl.setType(type);
        catchClause.setException(decl);
        Statement st = getCatchBody(ASTNodes.getQualifiedTypeName(type), name, lineDelimiter);
        if (st != null) {
          catchClause.getBody().statements().add(st);
        }
        fLinkedProposalModel
            .getPositionGroup(GROUP_EXC_TYPE + i, true)
            .addPosition(fRewriter.track(decl.getType()), i == 0);
        fLinkedProposalModel
            .getPositionGroup(GROUP_EXC_NAME + i, true)
            .addPosition(fRewriter.track(decl.getName()), false);
      }
    } else {
      List<ITypeBinding> filteredExceptions = filterSubtypeExceptions(exceptions);
      CatchClause catchClause = getAST().newCatchClause();
      SingleVariableDeclaration decl = getAST().newSingleVariableDeclaration();
      String varName = StubUtility.getExceptionVariableName(fCUnit.getJavaProject());
      String name = fScope.createName(varName, false);
      decl.setName(getAST().newSimpleName(name));

      UnionType unionType = getAST().newUnionType();
      List<Type> types = unionType.types();
      int i = 0;
      for (ITypeBinding exception : filteredExceptions) {
        Type type = fImportRewrite.addImport(exception, getAST(), context);
        types.add(type);
        fLinkedProposalModel
            .getPositionGroup(GROUP_EXC_TYPE + i, true)
            .addPosition(fRewriter.track(type), i == 0);
        i++;
      }

      decl.setType(unionType);
      catchClause.setException(decl);
      fLinkedProposalModel
          .getPositionGroup(GROUP_EXC_NAME + 0, true)
          .addPosition(fRewriter.track(decl.getName()), false);
      Statement st = getCatchBody("Exception", name, lineDelimiter); // $NON-NLS-1$
      if (st != null) {
        catchClause.getBody().statements().add(st);
      }
      tryStatement.catchClauses().add(catchClause);
    }
    List<ASTNode> variableDeclarations = getSpecialVariableDeclarationStatements();
    ListRewrite statements =
        fRewriter.getListRewrite(tryStatement.getBody(), Block.STATEMENTS_PROPERTY);
    boolean selectedNodeRemoved = false;
    ASTNode expressionStatement = null;
    for (int i = 0; i < fSelectedNodes.length; i++) {
      ASTNode node = fSelectedNodes[i];
      if (node instanceof VariableDeclarationStatement && variableDeclarations.contains(node)) {
        AST ast = getAST();
        VariableDeclarationStatement statement = (VariableDeclarationStatement) node;
        // Create a copy and remove the initializer
        VariableDeclarationStatement copy =
            (VariableDeclarationStatement) ASTNode.copySubtree(ast, statement);
        List<IExtendedModifier> modifiers = copy.modifiers();
        for (Iterator<IExtendedModifier> iter = modifiers.iterator(); iter.hasNext(); ) {
          IExtendedModifier modifier = iter.next();
          if (modifier.isModifier()
              && Modifier.isFinal(((Modifier) modifier).getKeyword().toFlagValue())) {
            iter.remove();
          }
        }
        List<VariableDeclarationFragment> fragments = copy.fragments();
        for (Iterator<VariableDeclarationFragment> iter = fragments.iterator(); iter.hasNext(); ) {
          VariableDeclarationFragment fragment = iter.next();
          fragment.setInitializer(null);
        }
        CompilationUnit root = (CompilationUnit) statement.getRoot();
        int extendedStart = root.getExtendedStartPosition(statement);
        // we have a leading comment and the comment is covered by the selection
        if (extendedStart != statement.getStartPosition()
            && extendedStart >= fSelection.getOffset()) {
          String commentToken =
              buffer.getText(extendedStart, statement.getStartPosition() - extendedStart);
          commentToken = Strings.trimTrailingTabsAndSpaces(commentToken);
          Type type = statement.getType();
          String typeName = buffer.getText(type.getStartPosition(), type.getLength());
          copy.setType(
              (Type)
                  fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
        }
        result.add(copy);
        // convert the fragments into expression statements
        fragments = statement.fragments();
        if (!fragments.isEmpty()) {
          List<ExpressionStatement> newExpressionStatements = new ArrayList<>();
          for (Iterator<VariableDeclarationFragment> iter = fragments.iterator();
              iter.hasNext(); ) {
            VariableDeclarationFragment fragment = iter.next();
            Expression initializer = fragment.getInitializer();
            if (initializer != null) {
              Assignment assignment = ast.newAssignment();
              assignment.setLeftHandSide(
                  (Expression) fRewriter.createCopyTarget(fragment.getName()));
              assignment.setRightHandSide((Expression) fRewriter.createCopyTarget(initializer));
              newExpressionStatements.add(ast.newExpressionStatement(assignment));
            }
          }
          if (!newExpressionStatements.isEmpty()) {
            if (fSelectedNodes.length == 1) {
              expressionStatement =
                  fRewriter.createGroupNode(
                      newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()]));
            } else {
              fRewriter.replace(
                  statement,
                  fRewriter.createGroupNode(
                      newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])),
                  null);
            }
          } else {
            fRewriter.remove(statement, null);
            selectedNodeRemoved = true;
          }
        } else {
          fRewriter.remove(statement, null);
          selectedNodeRemoved = true;
        }
      }
    }
    result.add(tryStatement);
    ASTNode replacementNode;
    if (result.size() == 1) {
      replacementNode = result.get(0);
    } else {
      replacementNode = fRewriter.createGroupNode(result.toArray(new ASTNode[result.size()]));
    }
    if (fSelectedNodes.length == 1) {
      ASTNode selectedNode = fSelectedNodes[0];

      if (selectedNode instanceof MethodReference) {
        MethodReference methodReference = (MethodReference) selectedNode;
        IMethodBinding functionalMethod =
            QuickAssistProcessor.getFunctionalMethodForMethodReference(methodReference);
        // functionalMethod is non-null and non-generic. See
        // ExceptionAnalyzer.handleMethodReference(MethodReference node).
        Assert.isTrue(functionalMethod != null && !functionalMethod.isGenericMethod());
        LambdaExpression lambda =
            QuickAssistProcessor.convertMethodRefernceToLambda(
                methodReference, functionalMethod, fRootNode, fRewriter, null, true);
        ASTNode statementInBlock = (ASTNode) ((Block) lambda.getBody()).statements().get(0);
        fRewriter.replace(statementInBlock, replacementNode, null);
        statements.insertLast(statementInBlock, null);
        return;
      }

      LambdaExpression enclosingLambda = ASTResolving.findEnclosingLambdaExpression(selectedNode);
      if (enclosingLambda != null
          && selectedNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY
          && enclosingLambda.resolveMethodBinding() != null) {
        QuickAssistProcessor.changeLambdaBodyToBlock(enclosingLambda, getAST(), fRewriter);
        Block blockBody = (Block) fRewriter.get(enclosingLambda, LambdaExpression.BODY_PROPERTY);
        ASTNode statementInBlock = (ASTNode) blockBody.statements().get(0);
        fRewriter.replace(statementInBlock, replacementNode, null);
        statements.insertLast(statementInBlock, null);
        return;
      }

      if (expressionStatement != null) {
        statements.insertLast(expressionStatement, null);
      } else {
        if (!selectedNodeRemoved)
          statements.insertLast(fRewriter.createMoveTarget(selectedNode), null);
      }
      fRewriter.replace(selectedNode, replacementNode, null);
    } else {
      ListRewrite source =
          fRewriter.getListRewrite(
              fSelectedNodes[0].getParent(),
              (ChildListPropertyDescriptor) fSelectedNodes[0].getLocationInParent());
      ASTNode toMove =
          source.createMoveTarget(
              fSelectedNodes[0], fSelectedNodes[fSelectedNodes.length - 1], replacementNode, null);
      statements.insertLast(toMove, null);
    }
  }
 public static SurroundWithTryCatchRefactoring create(
     ICompilationUnit cu, int offset, int length, boolean isMultiCatch) {
   return new SurroundWithTryCatchRefactoring(
       cu, Selection.createFromStartLength(offset, length), isMultiCatch);
 }