private ASTRewrite doAddParam(CompilationUnit cu) {
    AST ast = cu.getAST();
    SimpleName node = fOriginalNode;

    BodyDeclaration decl = ASTResolving.findParentBodyDeclaration(node);
    if (decl instanceof MethodDeclaration) {
      MethodDeclaration methodDeclaration = (MethodDeclaration) decl;

      ASTRewrite rewrite = ASTRewrite.create(ast);

      ImportRewrite imports = createImportRewrite((CompilationUnit) decl.getRoot());
      ImportRewriteContext importRewriteContext =
          new ContextSensitiveImportRewriteContext(decl, imports);

      SingleVariableDeclaration newDecl = ast.newSingleVariableDeclaration();
      newDecl.setType(
          evaluateVariableType(
              ast, imports, importRewriteContext, methodDeclaration.resolveBinding()));
      newDecl.setName(ast.newSimpleName(node.getIdentifier()));

      ListRewrite listRewriter =
          rewrite.getListRewrite(decl, MethodDeclaration.PARAMETERS_PROPERTY);
      listRewriter.insertLast(newDecl, null);

      addLinkedPosition(rewrite.track(node), true, KEY_NAME);

      // add javadoc tag
      Javadoc javadoc = methodDeclaration.getJavadoc();
      if (javadoc != null) {
        HashSet<String> leadingNames = new HashSet<String>();
        for (Iterator<SingleVariableDeclaration> iter = methodDeclaration.parameters().iterator();
            iter.hasNext(); ) {
          SingleVariableDeclaration curr = iter.next();
          leadingNames.add(curr.getName().getIdentifier());
        }
        SimpleName newTagRef = ast.newSimpleName(node.getIdentifier());

        TagElement newTagElement = ast.newTagElement();
        newTagElement.setTagName(TagElement.TAG_PARAM);
        newTagElement.fragments().add(newTagRef);
        TextElement commentStart = ast.newTextElement();
        newTagElement.fragments().add(commentStart);

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

        ListRewrite tagsRewriter = rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY);
        JavadocTagsSubProcessor.insertTag(tagsRewriter, newTagElement, leadingNames);
      }

      addLinkedPosition(rewrite.track(newDecl.getType()), false, KEY_TYPE);
      addLinkedPosition(rewrite.track(newDecl.getName()), false, KEY_NAME);

      return rewrite;
    }
    return null;
  }
    private void insertAllMissingTypeTags(ASTRewrite rewriter, TypeDeclaration typeDecl) {
      AST ast = typeDecl.getAST();
      Javadoc javadoc = typeDecl.getJavadoc();
      ListRewrite tagsRewriter = rewriter.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY);

      List<TypeParameter> typeParams = typeDecl.typeParameters();
      for (int i = typeParams.size() - 1; i >= 0; i--) {
        TypeParameter decl = typeParams.get(i);
        String name = '<' + decl.getName().getIdentifier() + '>';
        if (findTag(javadoc, TagElement.TAG_PARAM, name) == null) {
          TagElement newTag = ast.newTagElement();
          newTag.setTagName(TagElement.TAG_PARAM);
          TextElement text = ast.newTextElement();
          text.setText(name);
          newTag.fragments().add(text);
          insertTabStop(rewriter, newTag.fragments(), "typeParam" + i); // $NON-NLS-1$
          insertTag(tagsRewriter, newTag, getPreviousTypeParamNames(typeParams, decl));
        }
      }
    }
    private void insertAllMissingMethodTags(ASTRewrite rewriter, MethodDeclaration methodDecl) {
      AST ast = methodDecl.getAST();
      Javadoc javadoc = methodDecl.getJavadoc();
      ListRewrite tagsRewriter = rewriter.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY);

      List<TypeParameter> typeParams = methodDecl.typeParameters();
      ASTNode root = methodDecl.getRoot();
      if (root instanceof CompilationUnit) {
        ITypeRoot typeRoot = ((CompilationUnit) root).getTypeRoot();
        if (typeRoot != null
            && !StubUtility.shouldGenerateMethodTypeParameterTags(typeRoot.getJavaProject()))
          typeParams = Collections.emptyList();
      }
      List<String> typeParamNames = new ArrayList<>();
      for (int i = typeParams.size() - 1; i >= 0; i--) {
        TypeParameter decl = typeParams.get(i);
        String name = '<' + decl.getName().getIdentifier() + '>';
        if (findTag(javadoc, TagElement.TAG_PARAM, name) == null) {
          TagElement newTag = ast.newTagElement();
          newTag.setTagName(TagElement.TAG_PARAM);
          TextElement text = ast.newTextElement();
          text.setText(name);
          newTag.fragments().add(text);
          insertTabStop(rewriter, newTag.fragments(), "typeParam" + i); // $NON-NLS-1$
          insertTag(tagsRewriter, newTag, getPreviousTypeParamNames(typeParams, decl));
        }
        typeParamNames.add(name);
      }
      List<SingleVariableDeclaration> params = methodDecl.parameters();
      for (int i = params.size() - 1; i >= 0; i--) {
        SingleVariableDeclaration decl = params.get(i);
        String name = decl.getName().getIdentifier();
        if (findTag(javadoc, TagElement.TAG_PARAM, name) == null) {
          TagElement newTag = ast.newTagElement();
          newTag.setTagName(TagElement.TAG_PARAM);
          newTag.fragments().add(ast.newSimpleName(name));
          insertTabStop(rewriter, newTag.fragments(), "methParam" + i); // $NON-NLS-1$
          Set<String> sameKindLeadingNames = getPreviousParamNames(params, decl);
          sameKindLeadingNames.addAll(typeParamNames);
          insertTag(tagsRewriter, newTag, sameKindLeadingNames);
        }
      }
      if (!methodDecl.isConstructor()) {
        Type type = methodDecl.getReturnType2();
        if (!type.isPrimitiveType()
            || (((PrimitiveType) type).getPrimitiveTypeCode() != PrimitiveType.VOID)) {
          if (findTag(javadoc, TagElement.TAG_RETURN, null) == null) {
            TagElement newTag = ast.newTagElement();
            newTag.setTagName(TagElement.TAG_RETURN);
            insertTabStop(rewriter, newTag.fragments(), "return"); // $NON-NLS-1$
            insertTag(tagsRewriter, newTag, null);
          }
        }
      }
      List<Type> thrownExceptions = methodDecl.thrownExceptionTypes();
      for (int i = thrownExceptions.size() - 1; i >= 0; i--) {
        Type exception = thrownExceptions.get(i);
        ITypeBinding binding = exception.resolveBinding();
        if (binding != null) {
          String name = binding.getName();
          if (findThrowsTag(javadoc, name) == null) {
            TagElement newTag = ast.newTagElement();
            newTag.setTagName(TagElement.TAG_THROWS);
            TextElement excNode = ast.newTextElement();
            excNode.setText(ASTNodes.getQualifiedTypeName(exception));
            newTag.fragments().add(excNode);
            insertTabStop(rewriter, newTag.fragments(), "exception" + i); // $NON-NLS-1$
            insertTag(tagsRewriter, newTag, getPreviousExceptionNames(thrownExceptions, exception));
          }
        }
      }
    }
    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());
      }
    }