private boolean nodesHaveSameParentAndLocation(List<? extends ASTNode> nodes) {
   if (nodes.isEmpty()) {
     return true;
   }
   final ASTNode firstNode = nodes.get(0);
   final ASTNode parent = firstNode.getParent();
   final StructuralPropertyDescriptor locInParent = firstNode.getLocationInParent();
   for (ASTNode node : nodes) {
     if (!equal(node.getParent(), parent) || !equal(node.getLocationInParent(), locInParent)) {
       return false;
     }
   }
   return true;
 }
  public static void getMissingJavadocTagProposals(
      IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
    ASTNode node = problem.getCoveringNode(context.getASTRoot());
    if (node == null) {
      return;
    }
    node = ASTNodes.getNormalizedNode(node);

    BodyDeclaration bodyDeclaration = ASTResolving.findParentBodyDeclaration(node);
    if (bodyDeclaration == null) {
      return;
    }
    Javadoc javadoc = bodyDeclaration.getJavadoc();
    if (javadoc == null) {
      return;
    }

    String label;
    StructuralPropertyDescriptor location = node.getLocationInParent();
    if (location == SingleVariableDeclaration.NAME_PROPERTY) {
      label = CorrectionMessages.JavadocTagsSubProcessor_addjavadoc_paramtag_description;
      if (node.getParent().getLocationInParent() != MethodDeclaration.PARAMETERS_PROPERTY) {
        return; // paranoia checks
      }
    } else if (location == TypeParameter.NAME_PROPERTY) {
      label = CorrectionMessages.JavadocTagsSubProcessor_addjavadoc_paramtag_description;
      StructuralPropertyDescriptor parentLocation = node.getParent().getLocationInParent();
      if (parentLocation != MethodDeclaration.TYPE_PARAMETERS_PROPERTY
          && parentLocation != TypeDeclaration.TYPE_PARAMETERS_PROPERTY) {
        return; // paranoia checks
      }
    } else if (location == MethodDeclaration.RETURN_TYPE2_PROPERTY) {
      label = CorrectionMessages.JavadocTagsSubProcessor_addjavadoc_returntag_description;
    } else if (location == MethodDeclaration.THROWN_EXCEPTION_TYPES_PROPERTY) {
      label = CorrectionMessages.JavadocTagsSubProcessor_addjavadoc_throwstag_description;
    } else {
      return;
    }
    ASTRewriteCorrectionProposal proposal =
        new AddMissingJavadocTagProposal(
            label,
            context.getCompilationUnit(),
            bodyDeclaration,
            node,
            IProposalRelevance.ADD_MISSING_TAG);
    proposals.add(proposal);

    String label2 = CorrectionMessages.JavadocTagsSubProcessor_addjavadoc_allmissing_description;
    ASTRewriteCorrectionProposal addAllMissing =
        new AddAllMissingJavadocTagsProposal(
            label2,
            context.getCompilationUnit(),
            bodyDeclaration,
            IProposalRelevance.ADD_ALL_MISSING_TAGS);
    proposals.add(addAllMissing);
  }
 /*
  * Check if the node is in a block. We don't want to update declarations
  */
 private static boolean isNotInBlock(ASTNode parent) {
   ASTNode statement = parent.getParent();
   boolean isStatement = statement.getNodeType() != ASTNode.EXPRESSION_STATEMENT;
   ASTNode block = statement.getParent();
   boolean isBlock =
       block.getNodeType() == ASTNode.BLOCK || block.getNodeType() == ASTNode.SWITCH_STATEMENT;
   boolean isControlStatemenBody =
       ASTNodes.isControlStatementBody(statement.getLocationInParent());
   return isStatement || !(isBlock || isControlStatemenBody);
 }
  /**
   * Replace an AST node with another one by substituting the corresponding child of its parent.
   *
   * @param node The node to be replace.
   * @param newNode The new node.
   */
  public static void replaceNode(ASTNode node, ASTNode newNode) {
    ASTNode parent = node.getParent();
    StructuralPropertyDescriptor location = node.getLocationInParent();

    if (location.isChildProperty()) {
      parent.setStructuralProperty(location, newNode);
    } else {
      List<ASTNode> properties = (List<ASTNode>) parent.getStructuralProperty(location);
      int position = properties.indexOf(node);
      properties.set(position, newNode);
    }
  }
 private static ASTNode getDeclaringNode(ASTNode selectedNode) {
   ASTNode declaringNode = null;
   if (selectedNode instanceof MethodDeclaration) {
     declaringNode = selectedNode;
   } else if (selectedNode instanceof SimpleName) {
     StructuralPropertyDescriptor locationInParent = selectedNode.getLocationInParent();
     if (locationInParent == MethodDeclaration.NAME_PROPERTY
         || locationInParent == TypeDeclaration.NAME_PROPERTY) {
       declaringNode = selectedNode.getParent();
     } else if (locationInParent == VariableDeclarationFragment.NAME_PROPERTY) {
       declaringNode = selectedNode.getParent().getParent();
     }
   }
   return declaringNode;
 }
 private boolean validSelectedNodes() {
   ASTNode[] nodes = getSelectedNodes();
   for (int i = 0; i < nodes.length; i++) {
     ASTNode node = nodes[i];
     boolean isValidNode = node instanceof Statement;
     if (fSurroundWithTryCatch) { // allow method reference and lambda's expression body also
       isValidNode =
           isValidNode
               || node instanceof MethodReference
               || node.getLocationInParent() == LambdaExpression.BODY_PROPERTY;
     }
     if (!isValidNode) return false;
   }
   return true;
 }
 private void checkExpression(RefactoringStatus status) {
   ASTNode[] nodes = getSelectedNodes();
   if (nodes != null && nodes.length == 1) {
     ASTNode node = nodes[0];
     if (node instanceof Type) {
       status.addFatalError(
           RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_type_reference,
           JavaStatusContext.create(fCUnit, node));
     } else if (node.getLocationInParent() == SwitchCase.EXPRESSION_PROPERTY) {
       status.addFatalError(
           RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_switch_case,
           JavaStatusContext.create(fCUnit, node));
     } else if (node instanceof Annotation || ASTNodes.getParent(node, Annotation.class) != null) {
       status.addFatalError(
           RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_from_annotation,
           JavaStatusContext.create(fCUnit, node));
     }
   }
 }
 @Override
 public void endVisit(CompilationUnit node) {
   postProcessSelectedNodes(internalGetSelectedNodes());
   ASTNode enclosingNode = null;
   superCall:
   {
     if (getStatus().hasFatalError()) break superCall;
     if (!hasSelectedNodes()) {
       ASTNode coveringNode = getLastCoveringNode();
       if (coveringNode instanceof Block) {
         Block block = (Block) coveringNode;
         Message[] messages = ASTNodes.getMessages(block, ASTNodes.NODE_ONLY);
         if (messages.length > 0) {
           invalidSelection(
               RefactoringCoreMessages.SurroundWithTryCatchAnalyzer_compile_errors,
               JavaStatusContext.create(getCompilationUnit(), block));
           break superCall;
         }
       }
       invalidSelection(RefactoringCoreMessages.SurroundWithTryCatchAnalyzer_doesNotCover);
       break superCall;
     }
     enclosingNode = getEnclosingNode(getFirstSelectedNode());
     boolean isValidEnclosingNode =
         enclosingNode instanceof MethodDeclaration || enclosingNode instanceof Initializer;
     if (fSurroundWithTryCatch) {
       isValidEnclosingNode =
           isValidEnclosingNode
               || enclosingNode instanceof MethodReference
               || enclosingNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY;
     }
     if (!isValidEnclosingNode) {
       invalidSelection(RefactoringCoreMessages.SurroundWithTryCatchAnalyzer_doesNotContain);
       break superCall;
     }
     if (!validSelectedNodes()) {
       invalidSelection(RefactoringCoreMessages.SurroundWithTryCatchAnalyzer_onlyStatements);
     }
     fLocals = LocalDeclarationAnalyzer.perform(enclosingNode, getSelection());
   }
   super.endVisit(node);
 }
    private void insertMissingJavadocTag(
        ASTRewrite rewrite, ASTNode missingNode, BodyDeclaration bodyDecl) {
      AST ast = bodyDecl.getAST();
      Javadoc javadoc = bodyDecl.getJavadoc();
      if (javadoc == null) {
        javadoc = ast.newJavadoc();
        rewrite.set(bodyDecl, bodyDecl.getJavadocProperty(), javadoc, null);
      }

      ListRewrite tagsRewriter = rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY);

      StructuralPropertyDescriptor location = missingNode.getLocationInParent();
      TagElement newTag;
      if (location == SingleVariableDeclaration.NAME_PROPERTY) {
        // normal parameter
        SingleVariableDeclaration decl = (SingleVariableDeclaration) missingNode.getParent();

        String name = ((SimpleName) missingNode).getIdentifier();
        newTag = ast.newTagElement();
        newTag.setTagName(TagElement.TAG_PARAM);
        newTag.fragments().add(ast.newSimpleName(name));

        MethodDeclaration methodDeclaration = (MethodDeclaration) bodyDecl;
        List<SingleVariableDeclaration> params = methodDeclaration.parameters();

        Set<String> sameKindLeadingNames = getPreviousParamNames(params, decl);

        List<TypeParameter> typeParams = methodDeclaration.typeParameters();
        for (int i = 0; i < typeParams.size(); i++) {
          String curr = '<' + typeParams.get(i).getName().getIdentifier() + '>';
          sameKindLeadingNames.add(curr);
        }
        insertTag(tagsRewriter, newTag, sameKindLeadingNames);
      } else if (location == TypeParameter.NAME_PROPERTY) {
        // type parameter
        TypeParameter typeParam = (TypeParameter) missingNode.getParent();

        String name = '<' + ((SimpleName) missingNode).getIdentifier() + '>';
        newTag = ast.newTagElement();
        newTag.setTagName(TagElement.TAG_PARAM);
        TextElement text = ast.newTextElement();
        text.setText(name);
        newTag.fragments().add(text);
        List<TypeParameter> params;
        if (bodyDecl instanceof TypeDeclaration) {
          params = ((TypeDeclaration) bodyDecl).typeParameters();
        } else {
          params = ((MethodDeclaration) bodyDecl).typeParameters();
        }
        insertTag(tagsRewriter, newTag, getPreviousTypeParamNames(params, typeParam));
      } else if (location == MethodDeclaration.RETURN_TYPE2_PROPERTY) {
        newTag = ast.newTagElement();
        newTag.setTagName(TagElement.TAG_RETURN);
        insertTag(tagsRewriter, newTag, null);
      } else if (location == MethodDeclaration.THROWN_EXCEPTION_TYPES_PROPERTY) {
        newTag = ast.newTagElement();
        newTag.setTagName(TagElement.TAG_THROWS);
        TextElement excNode = ast.newTextElement();
        excNode.setText(ASTNodes.getQualifiedTypeName((Type) missingNode));
        newTag.fragments().add(excNode);
        List<Type> exceptions = ((MethodDeclaration) bodyDecl).thrownExceptionTypes();
        insertTag(tagsRewriter, newTag, getPreviousExceptionNames(exceptions, missingNode));
      } else {
        Assert.isTrue(
            false, "AddMissingJavadocTagProposal: unexpected node location"); // $NON-NLS-1$
        return;
      }

      TextElement textElement = ast.newTextElement();
      textElement.setText(""); // $NON-NLS-1$
      newTag.fragments().add(textElement);

      addLinkedPosition(rewrite.track(textElement), false, "comment_start"); // $NON-NLS-1$

      if (bodyDecl.getJavadoc() == null) {
        // otherwise the linked position spans over a line delimiter
        newTag.fragments().add(ast.newTextElement());
      }
    }
  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);
    }
  }