diff --git a/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerBase.java b/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerBase.java index 662e3559a384..0d7848a4efa1 100644 --- a/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerBase.java +++ b/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerBase.java @@ -135,7 +135,13 @@ public class JavaTypedHandlerBase extends TypedHandlerDelegate { final @NotNull FileType fileType) { if (!isJavaFile(file)) return Result.CONTINUE; - if (c == '@') { + if (c == '/') { + PsiElement element = file.findElementAt(editor.getCaretModel().getOffset() - 1); + if (element != null && element.getNode().getElementType() == JavaTokenType.END_OF_LINE_COMMENT && element.getTextLength() == 2) { + autoPopupJavadocLookup(project, editor); + } + } + else if (c == '@') { autoPopupJavadocLookup(project, editor); } else if (c == '#' || c == '.') { diff --git a/java/java-frontback-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java b/java/java-frontback-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java index d850484a0e19..dd50cde56806 100644 --- a/java/java-frontback-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java +++ b/java/java-frontback-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java @@ -350,7 +350,8 @@ public final class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeSty "LINE_COMMENT_ADD_SPACE_ON_REFORMAT", "LINE_COMMENT_AT_FIRST_COLUMN", "BLOCK_COMMENT_AT_FIRST_COLUMN", - "BLOCK_COMMENT_ADD_SPACE" + "BLOCK_COMMENT_ADD_SPACE", + "DOCUMENTATION_LINE_COMMENT_PREFERRED" ); } else if (settingsType == SettingsType.LANGUAGE_SPECIFIC) { diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.ft b/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.ft index 13012a710bde..06b6f97d3101 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.ft +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.ft @@ -1,6 +1,6 @@ #foreach($param in $RECORD_COMPONENTS) - * @param $param + $COMMENT_PREFIX @param $param #end #foreach($param in $TYPE_PARAMS) - * @param <$param> + $COMMENT_PREFIX @param <$param> #end \ No newline at end of file diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.html b/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.html index 9414b5ba6f07..818872a2a28c 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.html +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Class.java.html @@ -19,6 +19,13 @@ Predefined variables take the following values: + + + ${COMMENT_PREFIX} + +   + The prefix on each comment line (/// or *) + ${RECORD_COMPONENTS}   diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.ft b/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.ft index 20c2ad4ca1d2..84b10987fbc8 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.ft +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.ft @@ -1,9 +1,9 @@ #foreach($param in $PARAMS) - * @param $param + $COMMENT_PREFIX @param $param #end #foreach($param in $TYPE_PARAMS) - * @param <$param> + $COMMENT_PREFIX @param <$param> #end #foreach($exception in $THROWS) - * @throws $exception + $COMMENT_PREFIX @throws $exception #end \ No newline at end of file diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.html b/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.html index 25ace0f5ebe0..e347ca3ac598 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.html +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Constructor.java.html @@ -19,6 +19,13 @@ Predefined variables take the following values: + + + ${COMMENT_PREFIX} + +   + The prefix on each comment line (/// or *) + ${PARAMS}   diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.ft b/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.ft index 7b2c5d52847c..97f0195b23bd 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.ft +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.ft @@ -1,12 +1,12 @@ #foreach($param in $PARAMS) - * @param $param + $COMMENT_PREFIX @param $param #end #if($RETURN_TYPE != "void") - * @return + $COMMENT_PREFIX @return #end #foreach($param in $TYPE_PARAMS) - * @param <$param> + $COMMENT_PREFIX @param <$param> #end #foreach($exception in $THROWS) - * @throws $exception + $COMMENT_PREFIX @throws $exception #end \ No newline at end of file diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.html b/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.html index ab2b6253fe55..596f4485444d 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.html +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Method.java.html @@ -19,6 +19,13 @@ Predefined variables take the following values: + + + ${COMMENT_PREFIX} + +   + The prefix on each comment line (/// or *) + ${PARAMS}   diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.ft b/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.ft index cde83051dae4..b64d90c2c3f5 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.ft +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.ft @@ -1,17 +1,17 @@ #foreach ($param in $PARAMS_INHERITED) - * @param $param + $COMMENT_PREFIX @param $param #end #if (!$PARAMS_INHERITED) #foreach ($param in $PARAMS) - * @param $param + $COMMENT_PREFIX @param $param #end #end #if($RETURN_TYPE != "void") - * @return + $COMMENT_PREFIX @return #end #foreach($param in $TYPE_PARAMS) - * @param <$param> + $COMMENT_PREFIX @param <$param> #end #foreach($exception in $THROWS) - * @throws $exception + $COMMENT_PREFIX @throws $exception #end \ No newline at end of file diff --git a/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.html b/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.html index 0ea2f140de23..d1a39d44305c 100644 --- a/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.html +++ b/java/java-impl/resources/fileTemplates/code/JavaDoc Overriding Method.java.html @@ -19,6 +19,13 @@ Predefined variables take the following values: + + + ${COMMENT_PREFIX} + +   + The prefix on each comment line (/// or *) + ${PARAMS}   diff --git a/java/java-impl/resources/messages/RefactorJBundle.properties b/java/java-impl/resources/messages/RefactorJBundle.properties index adc64a1e9db0..9f77921afffe 100644 --- a/java/java-impl/resources/messages/RefactorJBundle.properties +++ b/java/java-impl/resources/messages/RefactorJBundle.properties @@ -44,3 +44,5 @@ codestyle.settings.extractor.command.name=CodeStyleSettings Extractor nullaway.suppress.command.name=Suppress NullAway Problem nullaway.suppress.inlay.text=Add @SuppressWarnings nullaway.suppress.error.no.target=Cannot find element to suppress + +insert.javadoc.template=Insert Javadoc Stub diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index 85667fb47235..87843bdeafaa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -25,6 +25,7 @@ import com.intellij.codeInspection.javaDoc.JavadocDeclarationInspection; import com.intellij.codeInspection.javaDoc.MissingJavadocInspection; import com.intellij.icons.AllIcons; import com.intellij.java.syntax.parser.JavaKeywords; +import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.diagnostic.Logger; @@ -64,6 +65,7 @@ import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiRecursiveElementWalkingVisitor; import com.intellij.psi.PsiReference; import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.TokenType; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.TrueFilter; @@ -84,6 +86,7 @@ import com.intellij.psi.javadoc.PsiSnippetAttribute; import com.intellij.psi.javadoc.PsiSnippetAttributeList; import com.intellij.psi.javadoc.PsiSnippetAttributeValue; import com.intellij.psi.javadoc.PsiSnippetDocTagValue; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -147,9 +150,20 @@ public final class JavaDocCompletionContributor extends CompletionContributor im @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { final PsiElement position = parameters.getPosition(); + + if (isStartOfMarkdownComment(position)) { + JavadocMarkdownTemplateLookupElement documentationElement = new JavadocMarkdownTemplateLookupElement( + ((PsiDocComment)position.getParent()).getOwner()); + + if (documentationElement.isAvailable()) { + result.addElement(documentationElement); + // Unusual early return, but only the template should be shown + return; + } + } + boolean isArg = PsiJavaPatterns.psiElement().afterLeaf("(").accepts(position); PsiDocTag tag = PsiTreeUtil.getParentOfType(position, PsiDocTag.class); - boolean onlyConstants = !isArg && tag != null && tag.getName().equals(VALUE_TAG); final PsiReference ref = position.getContainingFile().findReferenceAt(parameters.getOffset()); PsiElement refElement = ref == null ? null : ref.getElement(); @@ -165,6 +179,7 @@ public final class JavaDocCompletionContributor extends CompletionContributor im result = JavaCompletionSorting.addJavaSorting(parameters, result); result.stopHere(); + boolean onlyConstants = !isArg && tag != null && tag.getName().equals(VALUE_TAG); for (LookupElement item : completeJavadocReference(position, (PsiJavaReference)ref)) { if (onlyConstants) { if (!(item.getObject() instanceof PsiField field)) continue; @@ -192,7 +207,6 @@ public final class JavaDocCompletionContributor extends CompletionContributor im } } } - if (tag != null && "author".equals(tag.getName())) { result.addElement(LookupElementBuilder.create(SystemProperties.getUserName())); } @@ -282,6 +296,76 @@ public final class JavaDocCompletionContributor extends CompletionContributor im } } }); + + extend(CompletionType.BASIC, psiElement(PsiSnippetDocTagValue.class), new CompletionProvider<>() { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + @NotNull ProcessingContext context, + @NotNull CompletionResultSet result) { + PsiElement position = parameters.getPosition(); + + PsiElement parent = position.getParent(); + if (parent instanceof PsiDocTagValue && !(parent instanceof PsiDocParamRef) && !(parent instanceof PsiDocMethodOrFieldRef)) { + PsiDocTag docTag = ObjectUtils.tryCast(parent.getParent(), PsiDocTag.class); + if (docTag != null) { + JavadocManager docManager = JavadocManager.getInstance(parameters.getOriginalFile().getProject()); + JavadocTagInfo info = docManager.getTagInfo(docTag.getName()); + if (info != null) { + // Avoid suggesting standard tags inside custom tag value, as custom tag may require custom value (e.g., reference) + suggestTags(parameters, result, position, true); + } + } + } + } + }); + + extend(CompletionType.BASIC, psiElement(JavaDocTokenType.DOC_COMMENT_DATA), new CompletionProvider<>() { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + @NotNull ProcessingContext context, + @NotNull CompletionResultSet result) { + PsiElement position = parameters.getPosition(); + if (isStartOfMarkdownComment(position)) return; + + final PsiParameter param = getDocTagParam(position.getParent()); + if (param != null) { + suggestSimilarParameterDescriptions(result, position, param); + } + + if (!(position.getParent() instanceof PsiInlineDocTag)) { + suggestLinkWrappingVariants(parameters, result.withPrefixMatcher(CompletionUtil.findJavaIdentifierPrefix(parameters)), position); + } + + suggestCodeLiterals(result, position); + + boolean forceInlineTags = position.getParent() instanceof PsiDocTag && + !(position.getPrevSibling() instanceof PsiDocToken token && + token.getTokenType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS); + + suggestTags(parameters, result, position, forceInlineTags); + } + }); + } + + /// Returns `true` if the element is at the start of the Markdown comment. + /// Note that if the comment isn't empty, `false` will be returned. + private static boolean isStartOfMarkdownComment(@NotNull PsiElement element) { + PsiElement prev = element.getPrevSibling(); + if (prev == null) return false; + ASTNode prevNode = prev.getNode(); + IElementType prevType = prevNode.getElementType(); + + PsiDocComment comment = PsiTreeUtil.getParentOfType(prev, PsiDocComment.class); + if (comment == null || !comment.isMarkdownComment()) return false; + PsiElement[] children = comment.getChildren(); + if (children.length > 3) return false; + + // The identifier gets merged into the existing comment data (if it exists) + if (element.getTextLength() > CompletionUtilCore.DUMMY_IDENTIFIER.length()) return false; + + if (prevType == TokenType.WHITE_SPACE) return true; + if (prev == comment.getFirstChild()) return true; + return false; } private @Unmodifiable @NotNull List completeJavadocReference(PsiElement position, PsiJavaReference ref) { @@ -326,51 +410,6 @@ public final class JavaDocCompletionContributor extends CompletionContributor im return null; } - @Override - public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) { - PsiElement position = parameters.getPosition(); - - if (position.getParent() instanceof PsiDocFragmentName) { - super.fillCompletionVariants(parameters, result); - return; - } - - if (PsiDocToken.isDocToken(position, JavaDocTokenType.DOC_TAG_VALUE_TOKEN)) { - PsiElement parent = position.getParent(); - if (parent instanceof PsiDocTagValue && !(parent instanceof PsiDocParamRef) && !(parent instanceof PsiDocMethodOrFieldRef)) { - PsiDocTag docTag = ObjectUtils.tryCast(parent.getParent(), PsiDocTag.class); - if (docTag != null) { - JavadocManager docManager = JavadocManager.getInstance(parameters.getOriginalFile().getProject()); - JavadocTagInfo info = docManager.getTagInfo(docTag.getName()); - if (info != null) { - // Avoid suggesting standard tags inside custom tag value, as custom tag may require custom value (e.g., reference) - suggestTags(parameters, result, position, true); - } - } - } - } - if (PsiJavaPatterns.psiElement(JavaDocTokenType.DOC_COMMENT_DATA).accepts(position)) { - final PsiParameter param = getDocTagParam(position.getParent()); - if (param != null) { - suggestSimilarParameterDescriptions(result, position, param); - } - - if (!(position.getParent() instanceof PsiInlineDocTag)) { - suggestLinkWrappingVariants(parameters, result.withPrefixMatcher(CompletionUtil.findJavaIdentifierPrefix(parameters)), position); - } - - suggestCodeLiterals(result, position); - - boolean forceInlineTags = position.getParent() instanceof PsiDocTag && - !(position.getPrevSibling() instanceof PsiDocToken token - && token.getTokenType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS); - - suggestTags(parameters, result, position, forceInlineTags); - } - - super.fillCompletionVariants(parameters, result); - } - private static void suggestTags(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result, @NotNull PsiElement position, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavadocCompletionConfidence.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavadocCompletionConfidence.java index 56f615282c8f..11b784c890ce 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavadocCompletionConfidence.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavadocCompletionConfidence.java @@ -44,6 +44,9 @@ public final class JavadocCompletionConfidence extends CompletionConfidence { return ThreeState.NO; } } + if(PsiDocToken.isDocToken(contextElement, JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) { + return ThreeState.NO; + } return ThreeState.UNSURE; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavadocMarkdownTemplateLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavadocMarkdownTemplateLookupElement.java new file mode 100644 index 000000000000..64bf2903e4bf --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavadocMarkdownTemplateLookupElement.java @@ -0,0 +1,72 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.editorActions.CodeDocumentationUtil; +import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementCustomPreviewHolder; +import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.lang.documentation.CodeDocumentationProvider; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.modcommand.ActionContext; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiJavaDocumentedElement; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.RefactorJBundle; +import org.jetbrains.annotations.NotNull; + +/// [LookupElement] to handle Markdown Javadoc template preview and insertion +final class JavadocMarkdownTemplateLookupElement extends LookupElement implements LookupElementCustomPreviewHolder { + private final PsiJavaDocumentedElement targetElement; + private String cachedTemplate = null; + + JavadocMarkdownTemplateLookupElement(PsiJavaDocumentedElement element) { targetElement = element; } + + @Override + public @NotNull String getLookupString() { + return RefactorJBundle.message("insert.javadoc.template"); + } + + @Override + public @NotNull IntentionPreviewInfo preview(@NotNull ActionContext ctx) { + return new IntentionPreviewInfo.Snippet(JavaFileType.INSTANCE, "/// \n" + getTemplate(), + targetElement.getContainingFile().getFileDocument().getLineNumber(ctx.offset())); + } + + private String getTemplate() { + if (cachedTemplate == null) { + final CodeDocumentationProvider langDocumentationProvider = CodeDocumentationUtil.getCodeProvider(JavaLanguage.INSTANCE); + assert langDocumentationProvider != null; + + String potentialDocs = langDocumentationProvider.generateDocumentationContentStub(targetElement.getDocComment()); + cachedTemplate = potentialDocs == null ? "" : potentialDocs.stripTrailing().stripIndent(); + } + return cachedTemplate; + } + + public boolean isAvailable() { + return !StringUtil.isEmptyOrSpaces(getTemplate()); + } + + @Override + public void handleInsert(@NotNull InsertionContext context) { + String docs = "\n" + getTemplate(); + context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), docs); + context.commitDocument(); + + PsiComment comment = + PsiTreeUtil.getParentOfType(context.getFile().findElementAt(context.getTailOffset() - 1), PsiComment.class); + if (comment == null) return; + + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(context.getProject()); + CodeDocumentationUtil.formatComment(context.getFile(), comment, codeStyleManager); + + PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(context.getDocument()); + + context.getDocument().insertString(comment.getTextRange().getStartOffset() + 3, " "); + context.getEditor().getCaretModel().moveToOffset(comment.getTextRange().getStartOffset() + 4); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java index 0c012745f4b9..6df1326086c4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java @@ -17,7 +17,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.JavaDocTokenType; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; @@ -31,7 +30,6 @@ import com.intellij.psi.PsiTypeParameterListOwner; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.util.PairProcessor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CharArrayUtil; @@ -43,6 +41,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; public final class JavaDocCommentFixer implements DocCommentFixer { @@ -99,12 +98,12 @@ public final class JavaDocCommentFixer implements DocCommentFixer { } Document document = file.getFileDocument(); if (!commonProblems.isEmpty()) { - fixCommonProblems(ContainerUtil.flatten(commonProblems.values()), comment, document, project); + fixCommonProblems(ContainerUtil.flatten(commonProblems.values()), owner, document, project); } PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document); - ensureContentOrdered(docComment, document); - locateCaret(docComment, editor, file); + ensureContentOrdered(Objects.requireNonNull(owner.getDocComment()), document); + locateCaret(Objects.requireNonNull(owner.getDocComment()), editor, file); } private static @NotNull MissingJavadocInspection getMissingJavadocInspection() { @@ -151,15 +150,18 @@ public final class JavaDocCommentFixer implements DocCommentFixer { * parameter doesn't have a description etc). This method handles result of the second exception * * @param problems detected problems - * @param comment target comment to fix + * @param commentOwner owner of the comment to fix * @param document target document which contains text of the comment being fixed * @param project current project */ @SuppressWarnings("unchecked") private static void fixCommonProblems(@NotNull List problems, - @NotNull PsiComment comment, + @NotNull PsiJavaDocumentedElement commentOwner, final @NotNull Document document, @NotNull Project project) { + PsiDocComment comment = commentOwner.getDocComment(); + if (comment == null) return; + List toRemove = new ArrayList<>(); List problemsToApply = new ArrayList<>(); for (ProblemDescriptor problem : problems) { @@ -167,7 +169,7 @@ public final class JavaDocCommentFixer implements DocCommentFixer { if (element == null) { continue; } - if (!PsiDocToken.isDocToken(element, JavaDocTokenType.DOC_COMMENT_START) && comment.getTextRange().contains(element.getTextRange())) { + if ((element != comment.getFirstChild()) && comment.getTextRange().contains(element.getTextRange())) { // Unnecessary element like '@return' at the void method's javadoc. for (PsiElement e = element; e != null; e = e.getParent()) { if (e instanceof PsiDocTag) { @@ -188,6 +190,7 @@ public final class JavaDocCommentFixer implements DocCommentFixer { fixes[0].applyFix(project, problem); } } + comment = commentOwner.getDocComment(); PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); if (toRemove.isEmpty()) { @@ -205,8 +208,15 @@ public final class JavaDocCommentFixer implements DocCommentFixer { int i = CharArrayUtil.shiftBackward(text, startOffset - 1, " \t"); if (i >= 0) { char c = text.charAt(i); - if (c == '*') { - i = CharArrayUtil.shiftBackward(text, i - 1, " \t"); + if (!comment.isMarkdownComment()) { + if (c == '*') { + i = CharArrayUtil.shiftBackward(text, i - 1, " \t"); + } + } + else { + if (c == '/') { + i = CharArrayUtil.shiftBackward(text, i - 1, " \t/"); + } } } if (i >= 0 && text.charAt(i) == '\n') { @@ -215,7 +225,7 @@ public final class JavaDocCommentFixer implements DocCommentFixer { int endOffset = range.getEndOffset(); // Javadoc PSI is awkward, it includes next line text before the next tag. That's why we need to strip it. - i = CharArrayUtil.shiftBackward(text, endOffset - 1, " \t*"); + i = findBackwardOffset(text, endOffset - 1, comment.isMarkdownComment()); if (i > 0 && text.charAt(i) == '\n') { endOffset = i; } @@ -246,7 +256,7 @@ public final class JavaDocCommentFixer implements DocCommentFixer { String paramName = valueElement.getText(); if (paramName != null) { current.add(paramName); - tagInfoByName.put(paramName, parseTagValue(tag, document)); + tagInfoByName.put(paramName, parseTagValue(comment, tag, document)); } } //endregion @@ -294,7 +304,9 @@ public final class JavaDocCommentFixer implements DocCommentFixer { //endregion } - private static @NotNull Pair parseTagValue(@NotNull PsiDocTag tag, @NotNull Document document) { + private static @NotNull Pair parseTagValue(@NotNull PsiDocComment comment, + @NotNull PsiDocTag tag, + @NotNull Document document) { PsiDocTagValue valueElement = tag.getValueElement(); assert valueElement != null; @@ -302,7 +314,7 @@ public final class JavaDocCommentFixer implements DocCommentFixer { int endOffset = tag.getTextRange().getEndOffset(); // Javadoc PSI is rather weird... CharSequence text = document.getCharsSequence(); - int i = CharArrayUtil.shiftBackward(text, endOffset - 1, " \t*"); + int i = findBackwardOffset(text, endOffset - 1, comment.isMarkdownComment()); if (i > 0 && text.charAt(i) == '\n') { endOffset = i; } @@ -333,7 +345,7 @@ public final class JavaDocCommentFixer implements DocCommentFixer { if (!good) { int offset = tag.getTextRange().getEndOffset(); CharSequence text = document.getCharsSequence(); - int i = CharArrayUtil.shiftBackward(text, offset - 1, " \t*"); + int i = findBackwardOffset(text, offset - 1, comment.isMarkdownComment()); if (i > 0 && text.charAt(i) == '\n') { offset = i - 1; } @@ -347,4 +359,9 @@ public final class JavaDocCommentFixer implements DocCommentFixer { JavadocNavigationDelegate.navigateToLineEnd(editor, file); } } + + /// @return the new offset, taking into account the start of a comment line + private static int findBackwardOffset(@NotNull CharSequence text, int offset, boolean isMarkdown) { + return CharArrayUtil.shiftBackward(text, offset, isMarkdown ? " \t/" : " \t*"); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index 269e0aab455d..2020385aeeed 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -218,7 +218,11 @@ public final class JavaTypedHandler extends JavaTypedHandlerBase { int offset = editor.getCaretModel().getOffset(); PsiElement lastElement = file.findElementAt(offset - 1); - return lastElement != null && StringUtil.endsWithChar(lastElement.getText(), '@'); + if (lastElement != null) { + String lastElementText = lastElement.getText(); + return StringUtil.endsWithChar(lastElementText, '@') || StringUtil.endsWith(lastElementText, "///"); + } + return false; }); } diff --git a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java index 753e6409accf..d5ce9cb1ad6c 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java @@ -637,6 +637,11 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext attributes.put("CONTAINING_CLASS", psiClass.getName()); } } + + if (commentOwner.getDocComment() != null) { + attributes.put("COMMENT_PREFIX", commentOwner.getDocComment().isMarkdownComment() ? "///" : "*"); + } + return attributes; } @@ -697,16 +702,16 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext final PsiTypeParameterList typeParameterList = psiMethod.getTypeParameterList(); if (typeParameterList != null) { - createTypeParamsListComment(builder, commenter, typeParameterList); + createTypeParamsListComment(builder, commenter, typeParameterList, _comment); } if (psiMethod.getReturnType() != null && !PsiTypes.voidType().equals(psiMethod.getReturnType())) { - builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, _comment.getContainingFile(), commenter)); + builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, _comment, commenter)); builder.append(LINE_SEPARATOR); } final PsiJavaCodeReferenceElement[] references = psiMethod.getThrowsList().getReferenceElements(); for (PsiJavaCodeReferenceElement reference : references) { - builder.append(CodeDocumentationUtil.createDocCommentLine(THROWS_TAG, _comment.getContainingFile(), commenter)); + builder.append(CodeDocumentationUtil.createDocCommentLine(THROWS_TAG, _comment, commenter)); builder.append(reference.getText()); builder.append(LINE_SEPARATOR); } @@ -714,14 +719,14 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext else if (commentOwner instanceof PsiClass) { if (((PsiClass)commentOwner).isRecord()) { for (PsiRecordComponent component : ((PsiClass)commentOwner).getRecordComponents()) { - builder.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, commentOwner.getContainingFile(), commenter)); + builder.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, _comment, commenter)); builder.append(component.getName()); builder.append(LINE_SEPARATOR); } } final PsiTypeParameterList typeParameterList = ((PsiClass)commentOwner).getTypeParameterList(); if (typeParameterList != null) { - createTypeParamsListComment(builder, commenter, typeParameterList); + createTypeParamsListComment(builder, commenter, typeParameterList, _comment); } } return !builder.isEmpty() ? builder.toString() : null; @@ -732,10 +737,16 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext PsiMethod psiMethod) { PsiParameterList parameterList = psiMethod.getParameterList(); final PsiParameter[] parameters = parameterList.getParameters(); + + PsiDocComment docComment = psiMethod.getDocComment(); final Map index2Description = collectParentParameterDescriptions(psiMethod, parameters); for (int i = 0; i < parameters.length; i++) { - builder.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, psiMethod.getContainingFile(), commenter)); + builder.append( + docComment == null + ? CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, psiMethod.getContainingFile(), commenter) + : CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, docComment, commenter) + ); builder.append(parameters[i].getName()); String description = index2Description.get(i); if (description != null) { @@ -745,8 +756,10 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext } } + /// @return A "sparse array" of each parameter that is documented private static @NotNull Map collectParentParameterDescriptions(PsiMethod psiMethod, PsiParameter[] parameters) { final Map index2Description = new HashMap<>(); + CharSequence prefix = CodeDocumentationUtil.preferredDocumentationLinePrefix(psiMethod.getContainingFile(), psiMethod.getDocComment()); for (int i = 0; i < parameters.length; i++) { PsiDocTag param = JavaDocInfoGenerator.findInheritDocTag(psiMethod, i); @@ -763,7 +776,9 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext } } if (paramName != null) { - String description = param.getText().substring(endOffset).replaceFirst("(\\s*\\*)?\\s*$", ""); + String description = param.getText().substring(endOffset).replaceFirst("(\\s*(?:\\*|///))?\\s*$", ""); + // Remove the leading chars, since we don't know the final comment type. + description = description.replaceAll("(\\n\\s*)(?:\\*|///)", "$1" + prefix); index2Description.put(i, description); } } @@ -772,10 +787,11 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext public static void createTypeParamsListComment(final StringBuilder buffer, final CodeDocumentationAwareCommenter commenter, - final PsiTypeParameterList typeParameterList) { + final PsiTypeParameterList typeParameterList, + final PsiComment comment) { final PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters(); for (PsiTypeParameter typeParameter : typeParameters) { - buffer.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, typeParameterList.getContainingFile(), commenter)); + buffer.append(CodeDocumentationUtil.createDocCommentLine(PARAM_TAG, comment, commenter)); buffer.append("<").append(typeParameter.getName()).append(">"); buffer.append(LINE_SEPARATOR); } diff --git a/java/java-psi-impl/src/com/intellij/lang/java/JavaCommenter.java b/java/java-psi-impl/src/com/intellij/lang/java/JavaCommenter.java index 8634d230b25f..9c9aeeed86ee 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/JavaCommenter.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/JavaCommenter.java @@ -74,10 +74,25 @@ public final class JavaCommenter implements CodeDocumentationAwareCommenterEx { return element instanceof PsiDocComment; } + @Override + public boolean isDocumentationLineComment(PsiComment element) { + return isDocumentationComment(element) && ((PsiDocComment)element).isMarkdownComment(); + } + @Override public boolean isDocumentationCommentText(final PsiElement element) { if (element == null) return false; final ASTNode node = element.getNode(); return node != null && (node.getElementType() == JavaDocTokenType.DOC_COMMENT_DATA || node.getElementType() == JavaDocTokenType.DOC_TAG_VALUE_TOKEN); } + + @Override + public IElementType getDocumentationLineCommentTokenType() { + return JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS; + } + + @Override + public String getDocumentationLineCommentPrefix() { + return "///"; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java index a426d106a794..4fdd3f18a9a2 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java @@ -14,6 +14,7 @@ import com.intellij.lang.java.parser.JavaParserUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.platform.syntax.SyntaxElementType; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.impl.source.javadoc.PsiDocCommentImpl; import com.intellij.psi.impl.source.javadoc.PsiDocFragmentNameImpl; @@ -185,12 +186,21 @@ public interface JavaDocElementType { @NotNull CharSequence newText, @NotNull Language fileLanguage, @NotNull Project project) { - if (!StringUtil.startsWith(newText, "/**") || !StringUtil.endsWith(newText, "*/")) return false; + SyntaxElementType targetType; + if (StringUtil.startsWith(newText, "/**") && StringUtil.endsWith(newText, "*/")) { + targetType = JavaDocSyntaxElementType.DOC_COMMENT; + } + else if (StringUtil.startsWith(newText, "///")) { + targetType = JavaDocSyntaxElementType.DOC_MARKDOWN_COMMENT; + } + else { + return false; + } LanguageLevel level = LanguageLevelProjectExtension.getInstance(project).getLanguageLevel(); JavaLexer lexer = new JavaLexer(level); lexer.start(newText); - if (lexer.getTokenType() == JavaDocSyntaxElementType.DOC_COMMENT) { + if (lexer.getTokenType() == targetType) { lexer.advance(); return lexer.getTokenType() == null; } diff --git a/java/java-tests/testData/codeInsight/addJavadoc/afterInheritanceFromMarkdown.java b/java/java-tests/testData/codeInsight/addJavadoc/afterInheritanceFromMarkdown.java new file mode 100644 index 000000000000..4fef13bb0bce --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadoc/afterInheritanceFromMarkdown.java @@ -0,0 +1,13 @@ +// "Add Javadoc" "true-preview" +class A { + /// @param a Very beautiful param + /// from mk jdoc + void test(int a) {} +} +class B extends A { + /** + * @param a Very beautiful param + * from mk jdoc + */ + void test(int a) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadoc/beforeInheritanceFromMarkdown.java b/java/java-tests/testData/codeInsight/addJavadoc/beforeInheritanceFromMarkdown.java new file mode 100644 index 000000000000..2945e16fcf44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadoc/beforeInheritanceFromMarkdown.java @@ -0,0 +1,9 @@ +// "Add Javadoc" "true-preview" +class A { + /// @param a Very beautiful param + /// from mk jdoc + void test(int a) {} +} +class B extends A { + void test(int a) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterClass.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterClass.java new file mode 100644 index 000000000000..67ccad99938a --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterClass.java @@ -0,0 +1,6 @@ +// "Add Javadoc" "true-preview" + +/// +class Foo { + +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterDifferentParamNames.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterDifferentParamNames.java new file mode 100644 index 000000000000..b73589004d0e --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterDifferentParamNames.java @@ -0,0 +1,25 @@ +// "Add Javadoc" "true-preview" + +class A { + /// @param b it's a description + /// for the + /// second param + /// @param a it's a description for the first param + /// @param blah it's a description + /// for a nonexistent parameter + /// @param c it's a description + /// for the third param + void test(int a, int b, int c, int d) {} +} + +class B extends A { + /// @param x it's a description for the first param + /// @param y it's a description + /// for the + /// second param + /// @param z it's a description + /// for the third param + /// @param w + @Override + void test(final int x, int y, int z, int w) {} +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField.java new file mode 100644 index 000000000000..a659152ea9c9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField.java @@ -0,0 +1,8 @@ +// "Add Javadoc" "true-preview" + +class A { + + /// + private int myFoo; + +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField2.java new file mode 100644 index 000000000000..c2e6b94f334a --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField2.java @@ -0,0 +1,9 @@ +// "Add Javadoc" "true-preview" + +class Test { + + /// + @XXX + int xxx = 1; + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField3.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField3.java new file mode 100644 index 000000000000..2bc7186b8928 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterField3.java @@ -0,0 +1,8 @@ +// "Add Javadoc" "true-preview" + +class Test { + + /// + private @XXX int xxx = 1; + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterInheritanceFromClassic.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterInheritanceFromClassic.java new file mode 100644 index 000000000000..ce60d84fece6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterInheritanceFromClassic.java @@ -0,0 +1,14 @@ +// "Add Javadoc" "true-preview" + +class A { + /** + * @param a Very beautiful param + * From the classic javadoc + */ + void test(int a) {} +} +class B extends A { + /// @param a Very beautiful param + /// From the classic javadoc + void test(int a) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethod.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethod.java new file mode 100644 index 000000000000..877801d8f893 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethod.java @@ -0,0 +1,8 @@ +// "Add Javadoc" "true-preview" + +class A { + /// + public void foo() { + + } +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethod2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethod2.java new file mode 100644 index 000000000000..0abd8d16e1ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethod2.java @@ -0,0 +1,10 @@ +// "Add Javadoc" "true-preview" + +class A { + /// @param s + /// @return + /// @throws Exception + public int foo(final String s) throws Exception { + + } +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethodCommentInheritance.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethodCommentInheritance.java new file mode 100644 index 000000000000..594315ad55b5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMethodCommentInheritance.java @@ -0,0 +1,128 @@ +// "Add Javadoc" "true-preview" + +//Method Comments Algorithm +// +// If a method does not have a documentation comment, or has an {@inheritDoc} tag, then the standard doclet uses Automatic Supertype Search. + +interface ClazzInterface1Interface2 { + /// @param h must be copied to 8th place. Just + /// a few unicode symbols: <?> + /// @param f blah blah blah + /// @param c blah blah blah + /// @param d blah blah blah + /// @param g blah blah blah + void foo(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); +} + +interface ClazzInterface1Interface1 { + /// @param dd blah blah blah + /// @param ff blah blah blah + /// @param cc blah blah blah + /// @param gg must be copied to 7th place + void foo(int aa, int bb, int cc, int dd, int ee, int ff, int gg, int hh, int ii, int jj); +} + +class ClazzClazz { + /// @param fff must be copied to 6th place + /// @param ccc blah blah blah + void foo(int aaa, int bbb, int ccc, int ddd, int eee, int fff, int ggg, int hhh, int iii, int jjj) { + } +} + +interface ClazzInterface1 extends ClazzInterface1Interface1, ClazzInterface1Interface2 { + /// @param ffff blah blah blah + /// @param dddd must be copied to 4th place + /// @param cccc blah blah blah + void foo(int aaaa, int bbbb, int cccc, int dddd, int eeee, int ffff, int gggg, int hhhh, int iiii, int jjjj); +} + +interface ClazzInterface2 { + /// @param ddddd blah blah blah + /// @param hhhhh blah blah blah + /// @param fffff blah blah blah + /// @param ccccc blah blah blah + /// @param ggggg blah blah blah + /// @param eeeee must be copied to 5th place + void foo(int aaaaa, int bbbbb, int ccccc, int ddddd, int eeeee, int fffff, int ggggg, int hhhhh, int iiiii, int jjjjj); +} + +class Clazz extends ClazzClazz implements ClazzInterface1, ClazzInterface2 { + /// @param cccccc must be copied to 3rd place + public void foo(int aaaaaa, int bbbbbb, int cccccc, int dddddd, int eeeeee, int ffffff, int gggggg, int hhhhhh, int iiiiii, int jjjjjj) { + } +} + +interface Interface1Interface1 { + /// @param x1 blah blah blah + /// @param x3 blah blah blah + /// @param x4 blah blah blah + /// @param x5 blah blah blah + /// @param x6 blah blah blah + /// @param x7 blah blah blah + /// @param x8 blah blah blah + /// @param x10 must be copied to 10th place + void foo(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10); +} + +interface Interface1Interface2 { + /// @param b1 blah blah blah + /// @param b3 blah blah blah + /// @param b4 blah blah blah + /// @param b5 blah blah blah + /// @param b6 blah blah blah + /// @param b7 blah blah blah + /// @param b8 blah blah blah + /// @param b9 must be copied to 9th place + /// @param b10 blah blah blah + void foo(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8, int b9, int b10); +} + +interface Interface1 extends Interface1Interface1, Interface1Interface2 { + /// @param parameter1 must be copied to 1st place + /// @param parameter3 blah blah blah + /// @param parameter4 blah blah blah + /// @param parameter5 blah blah blah + /// @param parameter6 blah blah blah + /// @param parameter7 blah blah blah + /// @param parameter8 blah blah blah + void foo(int parameter1, + int parameter2, + int parameter3, + int parameter4, + int parameter5, + int parameter6, + int parameter7, + int parameter8, + int parameter9, + int parameter10); +} + +interface Interface2 { + /// @param param1 blah blah blah + /// @param param2 must be copied to 2nd place + /// @param param3 blah blah blah + /// @param param4 blah blah blah + /// @param param5 blah blah blah + /// @param param6 blah blah blah + /// @param param7 blah blah blah + /// @param param8 blah blah blah + /// @param param9 blah blah blah + /// @param param10 blah blah blah + void foo(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10); +} + +class Test extends Clazz implements Interface1, Interface2 { + /// @param p1 must be copied to 1st place + /// @param p2 must be copied to 2nd place + /// @param p3 must be copied to 3rd place + /// @param p4 must be copied to 4th place + /// @param p5 must be copied to 5th place + /// @param p6 must be copied to 6th place + /// @param p7 must be copied to 7th place + /// @param p8 must be copied to 8th place. Just + /// a few unicode symbols: <?> + /// @param p9 must be copied to 9th place + /// @param p10 must be copied to 10th place + public void foo(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMultiFieldDeclaration.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMultiFieldDeclaration.java new file mode 100644 index 000000000000..c3fbc839a579 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMultiFieldDeclaration.java @@ -0,0 +1,5 @@ +// "Add Javadoc" "true-preview" +class Foo { + int x = 2, /// + y = 1; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMultiFieldDeclaration2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMultiFieldDeclaration2.java new file mode 100644 index 000000000000..6d38076b550e --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterMultiFieldDeclaration2.java @@ -0,0 +1,5 @@ +// "Add Javadoc" "true-preview" +class Foo { + /// + int x = 2, y = 1; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterRecord.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterRecord.java new file mode 100644 index 000000000000..4c665e334c17 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/afterRecord.java @@ -0,0 +1,6 @@ +// "Add Javadoc" "true-preview" + + +/// @param u +record Test(int u) { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeAnonymous.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeAnonymous.java new file mode 100644 index 000000000000..563378ca3b04 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeAnonymous.java @@ -0,0 +1,13 @@ +// "Add Javadoc" "false" +class A { + + void m() { + new Runnable() { + @Override + public void run() { + + } + } + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeClass.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeClass.java new file mode 100644 index 000000000000..36d6dda48764 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeClass.java @@ -0,0 +1,5 @@ +// "Add Javadoc" "true-preview" + +class Foo { + +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeClass2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeClass2.java new file mode 100644 index 000000000000..0d1d456256d6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeClass2.java @@ -0,0 +1,13 @@ +// "Add Javadoc" "false" + +class A { + + void m() { + + Object o = new Object() { + + } + + } + +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeDifferentParamNames.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeDifferentParamNames.java new file mode 100644 index 000000000000..1078cea2e854 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeDifferentParamNames.java @@ -0,0 +1,18 @@ +// "Add Javadoc" "true-preview" + +class A { + /// @param b it's a description + /// for the + /// second param + /// @param a it's a description for the first param + /// @param blah it's a description + /// for a nonexistent parameter + /// @param c it's a description + /// for the third param + void test(int a, int b, int c, int d) {} +} + +class B extends A { + @Override + void test(final int x, int y, int z, int w) {} +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField.java new file mode 100644 index 000000000000..dd822f3bd13b --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField.java @@ -0,0 +1,7 @@ +// "Add Javadoc" "true-preview" + +class A { + + private int myFoo; + +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField2.java new file mode 100644 index 000000000000..792cedfa2a7b --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField2.java @@ -0,0 +1,8 @@ +// "Add Javadoc" "true-preview" + +class Test { + + @XXX + int xxx = 1; + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField3.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField3.java new file mode 100644 index 000000000000..24f17bab8231 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeField3.java @@ -0,0 +1,7 @@ +// "Add Javadoc" "true-preview" + +class Test { + + private @XXX int xxx = 1; + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeFieldAtInitializer.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeFieldAtInitializer.java new file mode 100644 index 000000000000..6fc362c6cd3c --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeFieldAtInitializer.java @@ -0,0 +1,8 @@ +// "Add Javadoc" "false" + +class Test { + + String foo = "xyz"; + String bar = foo; + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeInheritanceFromClassic.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeInheritanceFromClassic.java new file mode 100644 index 000000000000..eb2abf65ffb8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeInheritanceFromClassic.java @@ -0,0 +1,12 @@ +// "Add Javadoc" "true-preview" + +class A { + /** + * @param a Very beautiful param + * From the classic javadoc + */ + void test(int a) {} +} +class B extends A { + void test(int a) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeJavadocAlreadyExists.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeJavadocAlreadyExists.java new file mode 100644 index 000000000000..33ce8c440c0b --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeJavadocAlreadyExists.java @@ -0,0 +1,5 @@ +// "Add Javadoc" "false" +/// javadoc +class Foo { + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeLocalClass.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeLocalClass.java new file mode 100644 index 000000000000..098c5f3ee30e --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeLocalClass.java @@ -0,0 +1,9 @@ +// "Add Javadoc" "false" + +class Test { + + void x() { + class Local {} + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethod.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethod.java new file mode 100644 index 000000000000..e8fed15ad118 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethod.java @@ -0,0 +1,7 @@ +// "Add Javadoc" "true-preview" + +class A { + public void foo() { + + } +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethod2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethod2.java new file mode 100644 index 000000000000..ff63fb79ea0f --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethod2.java @@ -0,0 +1,7 @@ +// "Add Javadoc" "true-preview" + +class A { + public int foo(final String s) throws Exception { + + } +} diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethodCommentInheritance.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethodCommentInheritance.java new file mode 100644 index 000000000000..a68ed0bbae69 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMethodCommentInheritance.java @@ -0,0 +1,117 @@ +// "Add Javadoc" "true-preview" + +//Method Comments Algorithm +// +// If a method does not have a documentation comment, or has an {@inheritDoc} tag, then the standard doclet uses Automatic Supertype Search. + +interface ClazzInterface1Interface2 { + /// @param h must be copied to 8th place. Just + /// a few unicode symbols: <?> + /// @param f blah blah blah + /// @param c blah blah blah + /// @param d blah blah blah + /// @param g blah blah blah + void foo(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); +} + +interface ClazzInterface1Interface1 { + /// @param dd blah blah blah + /// @param ff blah blah blah + /// @param cc blah blah blah + /// @param gg must be copied to 7th place + void foo(int aa, int bb, int cc, int dd, int ee, int ff, int gg, int hh, int ii, int jj); +} + +class ClazzClazz { + /// @param fff must be copied to 6th place + /// @param ccc blah blah blah + void foo(int aaa, int bbb, int ccc, int ddd, int eee, int fff, int ggg, int hhh, int iii, int jjj) { + } +} + +interface ClazzInterface1 extends ClazzInterface1Interface1, ClazzInterface1Interface2 { + /// @param ffff blah blah blah + /// @param dddd must be copied to 4th place + /// @param cccc blah blah blah + void foo(int aaaa, int bbbb, int cccc, int dddd, int eeee, int ffff, int gggg, int hhhh, int iiii, int jjjj); +} + +interface ClazzInterface2 { + /// @param ddddd blah blah blah + /// @param hhhhh blah blah blah + /// @param fffff blah blah blah + /// @param ccccc blah blah blah + /// @param ggggg blah blah blah + /// @param eeeee must be copied to 5th place + void foo(int aaaaa, int bbbbb, int ccccc, int ddddd, int eeeee, int fffff, int ggggg, int hhhhh, int iiiii, int jjjjj); +} + +class Clazz extends ClazzClazz implements ClazzInterface1, ClazzInterface2 { + /// @param cccccc must be copied to 3rd place + public void foo(int aaaaaa, int bbbbbb, int cccccc, int dddddd, int eeeeee, int ffffff, int gggggg, int hhhhhh, int iiiiii, int jjjjjj) { + } +} + +interface Interface1Interface1 { + /// @param x1 blah blah blah + /// @param x3 blah blah blah + /// @param x4 blah blah blah + /// @param x5 blah blah blah + /// @param x6 blah blah blah + /// @param x7 blah blah blah + /// @param x8 blah blah blah + /// @param x10 must be copied to 10th place + void foo(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10); +} + +interface Interface1Interface2 { + /// @param b1 blah blah blah + /// @param b3 blah blah blah + /// @param b4 blah blah blah + /// @param b5 blah blah blah + /// @param b6 blah blah blah + /// @param b7 blah blah blah + /// @param b8 blah blah blah + /// @param b9 must be copied to 9th place + /// @param b10 blah blah blah + void foo(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8, int b9, int b10); +} + +interface Interface1 extends Interface1Interface1, Interface1Interface2 { + /// @param parameter1 must be copied to 1st place + /// @param parameter3 blah blah blah + /// @param parameter4 blah blah blah + /// @param parameter5 blah blah blah + /// @param parameter6 blah blah blah + /// @param parameter7 blah blah blah + /// @param parameter8 blah blah blah + void foo(int parameter1, + int parameter2, + int parameter3, + int parameter4, + int parameter5, + int parameter6, + int parameter7, + int parameter8, + int parameter9, + int parameter10); +} + +interface Interface2 { + /// @param param1 blah blah blah + /// @param param2 must be copied to 2nd place + /// @param param3 blah blah blah + /// @param param4 blah blah blah + /// @param param5 blah blah blah + /// @param param6 blah blah blah + /// @param param7 blah blah blah + /// @param param8 blah blah blah + /// @param param9 blah blah blah + /// @param param10 blah blah blah + void foo(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10); +} + +class Test extends Clazz implements Interface1, Interface2 { + public void foo(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMultiFieldDeclaration.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMultiFieldDeclaration.java new file mode 100644 index 000000000000..0b973323f689 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMultiFieldDeclaration.java @@ -0,0 +1,4 @@ +// "Add Javadoc" "true-preview" +class Foo { + int x = 2, y = 1; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMultiFieldDeclaration2.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMultiFieldDeclaration2.java new file mode 100644 index 000000000000..f5f3ddc0b774 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeMultiFieldDeclaration2.java @@ -0,0 +1,4 @@ +// "Add Javadoc" "true-preview" +class Foo { + int x = 2, y = 1; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeRecord.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeRecord.java new file mode 100644 index 000000000000..ff0ae83b20d2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeRecord.java @@ -0,0 +1,5 @@ +// "Add Javadoc" "true-preview" + + +record Test(int u) { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeTypeParameter.java b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeTypeParameter.java new file mode 100644 index 000000000000..37c40eb89233 --- /dev/null +++ b/java/java-tests/testData/codeInsight/addJavadocMarkdown/beforeTypeParameter.java @@ -0,0 +1,8 @@ +// "Add Javadoc" "false" +class A { + + TTT> void mmmm() { + + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/class.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/class.after.java new file mode 100644 index 000000000000..9eed38009d71 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/class.after.java @@ -0,0 +1,2 @@ +/// +class MarkdownGeneration {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/class.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/class.before.java new file mode 100644 index 000000000000..ecae7e7406a4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/class.before.java @@ -0,0 +1,2 @@ +/// +class MarkdownGeneration {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/classParam.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/classParam.after.java new file mode 100644 index 000000000000..eb86986776c5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/classParam.after.java @@ -0,0 +1,3 @@ +/// +/// @param +interface MarkdownFirstClassParam {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/classParam.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/classParam.before.java new file mode 100644 index 000000000000..0c47898231f4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/classParam.before.java @@ -0,0 +1,2 @@ +/// +interface MarkdownFirstClassParam {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled01.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled01.after.java new file mode 100644 index 000000000000..3478f47c771c --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled01.after.java @@ -0,0 +1,5 @@ +class MarkdownFirstClass { + + /// some text + int methodFull(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled01.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled01.before.java new file mode 100644 index 000000000000..3478f47c771c --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled01.before.java @@ -0,0 +1,5 @@ +class MarkdownFirstClass { + + /// some text + int methodFull(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled02.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled02.after.java new file mode 100644 index 000000000000..fc2fc90e47fd --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled02.after.java @@ -0,0 +1,5 @@ +class MarkdownFirstClass { + + /// some text + int methodFull(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled02.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled02.before.java new file mode 100644 index 000000000000..fc2fc90e47fd --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled02.before.java @@ -0,0 +1,5 @@ +class MarkdownFirstClass { + + /// some text + int methodFull(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled03.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled03.after.java new file mode 100644 index 000000000000..6d79d6a009e8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled03.after.java @@ -0,0 +1,5 @@ +class MarkdownFirstClass { + + /// z ome text + int methodFull(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled03.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled03.before.java new file mode 100644 index 000000000000..db2499f713d3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/generationDisabled03.before.java @@ -0,0 +1,5 @@ +class MarkdownFirstClass { + + /// zome text + int methodFull(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodAbstract.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodAbstract.after.java new file mode 100644 index 000000000000..a954842ea6cf --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodAbstract.after.java @@ -0,0 +1,7 @@ +abstract class MarkdownFirstClassParam { + /// + /// @param param1 + /// @param param2 + /// @return + abstract String methodAbstract(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodAbstract.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodAbstract.before.java new file mode 100644 index 000000000000..1e9ba2351184 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodAbstract.before.java @@ -0,0 +1,4 @@ +abstract class MarkdownFirstClassParam { + /// + abstract String methodAbstract(String param1, String param2); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodEmpty.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodEmpty.after.java new file mode 100644 index 000000000000..f8561e245fff --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodEmpty.after.java @@ -0,0 +1,4 @@ +interface MarkdownFirstClass { + /// + void methodEmpty(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodEmpty.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodEmpty.before.java new file mode 100644 index 000000000000..8732bb914914 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodEmpty.before.java @@ -0,0 +1,4 @@ +interface MarkdownFirstClass { + /// + void methodEmpty(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFull.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFull.after.java new file mode 100644 index 000000000000..d0abcdcf10aa --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFull.after.java @@ -0,0 +1,8 @@ +interface MarkdownFirstClass { + /// + /// @param param1 + /// @param param2 + /// @return + /// @throws RuntimeException + int methodFull(String param1, String param2) throws RuntimeException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFull.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFull.before.java new file mode 100644 index 000000000000..ce8fc9a668a5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFull.before.java @@ -0,0 +1,4 @@ +interface MarkdownFirstClass { + /// + int methodFull(String param1, String param2) throws RuntimeException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFullNoTemplate.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFullNoTemplate.after.java new file mode 100644 index 000000000000..384e06e8f87a --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFullNoTemplate.after.java @@ -0,0 +1,8 @@ +abstract class MarkdownFirstClassParam { + /// + /// @param param1 + /// @param param2 + /// @return + /// @throws RuntimeException + abstract String methodAbstract(String param1, String param2) throws RuntimeException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFullNoTemplate.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFullNoTemplate.before.java new file mode 100644 index 000000000000..9b21fa5cd50a --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodFullNoTemplate.before.java @@ -0,0 +1,4 @@ +abstract class MarkdownFirstClassParam { + /// + abstract String methodAbstract(String param1, String param2) throws RuntimeException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodParam.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodParam.after.java new file mode 100644 index 000000000000..87c51c83839a --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodParam.after.java @@ -0,0 +1,5 @@ +interface MarkdownFirstClass { + /// + /// @param param + void methodParam(String param); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodParam.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodParam.before.java new file mode 100644 index 000000000000..87ed6f8d88d9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodParam.before.java @@ -0,0 +1,4 @@ +interface MarkdownFirstClass { + /// + void methodParam(String param); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodReturn.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodReturn.after.java new file mode 100644 index 000000000000..973652e90f38 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodReturn.after.java @@ -0,0 +1,5 @@ +interface MarkdownFirstClass { + /// + /// @return + String methodReturn(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodReturn.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodReturn.before.java new file mode 100644 index 000000000000..b348126acf55 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodReturn.before.java @@ -0,0 +1,4 @@ +interface MarkdownFirstClass { + /// + String methodReturn(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodThrows.after.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodThrows.after.java new file mode 100644 index 000000000000..9421bac42ebc --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodThrows.after.java @@ -0,0 +1,5 @@ +interface MarkdownFirstClass { + /// + /// @throws RuntimeException + void methodReturn() throws RuntimeException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodThrows.before.java b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodThrows.before.java new file mode 100644 index 000000000000..60fe9cc875b8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateJavadocMarkdown/methodThrows.before.java @@ -0,0 +1,4 @@ +interface MarkdownFirstClass { + /// + void methodReturn() throws RuntimeException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeStyle/jsonExport.json b/java/java-tests/testData/codeStyle/jsonExport.json index befaef0342cc..6b3de5b6ccdd 100644 --- a/java/java-tests/testData/codeStyle/jsonExport.json +++ b/java/java-tests/testData/codeStyle/jsonExport.json @@ -92,6 +92,7 @@ "doc_param_description_on_new_line": false, "doc_preserve_line_breaks": false, "doc_use_throws_not_exception_tag": true, + "documentation_line_comment_preferred": false, "else_on_new_line": false, "enum_constants_wrap": "off", "enum_field_annotation_wrap": "off", diff --git a/java/java-tests/testData/codeStyle/notFirstImportModule.json b/java/java-tests/testData/codeStyle/notFirstImportModule.json index 6d4645175d1d..5571b03caa7c 100644 --- a/java/java-tests/testData/codeStyle/notFirstImportModule.json +++ b/java/java-tests/testData/codeStyle/notFirstImportModule.json @@ -92,6 +92,7 @@ "doc_param_description_on_new_line": false, "doc_preserve_line_breaks": false, "doc_use_throws_not_exception_tag": true, + "documentation_line_comment_preferred": false, "else_on_new_line": false, "enum_constants_wrap": "off", "enum_field_annotation_wrap": "off", diff --git a/java/java-tests/testData/codeStyle/notFirstImportModuleAfterMigration.json b/java/java-tests/testData/codeStyle/notFirstImportModuleAfterMigration.json index 6d4645175d1d..5571b03caa7c 100644 --- a/java/java-tests/testData/codeStyle/notFirstImportModuleAfterMigration.json +++ b/java/java-tests/testData/codeStyle/notFirstImportModuleAfterMigration.json @@ -92,6 +92,7 @@ "doc_param_description_on_new_line": false, "doc_preserve_line_breaks": false, "doc_use_throws_not_exception_tag": true, + "documentation_line_comment_preferred": false, "else_on_new_line": false, "enum_constants_wrap": "off", "enum_field_annotation_wrap": "off", diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.java b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.java index 0804e4cf2a78..1ef5b6d5fe3a 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.java +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.java @@ -4,4 +4,5 @@ /// ~~~ /// squigly code block /// ~~~ -/// out of code block \ No newline at end of file +/// out of code block +class X {} \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.txt index c9fde15252ec..e9ed328dbdae 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01.txt @@ -1,30 +1,46 @@ PsiJavaFile:CodeBlockMarkdown01.java - PsiDocComment - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiWhiteSpace(' ') - PsiMarkdownCodeBlock: - PsiDocToken:DOC_CODE_FENCE('```') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' backtick Code block') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiDocToken:DOC_CODE_FENCE('```') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiMarkdownCodeBlock: - PsiDocToken:DOC_CODE_FENCE('~~~') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' squigly code block') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiDocToken:DOC_CODE_FENCE('~~~') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' out of code block') PsiImportList - \ No newline at end of file + + PsiClass:X + PsiDocComment + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiWhiteSpace(' ') + PsiMarkdownCodeBlock: + PsiDocToken:DOC_CODE_FENCE('```') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' backtick Code block') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiDocToken:DOC_CODE_FENCE('```') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiMarkdownCodeBlock: + PsiDocToken:DOC_CODE_FENCE('~~~') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' squigly code block') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiDocToken:DOC_CODE_FENCE('~~~') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' out of code block') + PsiWhiteSpace('\n') + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:X('X') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01_node.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01_node.txt index df6a4b26cde9..2667c477ca7a 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01_node.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown01_node.txt @@ -1,30 +1,46 @@ java.FILE - DOC_MARKDOWN_COMMENT - DOC_COMMENT_LEADING_ASTERISKS - WHITE_SPACE - DOC_CODE_BLOCK - DOC_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_CODE_BLOCK - DOC_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA IMPORT_LIST - \ No newline at end of file + + CLASS + DOC_MARKDOWN_COMMENT + DOC_COMMENT_LEADING_ASTERISKS + WHITE_SPACE + DOC_CODE_BLOCK + DOC_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_CODE_BLOCK + DOC_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + WHITE_SPACE + MODIFIER_LIST + + CLASS_KEYWORD + WHITE_SPACE + IDENTIFIER + TYPE_PARAMETER_LIST + + EXTENDS_LIST + + IMPLEMENTS_LIST + + WHITE_SPACE + LBRACE + RBRACE \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.java b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.java index 829f641bb4e3..4a693ef72663 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.java +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.java @@ -1,4 +1,5 @@ /// ``` /// ~~~ /// Inside squigly code block, but the backtick codeblock has priority -/// ~~~ \ No newline at end of file +/// ~~~ +class X {} \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.txt index 12d0221e8c75..0ad4a2dbbb37 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02.txt @@ -1,21 +1,37 @@ PsiJavaFile:CodeBlockMarkdown02.java - PsiDocComment - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiWhiteSpace(' ') - PsiMarkdownCodeBlock: - PsiDocToken:DOC_CODE_FENCE('```') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiDocToken:DOC_COMMENT_DATA('~~~') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' Inside squigly code block') - PsiDocToken:DOC_COMMENT_DATA(',') - PsiDocToken:DOC_COMMENT_DATA(' but the backtick codeblock has priority') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiDocToken:DOC_COMMENT_DATA('~~~') PsiImportList - \ No newline at end of file + + PsiClass:X + PsiDocComment + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiWhiteSpace(' ') + PsiMarkdownCodeBlock: + PsiDocToken:DOC_CODE_FENCE('```') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiDocToken:DOC_COMMENT_DATA('~~~') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' Inside squigly code block') + PsiDocToken:DOC_COMMENT_DATA(',') + PsiDocToken:DOC_COMMENT_DATA(' but the backtick codeblock has priority') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiDocToken:DOC_COMMENT_DATA('~~~') + PsiWhiteSpace('\n') + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:X('X') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02_node.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02_node.txt index 69f41f3a9249..b47e57a0761d 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02_node.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown02_node.txt @@ -1,21 +1,37 @@ java.FILE - DOC_MARKDOWN_COMMENT - DOC_COMMENT_LEADING_ASTERISKS - WHITE_SPACE - DOC_CODE_BLOCK - DOC_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_COMMENT_DATA - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_COMMENT_DATA - DOC_COMMENT_DATA - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_COMMENT_DATA IMPORT_LIST - \ No newline at end of file + + CLASS + DOC_MARKDOWN_COMMENT + DOC_COMMENT_LEADING_ASTERISKS + WHITE_SPACE + DOC_CODE_BLOCK + DOC_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_COMMENT_DATA + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_COMMENT_DATA + DOC_COMMENT_DATA + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_COMMENT_DATA + WHITE_SPACE + MODIFIER_LIST + + CLASS_KEYWORD + WHITE_SPACE + IDENTIFIER + TYPE_PARAMETER_LIST + + EXTENDS_LIST + + IMPLEMENTS_LIST + + WHITE_SPACE + LBRACE + RBRACE \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.java b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.java index 2570914f5e36..72bd5b433223 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.java +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.java @@ -1,3 +1,4 @@ /// ~~~~~~~~ /// Codeblock with more than 3 chars -/// ~~~~ \ No newline at end of file +/// ~~~~ +class X {} \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.txt index 317a7d82440b..037139f2fc99 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03.txt @@ -1,15 +1,31 @@ PsiJavaFile:CodeBlockMarkdown03.java - PsiDocComment - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiWhiteSpace(' ') - PsiMarkdownCodeBlock: - PsiDocToken:DOC_CODE_FENCE('~~~~~~~~') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' Codeblock with more than 3 chars') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiDocToken:DOC_CODE_FENCE('~~~~') PsiImportList - \ No newline at end of file + + PsiClass:X + PsiDocComment + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiWhiteSpace(' ') + PsiMarkdownCodeBlock: + PsiDocToken:DOC_CODE_FENCE('~~~~~~~~') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' Codeblock with more than 3 chars') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiDocToken:DOC_CODE_FENCE('~~~~') + PsiWhiteSpace('\n') + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:X('X') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03_node.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03_node.txt index e2f5258b07ba..e1e051b26ad7 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03_node.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown03_node.txt @@ -1,15 +1,31 @@ java.FILE - DOC_MARKDOWN_COMMENT - DOC_COMMENT_LEADING_ASTERISKS - WHITE_SPACE - DOC_CODE_BLOCK - DOC_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_CODE_FENCE IMPORT_LIST - \ No newline at end of file + + CLASS + DOC_MARKDOWN_COMMENT + DOC_COMMENT_LEADING_ASTERISKS + WHITE_SPACE + DOC_CODE_BLOCK + DOC_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_CODE_FENCE + WHITE_SPACE + MODIFIER_LIST + + CLASS_KEYWORD + WHITE_SPACE + IDENTIFIER + TYPE_PARAMETER_LIST + + EXTENDS_LIST + + IMPLEMENTS_LIST + + WHITE_SPACE + LBRACE + RBRACE \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.java b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.java index 8de5cdf15018..b757cb508f10 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.java +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.java @@ -1 +1,2 @@ /// `Single line codeblock` +class X {} diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.txt index 31ade7b53f80..831028dd5897 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04.txt @@ -1,10 +1,26 @@ PsiJavaFile:CodeBlockMarkdown04.java - PsiDocComment - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiWhiteSpace(' ') - PsiMarkdownCodeBlock: - PsiDocToken:DOC_INLINE_CODE_FENCE('`') - PsiDocToken:DOC_COMMENT_DATA('Single line codeblock') - PsiDocToken:DOC_INLINE_CODE_FENCE('`') PsiImportList - \ No newline at end of file + + PsiClass:X + PsiDocComment + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiWhiteSpace(' ') + PsiMarkdownCodeBlock: + PsiDocToken:DOC_INLINE_CODE_FENCE('`') + PsiDocToken:DOC_COMMENT_DATA('Single line codeblock') + PsiDocToken:DOC_INLINE_CODE_FENCE('`') + PsiWhiteSpace('\n') + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:X('X') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04_node.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04_node.txt index 9f98a011b32a..962c88292520 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04_node.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown04_node.txt @@ -1,10 +1,26 @@ java.FILE - DOC_MARKDOWN_COMMENT - DOC_COMMENT_LEADING_ASTERISKS - WHITE_SPACE - DOC_CODE_BLOCK - DOC_INLINE_CODE_FENCE - DOC_COMMENT_DATA - DOC_INLINE_CODE_FENCE IMPORT_LIST - \ No newline at end of file + + CLASS + DOC_MARKDOWN_COMMENT + DOC_COMMENT_LEADING_ASTERISKS + WHITE_SPACE + DOC_CODE_BLOCK + DOC_INLINE_CODE_FENCE + DOC_COMMENT_DATA + DOC_INLINE_CODE_FENCE + WHITE_SPACE + MODIFIER_LIST + + CLASS_KEYWORD + WHITE_SPACE + IDENTIFIER + TYPE_PARAMETER_LIST + + EXTENDS_LIST + + IMPLEMENTS_LIST + + WHITE_SPACE + LBRACE + RBRACE \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.java b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.java index 7bb911017100..0243c77ebb4d 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.java +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.java @@ -1,3 +1,4 @@ /// ` /// According to markdown rules, this is inline /// ` +class X {} \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.txt index 029fdf1960e7..ce4b9677d0df 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05.txt @@ -1,15 +1,31 @@ PsiJavaFile:CodeBlockMarkdown05.java - PsiDocComment - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiWhiteSpace(' ') - PsiMarkdownCodeBlock: - PsiDocToken:DOC_INLINE_CODE_FENCE('`') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' According to markdown rules, this is inline') - PsiWhiteSpace('\n') - PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') - PsiDocToken:DOC_COMMENT_DATA(' ') - PsiDocToken:DOC_INLINE_CODE_FENCE('`') PsiImportList - \ No newline at end of file + + PsiClass:X + PsiDocComment + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiWhiteSpace(' ') + PsiMarkdownCodeBlock: + PsiDocToken:DOC_INLINE_CODE_FENCE('`') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' According to markdown rules, this is inline') + PsiWhiteSpace('\n') + PsiDocToken:DOC_COMMENT_LEADING_ASTERISKS('///') + PsiDocToken:DOC_COMMENT_DATA(' ') + PsiDocToken:DOC_INLINE_CODE_FENCE('`') + PsiWhiteSpace('\n') + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:X('X') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05_node.txt b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05_node.txt index bc0710c22879..3886a2b22120 100644 --- a/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05_node.txt +++ b/java/java-tests/testData/psi/parser-full/javadocParsing/CodeBlockMarkdown05_node.txt @@ -1,15 +1,31 @@ java.FILE - DOC_MARKDOWN_COMMENT - DOC_COMMENT_LEADING_ASTERISKS - WHITE_SPACE - DOC_CODE_BLOCK - DOC_INLINE_CODE_FENCE - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - WHITE_SPACE - DOC_COMMENT_LEADING_ASTERISKS - DOC_COMMENT_DATA - DOC_INLINE_CODE_FENCE IMPORT_LIST - \ No newline at end of file + + CLASS + DOC_MARKDOWN_COMMENT + DOC_COMMENT_LEADING_ASTERISKS + WHITE_SPACE + DOC_CODE_BLOCK + DOC_INLINE_CODE_FENCE + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + WHITE_SPACE + DOC_COMMENT_LEADING_ASTERISKS + DOC_COMMENT_DATA + DOC_INLINE_CODE_FENCE + WHITE_SPACE + MODIFIER_LIST + + CLASS_KEYWORD + WHITE_SPACE + IDENTIFIER + TYPE_PARAMETER_LIST + + EXTENDS_LIST + + IMPLEMENTS_LIST + + WHITE_SPACE + LBRACE + RBRACE \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/GenerateJavadocMarkdownTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/GenerateJavadocMarkdownTest.java new file mode 100644 index 000000000000..196bf093fc83 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/GenerateJavadocMarkdownTest.java @@ -0,0 +1,64 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.java.codeInsight; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.registry.RegistryTestUtil; +import com.intellij.testFramework.HeavyPlatformTestCase; +import kotlin.Unit; + +/// Variant of [GenerateJavadocTest] to handle Markdown comment generation +/// Since the workflow for Markdown comments is different ([com.intellij.codeInsight.completion.CompletionContributor]-based), +/// it is a separate class +@HeavyPlatformTestCase.WrapInCommand +public class GenerateJavadocMarkdownTest extends LightFixtureCompletionTestCase { + + @Override + protected String getBasePath() { + return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/generateJavadocMarkdown/"; + } + + public void testClass() { doTestWithTemplates(); } + public void testClassParam() { doTestWithTemplates(); } + public void testMethodEmpty() { doTestWithTemplates(); } + public void testMethodParam() { doTestWithTemplates(); } + public void testMethodReturn() { doTestWithTemplates(); } + public void testMethodThrows() { doTestWithTemplates(); } + public void testMethodFull() { doTestWithTemplates(); } + public void testMethodAbstract() { doTestWithTemplates(); } + + public void testGenerationDisabled01(){ doTestWithTemplates(); } + public void testGenerationDisabled02(){ doTestWithTemplates(); } + public void testGenerationDisabled03(){ doTestWithTemplates(); } + + /// Sanity check: verify template-less code path doesn't explode + public void testMethodFullNoTemplate() { doTestNoTemplates(); } + + private void doTestNoTemplates() { + RegistryTestUtil.withValue(Registry.get("java.javadoc.use.templates"), Boolean.FALSE, ()-> { + doTest(); + return Unit.INSTANCE; + }); + } + + private void doTestWithTemplates() { + RegistryTestUtil.withValue(Registry.get("java.javadoc.use.templates"), Boolean.TRUE, ()-> { + doTest(); + return Unit.INSTANCE; + }); + } + + private void doTest() { + String name = getTestName(true); + configureByFile(name + ".before.java"); + performAction(); + checkResultByFile(name + ".after.java"); + } + + private void performAction() { + myFixture.completeBasic(); + if (myItems.length <= 1) + myFixture.type("\t"); + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocMarkdownCommentTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocMarkdownCommentTest.java new file mode 100644 index 000000000000..246f0931cdc7 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocMarkdownCommentTest.java @@ -0,0 +1,528 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.java.codeInsight.editorActions; + +import com.intellij.application.options.CodeStyle; +import com.intellij.codeInsight.editorActions.FixDocCommentAction; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.editor.impl.AbstractEditorTest; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.JavaCodeStyleSettings; + +public class FixDocMarkdownCommentTest extends AbstractEditorTest { + + @Override + protected void setUp() throws Exception { + super.setUp(); + + CodeStyleSettings settings = CodeStyle.getSettings(getProject()); + settings.getCommonSettings(JavaLanguage.INSTANCE).DOCUMENTATION_LINE_COMMENT_PREFERRED = true; + CodeStyle.setTemporarySettings(getProject(), settings); + } + + public void testGenerateMethodDoc() { + String initial = """ + class Test { + String test(int i) { + return "s"; + } + }"""; + String expected = """ + class Test { + /// @param i + /// @return + String test(int i) { + return "s"; + } + }"""; + doTest(initial, expected); + } + + public void testGenerateFieldDoc() { + String initial = """ + class Test { + int i; + }"""; + String expected = """ + class Test { + /// + int i; + }"""; + doTest(initial, expected); + } + + public void testGenerateClassDoc() { + String initial = """ + class Test { + void test1() {} + + void test2() {} + }"""; + String expected = """ + /// + class Test { + void test1() {} + + void test2() {} + }"""; + doTest(initial, expected); + } + + public void testRemoveOneParameterFromMany() { + String initial = """ + class Test { + /// @param i + /// @param j + /// @param k + void test(int i, int j) { + } + }"""; + String expected = """ + class Test { + /// @param i + /// @param j + void test(int i, int j) { + } + }"""; + doTest(initial, expected); + } + + public void testRemoveTheOnlyParameter() { + String initial = """ + class Test { + /// My description + /// @param i + void test() { + } + }"""; + String expected = """ + class Test { + /// My description + void test() { + } + }"""; + doTest(initial, expected); + } + + public void testRemoveReturn() { + String initial = """ + class Test { + /// My description + /// @return data + void test() { + } + }"""; + String expected = """ + class Test { + /// My description + void test() { + } + }"""; + doTest(initial, expected); + } + + public void testRemoveOneThrowsFromMany() { + String initial = """ + class MyException1 extends Exception {} + class MyException2 extends Exception {} + + class Test { + /// @param i my arg + /// @throws MyException1 text1 + /// @throws MyException2 text2 + void test(int i) throws MyException2 { + } + }"""; + String expected = """ + class MyException1 extends Exception {} + class MyException2 extends Exception {} + + class Test { + /// @param i my arg + /// @throws MyException2 text2 + void test(int i) throws MyException2 { + } + }"""; + doTest(initial, expected); + } + + public void testRemoveTheOnlyThrows() { + String initial = """ + class MyException extends Exception {} + + class Test { + /// @param i my arg + /// @throws MyException text + void test(int i) { + } + }"""; + String expected = """ + class MyException extends Exception {} + + class Test { + /// @param i my arg + void test(int i) { + } + }"""; + doTest(initial, expected); + } + + public void testRemoveOneTypeParameterFromMany() { + String initial = """ + /// @param tDescription + /// @param vDescription + class Test { + }"""; + String expected = """ + /// @param vDescription + class Test { + }"""; + doTest(initial, expected); + } + + public void testRemoveMultipleTypeParameter() { + String initial = """ + /// @param tDescription + /// @param vDescription + class Test { + }"""; + String expected = """ + /// + class Test { + }"""; + doTest(initial, expected); + } + + public void testAddFirstParameter() { + String initial = """ + class Test { + void test(int i) { + } + }"""; + String expected = """ + class Test { + /// @param i + void test(int i) { + } + }"""; + doTest(initial, expected); + } + + public void testAddMultipleParameter() { + String initial = """ + class Test { + /// @param i + void test(int i, int j, int k) { + } + }"""; + String expected = """ + class Test { + /// @param i + /// @param j + /// @param k + void test(int i, int j, int k) { + } + }"""; + doTest(initial, expected); + } + + public void testAddReturn() { + String initial = """ + class Test { + int test() { + } + }"""; + String expected = """ + class Test { + /// @return + int test() { + } + }"""; + doTest(initial, expected); + } + + public void testAddFirstThrows() { + String initial = """ + class MyException extends Exception {} + + class Test { + /// @param i my arg + void test(int i) throws MyException { + } + }"""; + String expected = """ + class MyException extends Exception {} + + class Test { + /// @param i my arg + /// @throws MyException + void test(int i) throws MyException { + } + }"""; + doTest(initial, expected); + } + + public void testAddNonFirstThrows() { + String initial = """ + class MyException1 extends Exception {} + class MyException2 extends Exception {} + class MyException3 extends Exception {} + + class Test { + /// @param i my arg + /// @throws MyException1 + void test(int i) throws MyException1, MyException2, MyException3 { + } + }"""; + String expected = """ + class MyException1 extends Exception {} + class MyException2 extends Exception {} + class MyException3 extends Exception {} + + class Test { + /// @param i my arg + /// @throws MyException1 + /// @throws MyException2 + /// @throws MyException3 + void test(int i) throws MyException1, MyException2, MyException3 { + } + }"""; + doTest(initial, expected); + } + + public void testAddFirstThrowsWhenEmptyReturnIsAvailable() { + String initial = """ + class MyException extends Exception {} + + class Test { + /// @return + int test() throws MyException { + return 1; + } + }"""; + String expected = """ + class MyException extends Exception {} + + class Test { + /// @return + /// @throws MyException + int test() throws MyException { + return 1; + } + }"""; + doTest(initial, expected); + } + + public void testAddFirstTypeParameter() { + String initial = """ + /// My description + /// @author me + class Test { + }"""; + String expected = """ + /// My description + /// @author me + /// @param + class Test { + }"""; + doTest(initial, expected); + } + + public void testAddNonFirstTypeParameter() { + String initial = """ + /// My description + /// @author me + /// @param type description + class Test { + }"""; + String expected = """ + /// My description + /// @author me + /// @param type description + /// @param + class Test { + }"""; + doTest(initial, expected); + } + + public void testCorrectParametersOrder() { + String initial = """ + class Test { + /// @param j + /// @param k single line description + /// @param i multi-line + /// description + public void test(int i, int j, int k) { + } + }"""; + String expected = """ + class Test { + /// @param i multi-line + /// description + /// @param j + /// @param k single line description + public void test(int i, int j, int k) { + } + }"""; + doTest(initial, expected); + } + + public void testCorrectParametersDescriptionWhenIndentIsDefines() { + String initial = """ + class Test { + /// @param j \s + /// @param i + public void test(int i, int j) { + } + }"""; + String expected = """ + class Test { + /// @param i + /// @param j \s + public void test(int i, int j) { + } + }"""; + doTest(initial, expected); + } + + public void testCorrectMethodTypeParametersOrder() { + String initial = """ + class Test { + /// @param + /// @param A description + void test() { + } + }"""; + String expected = """ + class Test { + /// @param A description + /// @param + void test() { + } + }"""; + doTest(initial, expected); + } + + public void testCorrectClassTypeParametersOrder() { + String initial = """ + /// Class description + /// @author Zigmund + /// @param multi-line + /// description + /// @param + class Test { + }"""; + String expected = """ + /// Class description + /// @author Zigmund + /// @param + /// @param multi-line + /// description + class Test { + }"""; + doTest(initial, expected); + } + + public void testAllesZusammen() { + String initial = """ + class MyException1 extends Exception {} + class MyException2 extends Exception {} + + class Test { + /// Method description + /// @param j j description (single line) + /// @param s s description + /// @param k + /// k description (single line but located at another line) + /// @throws MyException2 + /// @return some value + void test(int i, int j, int k) throws MyException1 { + } + }"""; + String expected = """ + class MyException1 extends Exception {} + class MyException2 extends Exception {} + + class Test { + /// Method description + /// @param i + /// @param j j description (single line) + /// @param k + /// k description (single line but located at another line) + /// @throws MyException1 + void test(int i, int j, int k) throws MyException1 { + } + }"""; + doTest(initial, expected); + } + + public void testNavigateToMissingParamDescription() { + String initial = """ + class Test { + /// @param i + void test(int i) { + } + }"""; + String expected = """ + class Test { + /// @param i + void test(int i) { + } + }"""; + doTest(initial, expected); + } + + public void test_many_newlines_before_interface() { + String initial = """ + + + + + interface I {}"""; + String expected = """ + ///\s + interface I {}"""; + doTest(initial, expected); + } + + public void testWithEmptyTagsRemovalOption() { + JavaCodeStyleSettings settings = getCustomSettings(JavaCodeStyleSettings.class); + settings.JD_KEEP_EMPTY_PARAMETER = false; + settings.JD_KEEP_EMPTY_RETURN = false; + settings.JD_KEEP_EMPTY_EXCEPTION = false; + String initial = """ + package com.company; + + public class Test + { + int foo(String s, int i, double d) throws Exception + { + return 0; + } + } + """; + String expected = """ + package com.company; + + public class Test + { + /// @param s + /// @param i + /// @param d + /// @return + /// @throws Exception + int foo(String s, int i, double d) throws Exception + { + return 0; + } + } + """; + doTest(initial, expected); + } + + private void doTest(String initial, String expected) { + configureFromFileText(getTestName(false) + ".java", initial); + getEditor().getSettings().setVirtualSpace(false); + executeAction(FixDocCommentAction.ACTION_ID); + checkResultByText(expected); + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocMarkdownIntentionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocMarkdownIntentionTest.java new file mode 100644 index 000000000000..21595cedc516 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocMarkdownIntentionTest.java @@ -0,0 +1,24 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.java.codeInsight.intention; + +import com.intellij.application.options.CodeStyle; +import com.intellij.codeInsight.daemon.LightIntentionActionTestCase; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.psi.codeStyle.CodeStyleSettings; + +public class AddJavadocMarkdownIntentionTest extends LightIntentionActionTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + + CodeStyleSettings settings = CodeStyle.getSettings(getProject()); + settings.getCommonSettings(JavaLanguage.INSTANCE).DOCUMENTATION_LINE_COMMENT_PREFERRED = true; + CodeStyle.setTemporarySettings(getProject(), settings); + } + + @Override + protected String getBasePath() { + return "/codeInsight/addJavadocMarkdown"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocToModuleAndPackageTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocToModuleAndPackageTest.java index a52c6f7f5e43..6c2a359d5f4d 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocToModuleAndPackageTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/intention/AddJavadocToModuleAndPackageTest.java @@ -1,6 +1,9 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.java.codeInsight.intention; +import com.intellij.application.options.CodeStyle; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; @@ -31,4 +34,31 @@ public class AddJavadocToModuleAndPackageTest extends LightJavaCodeInsightFixtur */ module org.some.awesome{}"""); } + + public void testPackageInfoMarkdown() { + myFixture.configureByText("package-info.java", "package org.some.awesome;"); + myFixture.launchAction(myFixture.findSingleIntention("Add Javadoc")); + myFixture.checkResult(""" + /// + package org.some.awesome;"""); + } + + public void testModuleInfoMarkdown() { + myFixture.configureByText("module-info.java", "module org.some.awesome{}"); + myFixture.launchAction(myFixture.findSingleIntention("Add Javadoc")); + myFixture.checkResult(""" + /// + module org.some.awesome{}"""); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + if (getQualifiedTestMethodName().endsWith("Markdown")) { + CodeStyleSettings settings = CodeStyle.getSettings(myFixture.getProject()); + settings.getCommonSettings(JavaLanguage.INSTANCE).DOCUMENTATION_LINE_COMMENT_PREFERRED = true; + CodeStyle.setTemporarySettings(getProject(), settings); + } + } } diff --git a/platform/analysis-api/src/com/intellij/codeInsight/lookup/LookupElementCustomPreviewHolder.kt b/platform/analysis-api/src/com/intellij/codeInsight/lookup/LookupElementCustomPreviewHolder.kt index 280f1634af29..8d713c58d0b7 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/lookup/LookupElementCustomPreviewHolder.kt +++ b/platform/analysis-api/src/com/intellij/codeInsight/lookup/LookupElementCustomPreviewHolder.kt @@ -9,7 +9,7 @@ import org.jetbrains.annotations.ApiStatus /** * Represents an entity that can provide or indicate the availability of a custom preview for a lookup element. - * + * @see LookupElement */ @ApiStatus.Experimental interface LookupElementCustomPreviewHolder { diff --git a/platform/code-style-api/api-dump.txt b/platform/code-style-api/api-dump.txt index 0cc18aaaf1df..36019779a7f1 100644 --- a/platform/code-style-api/api-dump.txt +++ b/platform/code-style-api/api-dump.txt @@ -685,6 +685,7 @@ c:com.intellij.psi.codeStyle.CommonCodeStyleSettings - CATCH_ON_NEW_LINE:Z - CLASS_ANNOTATION_WRAP:I - CLASS_BRACE_STYLE:I +- DOCUMENTATION_LINE_COMMENT_PREFERRED:Z - DOWHILE_BRACE_FORCE:I - sf:DO_NOT_FORCE:I - DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS:Z diff --git a/platform/code-style-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/code-style-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index 48d42fcda4cd..f70b9777b980 100644 --- a/platform/code-style-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/code-style-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -261,6 +261,9 @@ public class CommonCodeStyleSettings implements CommentStyleSettings { public boolean LINE_COMMENT_ADD_SPACE_ON_REFORMAT = false; public boolean LINE_COMMENT_ADD_SPACE_IN_SUPPRESSION = false; + /// Whether to prefer documentation line comments (In languages like Java, Rust, Dart) + public boolean DOCUMENTATION_LINE_COMMENT_PREFERRED = false; + public boolean KEEP_LINE_BREAKS = true; /** diff --git a/platform/core-api/api-dump.txt b/platform/core-api/api-dump.txt index 00969b9ee096..7be07756a895 100644 --- a/platform/core-api/api-dump.txt +++ b/platform/core-api/api-dump.txt @@ -154,9 +154,14 @@ com.intellij.lang.CodeDocumentationAwareCommenter - a:getDocumentationCommentPrefix():java.lang.String - a:getDocumentationCommentSuffix():java.lang.String - a:getDocumentationCommentTokenType():com.intellij.psi.tree.IElementType +- getDocumentationLineCommentPrefix():java.lang.String +- getDocumentationLineCommentPrefixes():java.util.List +- getDocumentationLineCommentTokenType():com.intellij.psi.tree.IElementType +- getDocumentationLineCommentTokenTypes():java.util.List - a:getLineCommentTokenType():com.intellij.psi.tree.IElementType - getLineCommentTokenTypes():java.util.List - a:isDocumentationComment(com.intellij.psi.PsiComment):Z +- isDocumentationLineComment(com.intellij.psi.PsiComment):Z com.intellij.lang.CodeDocumentationAwareCommenterEx - com.intellij.lang.CodeDocumentationAwareCommenter - a:isDocumentationCommentText(com.intellij.psi.PsiElement):Z diff --git a/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java b/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java index 5298bac9fcfb..df3eafe862f9 100644 --- a/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java +++ b/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java @@ -42,9 +42,9 @@ public interface CodeDocumentationAwareCommenter extends Commenter { IElementType getBlockCommentTokenType(); /** - * Returns the type of the documentation comment token in the language, - * or {@code null} if the language does not support documentation comments. - * It is assumed that the documentation comment prefix is not {@code null} when the documentation comment type is not {@code null}. + * Returns the type of the block documentation comment token in the language, + * or {@code null} if the language does not support block documentation comments. + * It is assumed that {@link #getDocumentationCommentPrefix()} does not return {@code null} when the documentation comment type is not {@code null}. * * @return the documentation comment type. */ @@ -75,5 +75,40 @@ public interface CodeDocumentationAwareCommenter extends Commenter { */ @Nullable String getDocumentationCommentSuffix(); + @Nullable + default IElementType getDocumentationLineCommentTokenType() { + return null; + } + + /// Returns the types of the documentation **line** comment token in the language, + /// or `null` if the language does not support documentation **line** comments. + /// + /// It is assumed that [#getDocumentationLineCommentPrefixes()] does not return `null` when the documentation comment type is not `null`. + /// Implementations are expected to have [List]s of the same length between this function and [#getDocumentationLineCommentPrefixes()] + @Nullable + default List getDocumentationLineCommentTokenTypes() { + return ContainerUtil.createMaybeSingletonList(getDocumentationLineCommentTokenType()); + } + + @Nullable + default String getDocumentationLineCommentPrefix() { + return null; + } + + /// Returns the prefixes of the **line** documentation comment in the language, + /// or `null` if the language does not support **line** documentation comments. + /// + /// It is assumed that [#getDocumentationLineCommentTokenTypes()] does not return `null` when the documentation comment type is not `null`. + /// Implementations are expected to have [List]s of the same length between this function and [#getDocumentationLineCommentTokenTypes()] + @Nullable + default List getDocumentationLineCommentPrefixes() { + return ContainerUtil.createMaybeSingletonList(getDocumentationLineCommentPrefix()); + } + boolean isDocumentationComment(PsiComment element); + + /// @return `true` if the comment is a documentation **line** comment + default boolean isDocumentationLineComment(PsiComment element) { + return false; + } } diff --git a/platform/ide-core/resources/messages/ApplicationBundle.properties b/platform/ide-core/resources/messages/ApplicationBundle.properties index 0fa447b1f068..c929f6976a25 100644 --- a/platform/ide-core/resources/messages/ApplicationBundle.properties +++ b/platform/ide-core/resources/messages/ApplicationBundle.properties @@ -655,6 +655,7 @@ code.style.other.label=Text files and unsupported file types\: checkbox.line.comment.add.space=Add a space at line comment start checkbox.line.comment.add.space.on.reformat=Enforce on reformat checkbox.block.comment.add.space=Add spaces around block comments +checkbox.documentation.line.comment=Prefer documentation line comments rainbow.option.panel.overwritten.by.host=Overwritten By Remote Host rainbow.option.panel.display.name=Semantic highlighting diff --git a/platform/lang-api/api-dump.txt b/platform/lang-api/api-dump.txt index fa2a2451f767..42b00cb244fd 100644 --- a/platform/lang-api/api-dump.txt +++ b/platform/lang-api/api-dump.txt @@ -936,6 +936,8 @@ com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable - showCustomOption(java.lang.Class,java.lang.String,java.lang.String,java.lang.String,com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable$OptionAnchor,java.lang.String,java.lang.Object[]):V - showCustomOption(java.lang.Class,java.lang.String,java.lang.String,java.lang.String,java.lang.Object[]):V - a:showStandardOptions(java.lang.String[]):V +e:com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable$CommenterOption +- sf:DOCUMENTATION_LINE_COMMENT_PREFERRED:com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable$CommenterOption com.intellij.psi.codeStyle.DisplayPrioritySortable - s:compare(java.lang.Object,java.lang.Object,java.util.function.Function):I - a:getPriority():com.intellij.psi.codeStyle.DisplayPriority diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java index 111c12028094..59714e7b3e44 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java @@ -215,7 +215,8 @@ public interface CodeStyleSettingsCustomizable { LINE_COMMENT_ADD_SPACE_IN_SUPPRESSION, LINE_COMMENT_AT_FIRST_COLUMN, BLOCK_COMMENT_AT_FIRST_COLUMN, - BLOCK_COMMENT_ADD_SPACE + BLOCK_COMMENT_ADD_SPACE, + DOCUMENTATION_LINE_COMMENT_PREFERRED } int[] WRAP_VALUES = {CommonCodeStyleSettings.DO_NOT_WRAP, diff --git a/platform/lang-impl/api-dump.txt b/platform/lang-impl/api-dump.txt index 2a3878182d27..bf1b70f97d23 100644 --- a/platform/lang-impl/api-dump.txt +++ b/platform/lang-impl/api-dump.txt @@ -245,6 +245,8 @@ c:com.intellij.codeInsight.editorActions.AutoHardWrapHandler - wrapLineIfNecessary(com.intellij.openapi.editor.Editor,com.intellij.openapi.actionSystem.DataContext,J):V com.intellij.codeInsight.editorActions.CodeBlockProvider - a:getCodeBlockRange(com.intellij.openapi.editor.Editor,com.intellij.psi.PsiFile):com.intellij.openapi.util.TextRange +f:com.intellij.codeInsight.editorActions.CodeDocumentationUtil +- s:createDocCommentLine(java.lang.String,com.intellij.psi.PsiComment,com.intellij.lang.CodeDocumentationAwareCommenter):java.lang.String com.intellij.codeInsight.editorActions.CommentCompleteHandler - sf:EP_NAME:com.intellij.openapi.extensions.ExtensionPointName - a:isApplicable(com.intellij.psi.PsiComment,com.intellij.lang.CodeDocumentationAwareCommenter):Z @@ -258,6 +260,7 @@ c:com.intellij.codeInsight.editorActions.EnterHandler - s:adjustLineIndentNoCommit(com.intellij.openapi.editor.Document,I,java.lang.String):I f:com.intellij.codeInsight.editorActions.FixDocCommentAction - s:generateComment(com.intellij.psi.PsiElement,com.intellij.openapi.project.Project,com.intellij.openapi.editor.ModNavigator):V +- s:preferDocumentationLineComment(com.intellij.psi.PsiFile,com.intellij.psi.PsiDocCommentBase):Z com.intellij.codeInsight.editorActions.JavaLikeQuoteHandler - com.intellij.codeInsight.editorActions.QuoteHandler - canBeConcatenated(com.intellij.psi.PsiElement):Z diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.form b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.form index be2f3bd1ef16..f5acd71473cd 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.form +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.form @@ -1,6 +1,6 @@
- + @@ -18,7 +18,7 @@ - + @@ -50,9 +50,18 @@ + + + + + + + + + diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.java index 561003b5ca4c..ced6f7e7533b 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CommenterForm.java @@ -34,6 +34,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { private final JBCheckBox myLineCommentAddSpaceOnReformatCb; private final JBCheckBox myBlockCommentAtFirstJBCheckBox; private final JBCheckBox myBlockCommentAddSpaceCb; + private final JBCheckBox myDocumentationLineCommentPrefered; private final Language myLanguage; @@ -48,7 +49,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { // >>> IMPORTANT!! <<< // DO NOT EDIT OR ADD ANY CODE HERE! myCommenterPanel = new JPanel(); - myCommenterPanel.setLayout(new GridLayoutManager(6, 1, new Insets(0, 0, 0, 0), -1, -1)); + myCommenterPanel.setLayout(new GridLayoutManager(7, 1, new Insets(0, 0, 0, 0), -1, -1)); myLineCommentAtFirstColumnCb = new JBCheckBox(); this.$$$loadButtonText$$$(myLineCommentAtFirstColumnCb, this.$$$getMessageFromBundle$$$("messages/ApplicationBundle", "checkbox.line.comment.at.first.column")); @@ -57,7 +58,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); final Spacer spacer1 = new Spacer(); - myCommenterPanel.add(spacer1, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, + myCommenterPanel.add(spacer1, new GridConstraints(6, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); myLineCommentAddSpaceCb = new JBCheckBox(); this.$$$loadButtonText$$$(myLineCommentAddSpaceCb, @@ -80,11 +81,19 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); myBlockCommentAddSpaceCb = new JBCheckBox(); + myBlockCommentAddSpaceCb.setEnabled(true); this.$$$loadButtonText$$$(myBlockCommentAddSpaceCb, this.$$$getMessageFromBundle$$$("messages/ApplicationBundle", "checkbox.block.comment.add.space")); myCommenterPanel.add(myBlockCommentAddSpaceCb, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + myDocumentationLineCommentPrefered = new JBCheckBox(); + this.$$$loadButtonText$$$(myDocumentationLineCommentPrefered, + this.$$$getMessageFromBundle$$$("messages/ApplicationBundle", "checkbox.documentation.line.comment")); + myCommenterPanel.add(myDocumentationLineCommentPrefered, + new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, + GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, + false)); } if (title != null) { myCommenterPanel.setBorder(IdeBorderFactory.createTitledBorder(title)); @@ -166,6 +175,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { myLineCommentAddSpaceOnReformatCb.setSelected(langSettings.LINE_COMMENT_ADD_SPACE_ON_REFORMAT); myBlockCommentAddSpaceCb.setSelected(langSettings.BLOCK_COMMENT_ADD_SPACE); + myDocumentationLineCommentPrefered.setSelected(langSettings.DOCUMENTATION_LINE_COMMENT_PREFERRED); } @@ -176,6 +186,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { langSettings.LINE_COMMENT_ADD_SPACE = myLineCommentAddSpaceCb.isSelected(); langSettings.LINE_COMMENT_ADD_SPACE_ON_REFORMAT = myLineCommentAddSpaceOnReformatCb.isSelected(); langSettings.BLOCK_COMMENT_ADD_SPACE = myBlockCommentAddSpaceCb.isSelected(); + langSettings.DOCUMENTATION_LINE_COMMENT_PREFERRED = myDocumentationLineCommentPrefered.isSelected(); } public boolean isModified(@NotNull CodeStyleSettings settings) { @@ -185,6 +196,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { || myLineCommentAddSpaceCb.isSelected() != langSettings.LINE_COMMENT_ADD_SPACE || myBlockCommentAddSpaceCb.isSelected() != langSettings.BLOCK_COMMENT_ADD_SPACE || myLineCommentAddSpaceOnReformatCb.isSelected() != langSettings.LINE_COMMENT_ADD_SPACE_ON_REFORMAT + || myDocumentationLineCommentPrefered.isSelected() != langSettings.DOCUMENTATION_LINE_COMMENT_PREFERRED ; } @@ -215,6 +227,9 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { else if (CommenterOption.BLOCK_COMMENT_ADD_SPACE.name().equals(optionName)) { myBlockCommentAddSpaceCb.setVisible(true); } + else if (CommenterOption.DOCUMENTATION_LINE_COMMENT_PREFERRED.name().equals(optionName)) { + myDocumentationLineCommentPrefered.setVisible(true); + } } } @@ -224,6 +239,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { myBlockCommentAtFirstJBCheckBox.setVisible(isVisible); myBlockCommentAddSpaceCb.setVisible(isVisible); myLineCommentAddSpaceOnReformatCb.setVisible(isVisible); + myDocumentationLineCommentPrefered.setVisible(isVisible); } private void customizeSettings() { @@ -238,6 +254,7 @@ public final class CommenterForm implements CodeStyleSettingsCustomizable { || myLineCommentAddSpaceOnReformatCb.isVisible() || myBlockCommentAtFirstJBCheckBox.isVisible() || myBlockCommentAddSpaceCb.isVisible() + || myDocumentationLineCommentPrefered.isVisible() ); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java index 9037d7355255..eb43c2676b06 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java @@ -2,15 +2,27 @@ package com.intellij.codeInsight.editorActions; +import com.intellij.application.options.CodeStyle; import com.intellij.lang.CodeDocumentationAwareCommenter; import com.intellij.lang.Commenter; +import com.intellij.lang.Language; import com.intellij.lang.LanguageCommenters; +import com.intellij.lang.LanguageDocumentation; +import com.intellij.lang.documentation.CodeDocumentationProvider; +import com.intellij.lang.documentation.CompositeDocumentationProvider; +import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiDocCommentBase; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.DocCommentSettings; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,12 +32,38 @@ public final class CodeDocumentationUtil { private CodeDocumentationUtil() { } + /// @deprecated Prefer using [#createDocCommentLineGenericElement(String, PsiElement, CodeDocumentationAwareCommenter)] to take into account + /// potential line doc comments + @Deprecated public static String createDocCommentLine(String lineData, PsiFile file, CodeDocumentationAwareCommenter commenter) { - DocCommentSettings settings = CodeStyleManager.getInstance(file.getProject()).getDocCommentSettings(file); - return createLine(lineData, commenter, settings); + return createDocCommentLineGenericElement(lineData, file, commenter); } - private static @NotNull String createLine(String lineData, CodeDocumentationAwareCommenter commenter, DocCommentSettings settings) { + /// @param lineData The content of the commented line + /// @param element The doc comment that is being worked on. + public static String createDocCommentLine(String lineData, @NotNull PsiComment element, CodeDocumentationAwareCommenter commenter) { + return createDocCommentLineGenericElement(lineData, element, commenter); + } + + private static String createDocCommentLineGenericElement(String lineData, + @NotNull PsiElement element, + CodeDocumentationAwareCommenter commenter) { + boolean isLineComment = element instanceof PsiComment comment && commenter.isDocumentationLineComment(comment); + PsiFile file = element.getContainingFile(); + DocCommentSettings settings = CodeStyleManager.getInstance(file.getProject()).getDocCommentSettings(file); + return createLine(lineData, isLineComment, commenter, settings); + } + + private static @NotNull String createLine(String lineData, + boolean isLineComment, + CodeDocumentationAwareCommenter commenter, + DocCommentSettings settings) { + if (isLineComment) { + return lineData.isEmpty() + ? commenter.getDocumentationLineCommentPrefix() + " " + : commenter.getDocumentationLineCommentPrefix() + " " + lineData + " "; + } + if (!settings.isLeadingAsteriskEnabled()) { return " " + lineData + " "; } @@ -36,7 +74,6 @@ public final class CodeDocumentationUtil { else { return commenter.getDocumentationCommentLinePrefix() + " " + lineData + " "; } - } } @@ -103,6 +140,48 @@ public final class CodeDocumentationUtil { return new CommentContext(commenter, docStart, docAsterisk, commentStartOffset); } + /// @return The formatted comment + @ApiStatus.Internal + public static @Nullable PsiComment formatComment(PsiFile psiFile, PsiComment comment, CodeStyleManager codeStyleManager) { + RangeMarker commentMarker = psiFile.getFileDocument().createRangeMarker(comment.getTextRange().getStartOffset(), + comment.getTextRange().getEndOffset()); + codeStyleManager.reformatNewlyAddedElement(comment.getNode().getTreeParent(), comment.getNode()); + PsiComment result = PsiTreeUtil.getNonStrictParentOfType(psiFile.findElementAt(commentMarker.getStartOffset()), PsiComment.class); + commentMarker.dispose(); + return result; + } + + /// @return The [CodeDocumentationProvider] for the given [Language], if any + @ApiStatus.Internal + public static @Nullable CodeDocumentationProvider getCodeProvider(Language language) { + final DocumentationProvider langDocumentationProvider = + LanguageDocumentation.INSTANCE.forLanguage(language); + + if (langDocumentationProvider instanceof CompositeDocumentationProvider) { + return ((CompositeDocumentationProvider)langDocumentationProvider).getFirstCodeDocumentationProvider(); + } + return langDocumentationProvider instanceof CodeDocumentationProvider ? + (CodeDocumentationProvider)langDocumentationProvider : null; + } + + /// @return The prefered line prefix type (for the given comment), or `null` if the language commenter is not code aware + @ApiStatus.Internal + public static @Nullable CharSequence preferredDocumentationLinePrefix(@NotNull PsiFile file, @Nullable PsiDocCommentBase comment) { + Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(file.getLanguage()); + if (commenter instanceof CodeDocumentationAwareCommenter docCommenter) { + if (comment == null) { + return CodeStyle.getLanguageSettings(file).DOCUMENTATION_LINE_COMMENT_PREFERRED + ? docCommenter.getDocumentationLineCommentPrefix() + : docCommenter.getDocumentationCommentLinePrefix(); + } + return docCommenter.isDocumentationLineComment(comment) + ? comment.getFirstChild().getText() // Assume the first psi element contains the prefix + : docCommenter.getDocumentationCommentLinePrefix(); + } + + return null; + } + /** * Utility class that contains information about current comment context. */ diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java index 77d2faf49cb2..cf7d290bb004 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java @@ -28,6 +28,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiDocCommentBase; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -40,6 +41,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Objects; + /** * Creates documentation comment for the current context if it's not created yet (e.g. the caret is inside a method which * doesn't have a doc comment). @@ -182,6 +185,7 @@ public final class FixDocCommentAction extends EditorAction { @NotNull CodeDocumentationProvider documentationProvider, @NotNull CodeDocumentationAwareCommenter commenter, @NotNull Project project) { + PsiFile anchorFile = anchor.getContainingFile(); Document document = anchor.getContainingFile().getFileDocument(); int commentStartOffset = anchor.getTextRange().getStartOffset(); int lineStartOffset = document.getLineStartOffset(document.getLineNumber(commentStartOffset)); @@ -201,24 +205,31 @@ public final class FixDocCommentAction extends EditorAction { int commentBodyRelativeOffset = 0; int caretLineOffset = 0; StringBuilder buffer = new StringBuilder(); - String commentPrefix = commenter.getDocumentationCommentPrefix(); - if (commentPrefix != null) { - buffer.append(commentPrefix).append("\n"); - caretLineOffset++; - commentBodyRelativeOffset += commentPrefix.length() + 1; - } - String linePrefix = commenter.getDocumentationCommentLinePrefix(); - if (linePrefix != null) { - buffer.append(linePrefix); - commentBodyRelativeOffset += linePrefix.length(); + if (preferDocumentationLineComment(anchorFile, null)) { + buffer.append(commenter.getDocumentationLineCommentPrefix()).append("\n"); + commentBodyRelativeOffset += Objects.requireNonNull(commenter.getDocumentationLineCommentPrefix()).length() + 1; } - buffer.append("\n"); - commentBodyRelativeOffset++; + else { + String commentPrefix = commenter.getDocumentationCommentPrefix(); + if (commentPrefix != null) { + buffer.append(commentPrefix).append("\n"); + caretLineOffset++; + commentBodyRelativeOffset += commentPrefix.length() + 1; + } - String commentSuffix = commenter.getDocumentationCommentSuffix(); - if (commentSuffix != null) { - buffer.append(commentSuffix).append("\n"); + String linePrefix = commenter.getDocumentationCommentLinePrefix(); + if (linePrefix != null) { + buffer.append(linePrefix); + commentBodyRelativeOffset += linePrefix.length(); + } + buffer.append("\n"); + commentBodyRelativeOffset++; + + String commentSuffix = commenter.getDocumentationCommentSuffix(); + if (commentSuffix != null) { + buffer.append(commentSuffix).append("\n"); + } } if (buffer.length() <= 0) { @@ -299,4 +310,20 @@ public final class FixDocCommentAction extends EditorAction { } return result; } + + /// @param file The file being worked on. Useful to retrieve the settings. + /// @param comment A comment possibly targeted by an action. + /// @return `true` if the language/comment prefers/id **line** documentation comments + /// over **block** documentation comments. + public static boolean preferDocumentationLineComment(@NotNull PsiFile file, @Nullable PsiDocCommentBase comment) { + Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(file.getLanguage()); + if (commenter instanceof CodeDocumentationAwareCommenter docCommenter) { + if (comment == null) { + return CodeStyle.getLanguageSettings(file).DOCUMENTATION_LINE_COMMENT_PREFERRED; + } + return docCommenter.isDocumentationLineComment(comment); + } + // Can't guess + return false; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java index f7ca546f2050..8becad9ef2a1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java @@ -580,13 +580,13 @@ public final class GroovyDocumentationProvider implements CodeDocumentationProvi final PsiType returnType = method.getInferredReturnType(); if ((returnType != null || method.getModifierList().hasModifierProperty(GrModifier.DEF)) && !PsiTypes.voidType().equals(returnType)) { - builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, contextComment.getContainingFile(), commenter)); + builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, contextComment, commenter)); builder.append(LINE_SEPARATOR); } final PsiClassType[] references = method.getThrowsList().getReferencedTypes(); for (PsiClassType reference : references) { - builder.append(CodeDocumentationUtil.createDocCommentLine(THROWS_TAG, contextComment.getContainingFile(), commenter)); + builder.append(CodeDocumentationUtil.createDocCommentLine(THROWS_TAG, contextComment, commenter)); builder.append(reference.getClassName()); builder.append(LINE_SEPARATOR); } @@ -594,7 +594,7 @@ public final class GroovyDocumentationProvider implements CodeDocumentationProvi else if (owner instanceof GrTypeDefinition) { final PsiTypeParameterList typeParameterList = ((PsiClass)owner).getTypeParameterList(); if (typeParameterList != null) { - JavaDocumentationProvider.createTypeParamsListComment(builder, commenter, typeParameterList); + JavaDocumentationProvider.createTypeParamsListComment(builder, commenter, typeParameterList, contextComment); } } return !builder.isEmpty() ? builder.toString() : null;