public String getExpectedText(PsiBuilder builder) {
   int position = builder.rawTokenIndex();
   StringBuilder sb = new StringBuilder();
   if (addExpected(sb, position, true)) {
     sb.append(" expected, ");
   }
   return sb.toString();
 }
 public String getExpectedText(PsiBuilder builder_) {
   int offset = builder_.getCurrentOffset();
   StringBuilder sb = new StringBuilder();
   if (addExpected(sb, offset, true)) {
     sb.append(" expected, ");
   } else if (addExpected(sb, offset, false)) sb.append(" unexpected, ");
   return sb.toString();
 }
 private boolean addExpected(StringBuilder sb, int position, boolean expected) {
   MyList<Variant> list = expected ? variants : unexpected;
   String[] strings = new String[list.size()];
   long[] hashes = new long[strings.length];
   Arrays.fill(strings, "");
   int count = 0;
   loop:
   for (Variant variant : list) {
     if (position == variant.position) {
       String text = variant.object.toString();
       long hash = StringHash.calc(text);
       for (int i = 0; i < count; i++) {
         if (hashes[i] == hash) continue loop;
       }
       hashes[count] = hash;
       strings[count] = text;
       count++;
     }
   }
   Arrays.sort(strings);
   count = 0;
   for (String s : strings) {
     if (s.length() == 0) continue;
     if (count++ > 0) {
       if (count > MAX_VARIANTS_TO_DISPLAY) {
         sb.append(" and ...");
         break;
       } else {
         sb.append(", ");
       }
     }
     char c = s.charAt(0);
     String displayText = c == '<' || StringUtil.isJavaIdentifierStart(c) ? s : '\'' + s + '\'';
     sb.append(displayText);
   }
   if (count > 1 && count < MAX_VARIANTS_TO_DISPLAY) {
     int idx = sb.lastIndexOf(", ");
     sb.replace(idx, idx + 1, " or");
   }
   return count > 0;
 }
  @NotNull
  @Override
  public PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes) {
    @NonNls StringBuilder builder = new StringBuilder();
    builder.append("public <").append(name);
    if (superTypes.length > 1
        || superTypes.length == 1
            && !superTypes[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
      builder.append(" extends ");
      for (PsiClassType type : superTypes) {
        if (type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) continue;
        builder.append(type.getCanonicalText()).append('&');
      }

      builder.delete(builder.length() - 1, builder.length());
    }
    builder.append("> void foo(){}");
    try {
      return createMethodFromText(builder.toString(), null).getTypeParameters()[0];
    } catch (RuntimeException e) {
      throw new IncorrectOperationException("type parameter text: " + builder.toString());
    }
  }
 @NotNull
 @Override
 public PsiDocTag createParamTag(
     @NotNull final String parameterName, @NonNls final String description)
     throws IncorrectOperationException {
   @NonNls final StringBuilder builder = new StringBuilder();
   builder.append(" * @param ");
   builder.append(parameterName);
   builder.append(" ");
   final String[] strings = description.split("\\n");
   for (int i = 0; i < strings.length; i++) {
     if (i > 0) builder.append("\n * ");
     builder.append(strings[i]);
   }
   return createDocTagFromText(builder.toString());
 }
 @NotNull
 @Override
 public PsiReferenceList createReferenceList(
     @NotNull final PsiJavaCodeReferenceElement[] references) throws IncorrectOperationException {
   @NonNls final StringBuilder builder = new StringBuilder();
   builder.append("void method()");
   if (references.length > 0) {
     builder.append(" throws ");
     for (int i = 0; i < references.length; i++) {
       if (i > 0) builder.append(", ");
       builder.append(references[i].getCanonicalText());
     }
   }
   builder.append(';');
   return createMethodFromText(builder.toString(), null).getThrowsList();
 }
 @NotNull
 @Override
 public PsiParameterList createParameterList(
     @NotNull final String[] names, @NotNull final PsiType[] types)
     throws IncorrectOperationException {
   @NonNls StringBuilder builder = new StringBuilder();
   builder.append("void method(");
   for (int i = 0; i < names.length; i++) {
     if (i > 0) builder.append(", ");
     builder.append(types[i].getCanonicalText()).append(' ').append(names[i]);
   }
   builder.append(");");
   return createMethodFromText(builder.toString(), null).getParameterList();
 }
  /**
   * Generates a comment if possible.
   *
   * <p>It's assumed that this method {@link PsiDocumentManager#commitDocument(Document) syncs} all
   * PSI-document changes during the processing.
   *
   * @param anchor target element for which a comment should be generated
   * @param editor target editor
   * @param commenter commenter to use
   * @param project current project
   */
  private static void generateComment(
      @NotNull PsiElement anchor,
      @NotNull Editor editor,
      @NotNull CodeDocumentationProvider documentationProvider,
      @NotNull CodeDocumentationAwareCommenter commenter,
      @NotNull Project project) {
    Document document = editor.getDocument();
    int commentStartOffset = anchor.getTextRange().getStartOffset();
    int lineStartOffset = document.getLineStartOffset(document.getLineNumber(commentStartOffset));
    if (lineStartOffset > 0 && lineStartOffset < commentStartOffset) {
      // Example:
      //    void test1() {
      //    }
      //    void test2() {
      //       <offset>
      //    }
      // We want to insert the comment at the start of the line where 'test2()' is declared.
      int nonWhiteSpaceOffset =
          CharArrayUtil.shiftBackward(document.getCharsSequence(), commentStartOffset - 1, " \t");
      commentStartOffset = Math.max(nonWhiteSpaceOffset, lineStartOffset);
    }

    int commentBodyRelativeOffset = 0;
    int caretOffsetToSet = -1;
    StringBuilder buffer = new StringBuilder();
    String commentPrefix = commenter.getDocumentationCommentPrefix();
    if (commentPrefix != null) {
      buffer.append(commentPrefix).append("\n");
      commentBodyRelativeOffset += commentPrefix.length() + 1;
    }

    String linePrefix = commenter.getDocumentationCommentLinePrefix();
    if (linePrefix != null) {
      buffer.append(linePrefix);
      commentBodyRelativeOffset += linePrefix.length();
      caretOffsetToSet = commentStartOffset + commentBodyRelativeOffset;
    }
    buffer.append("\n");
    commentBodyRelativeOffset++;

    String commentSuffix = commenter.getDocumentationCommentSuffix();
    if (commentSuffix != null) {
      buffer.append(commentSuffix).append("\n");
    }

    if (buffer.length() <= 0) {
      return;
    }

    document.insertString(commentStartOffset, buffer);
    PsiDocumentManager docManager = PsiDocumentManager.getInstance(project);
    docManager.commitDocument(document);

    Pair<PsiElement, PsiComment> pair = documentationProvider.parseContext(anchor);
    if (pair == null || pair.second == null) {
      return;
    }

    String stub = documentationProvider.generateDocumentationContentStub(pair.second);
    CaretModel caretModel = editor.getCaretModel();
    if (stub != null) {
      int insertionOffset = commentStartOffset + commentBodyRelativeOffset;
      // if (CodeStyleSettingsManager.getSettings(project).JD_ADD_BLANK_AFTER_DESCRIPTION) {
      //  buffer.setLength(0);
      //  if (linePrefix != null) {
      //    buffer.append(linePrefix);
      //  }
      //  buffer.append("\n");
      //  buffer.append(stub);
      //  stub = buffer.toString();
      // }
      document.insertString(insertionOffset, stub);
      docManager.commitDocument(document);
      pair = documentationProvider.parseContext(anchor);
    }

    if (caretOffsetToSet >= 0) {
      caretModel.moveToOffset(caretOffsetToSet);
    }

    if (pair == null || pair.second == null) {
      return;
    }

    int start = Math.min(calcStartReformatOffset(pair.first), calcStartReformatOffset(pair.second));
    int end = pair.second.getTextRange().getEndOffset();

    CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
    codeStyleManager.reformatText(anchor.getContainingFile(), start, end);

    int caretOffset = caretModel.getOffset();
    if (caretOffset > 0 && caretOffset <= document.getTextLength()) {
      char c = document.getCharsSequence().charAt(caretOffset - 1);
      if (!StringUtil.isWhiteSpace(c)) {
        document.insertString(caretOffset, " ");
        caretModel.moveToOffset(caretOffset + 1);
      }
    }
  }
    private void generateJavadoc(CodeDocumentationAwareCommenter commenter)
        throws IncorrectOperationException {
      CodeInsightSettings settings = CodeInsightSettings.getInstance();
      StringBuilder buffer = new StringBuilder();
      final String docCommentLinePrefix = commenter.getDocumentationCommentLinePrefix();
      if (docCommentLinePrefix == null) {
        return;
      }

      // There are at least two approaches for completing javadoc in case there is a text between
      // current caret position and line end:
      //     1. Move that tail text below the javadoc. Use-case:
      //         Before:
      //             /**<caret>public void foo() {}
      //         After:
      //             /**
      //              */
      //             public void foo() {}
      //     2. Move the tail text inside the javadoc. Use-case:
      //          Before:
      //             /**This is <caret>javadoc description
      //          After:
      //             /** This is
      //              * javadoc description
      //              */
      // The later is most relevant when we have 'auto wrap when typing reaches right margin' option
      // set, i.e. user starts javadoc
      // and types until right margin is reached. We want the wrapped text tail to be located inside
      // javadoc and continue typing
      // inside it. So, we have a control flow branch below that does the trick.
      buffer.append(docCommentLinePrefix);
      if (DataManager.getInstance()
              .loadFromDataContext(
                  myDataContext, AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY)
          == Boolean.TRUE) {
        myDocument.insertString(myOffset, buffer);

        // We create new buffer here because the one referenced by current 'buffer' variable value
        // may be already referenced at another
        // place (e.g. 'undo' processing stuff).
        buffer =
            new StringBuilder(LINE_SEPARATOR).append(commenter.getDocumentationCommentSuffix());
        int line = myDocument.getLineNumber(myOffset);
        myOffset = myDocument.getLineEndOffset(line);
      } else {
        buffer.append(LINE_SEPARATOR);
        buffer.append(commenter.getDocumentationCommentSuffix());
      }

      PsiComment comment = createComment(buffer, settings);
      if (comment == null) {
        return;
      }

      myOffset = comment.getTextRange().getStartOffset();
      CharSequence text = myDocument.getCharsSequence();
      myOffset = CharArrayUtil.shiftForwardUntil(text, myOffset, LINE_SEPARATOR);
      myOffset = CharArrayUtil.shiftForward(text, myOffset, LINE_SEPARATOR);
      myOffset = CharArrayUtil.shiftForwardUntil(text, myOffset, docCommentLinePrefix) + 1;
      removeTrailingSpaces(myDocument, myOffset);

      if (!CodeStyleSettingsManager.getSettings(getProject()).JD_LEADING_ASTERISKS_ARE_ENABLED) {
        LOG.assertTrue(
            CharArrayUtil.regionMatches(
                myDocument.getCharsSequence(),
                myOffset - docCommentLinePrefix.length(),
                docCommentLinePrefix));
        myDocument.deleteString(myOffset - docCommentLinePrefix.length(), myOffset);
        myOffset--;
      } else {
        myDocument.insertString(myOffset, " ");
        myOffset++;
      }

      PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
    }