diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index c644972454e7..cc71ed9e6511 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -544,7 +544,10 @@ public class JavaDocInfoGenerator { } public boolean generateDocInfoCore(StringBuilder buffer, boolean generatePrologue) { - if (myElement instanceof PsiClass cls) { + if (myElement instanceof PsiTypeParameter parameter) { + generateTypeParameterJavaDoc(buffer, parameter, generatePrologue); + } + else if (myElement instanceof PsiClass cls) { generateClassJavaDoc(buffer, cls, generatePrologue); } else if (myElement instanceof PsiMethod method) { @@ -834,6 +837,33 @@ public class JavaDocInfoGenerator { buffer.append(DocumentationMarkup.SECTIONS_END); } + private void generateTypeParameterJavaDoc(StringBuilder buffer, PsiTypeParameter parameter, boolean generatePrologue) { + if (parameter instanceof PsiAnonymousClass) return; + + if (generatePrologue) generatePrologue(buffer); + + if (!isRendered()) { + buffer.append(DocumentationMarkup.DEFINITION_START); + generateTypeParameterSignature(buffer, parameter, SignaturePlace.Javadoc); + buffer.append(DocumentationMarkup.DEFINITION_END); + } + + if (parameter.getOwner() instanceof PsiJavaDocumentedElement documentedElement) { + final PsiDocComment docComment = getDocComment(documentedElement); + PsiDocTag[] localTags = docComment != null ? docComment.getTags() : PsiDocTag.EMPTY_ARRAY; + PsiDocTag tag = getTagByName(localTags, "<" + parameter.getName() + ">"); + if (tag != null) { + buffer.append("

"); + final PsiElement[] elements = Arrays.stream(tag.getChildren()) + .skip(1) + .filter(e -> e.getNode().getElementType() != JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS && + e.getNode().getElementType() != JavaDocElementType.DOC_PARAMETER_REF) + .toArray(PsiElement[]::new); + generateValue(buffer, elements, ourEmptyElementsProvider); + } + } + } + private void generateRecordParametersSection(StringBuilder buffer, PsiClass recordClass, PsiDocComment comment) { if (!recordClass.isRecord() || comment == null) return; PsiDocTag[] localTags = comment.findTagsByName("param"); @@ -899,6 +929,19 @@ public class JavaDocInfoGenerator { return false; } + private void generateTypeParameterSignature(StringBuilder buffer, PsiTypeParameter parameter, SignaturePlace place) { + boolean generateLink = place == SignaturePlace.Javadoc; + + appendPlainText(buffer, generateOneTypeParameterPresentableName(parameter)); + + buffer.append('\n'); + + PsiClassType[] refs = parameter.getExtendsListTypes(); + if (refs.length > 0) { + generateRefList(buffer, parameter, generateLink, refs, "extends"); + } + } + private void generateRefList(StringBuilder buffer, PsiClass aClass, boolean generateLink, PsiClassType[] refs, String keyword) { appendStyledSpan(buffer, getHighlightingManager().getKeywordAttributes(), keyword); buffer.append(" "); diff --git a/java/java-tests/testData/codeInsight/javadocIG/classTypeParameter2.html b/java/java-tests/testData/codeInsight/javadocIG/classTypeParameter2.html new file mode 100644 index 000000000000..c5126116cd44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/classTypeParameter2.html @@ -0,0 +1,2 @@ +

<T>
+extends Runnable

param description

\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/classTypeParameter2.java b/java/java-tests/testData/codeInsight/javadocIG/classTypeParameter2.java new file mode 100644 index 000000000000..969a67f1b569 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/classTypeParameter2.java @@ -0,0 +1,6 @@ +/** + * @param param description + */ +class MethodTypeParam<T extends Runnable, K extends String> { + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/methodTypeParameter2.html b/java/java-tests/testData/codeInsight/javadocIG/methodTypeParameter2.html new file mode 100644 index 000000000000..cbf207265ea0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/methodTypeParameter2.html @@ -0,0 +1,2 @@ +
<T>
+

type param

\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/methodTypeParameter2.java b/java/java-tests/testData/codeInsight/javadocIG/methodTypeParameter2.java new file mode 100644 index 000000000000..2f9fee6f99c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/methodTypeParameter2.java @@ -0,0 +1,7 @@ +class MethodTypeParam2 { + /** + * @param type param + */ + <T> void foo(T t) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/paramInMethod.html b/java/java-tests/testData/codeInsight/javadocIG/paramInMethod.html new file mode 100644 index 000000000000..cd613f4503d9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/paramInMethod.html @@ -0,0 +1,2 @@ +
<T>
+

parameter

\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/paramInMethod.java b/java/java-tests/testData/codeInsight/javadocIG/paramInMethod.java new file mode 100644 index 000000000000..689f2450e46c --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/paramInMethod.java @@ -0,0 +1,6 @@ +class C { + /** + * @param parameter + */ + void m(T i) {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavaDocInfoGeneratorTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavaDocInfoGeneratorTest.java index 088b0bf8bea1..d4ab2b14b428 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavaDocInfoGeneratorTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/javadoc/JavaDocInfoGeneratorTest.java @@ -77,11 +77,13 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase { public void testEscapingStringValue() { doTestMethod(); } public void testIdeadev2326() { doTestMethod(); } public void testMethodTypeParameter() { doTestMethod(); } + public void testMethodTypeParameter2() { doTestAtCaret(); } public void testInheritedDocInThrows() { doTestMethod(); } public void testInheritedDocInThrows1() { doTestMethod(); } public void testEscapeValues() { doTestClass(); } public void testClassTypeParameter() { doTestClass(); } public void testClassTypeParameter1() { doTestClass(); } + public void testClassTypeParameter2() { doTestAtCaret(); } public void testUnicodeEscapes() { doTestClass(); } public void testEnumValueOf() { doTestMethod(); } public void testMethodFormatting() { doTestMethod(); } @@ -119,6 +121,7 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase { public void testDocumentationForUncheckedExceptionsInSupers() { doTestAtCaret(); } public void testDocumentationForGetterByField() { doTestAtCaret(); } public void testParamInJavadoc() { doTestAtCaret(); } + public void testParamInMethod() { doTestAtCaret(); } public void testExternalLinksInJavadoc() { doTestAtCaret(); } public void testLiteralInsideCode() { useJava8(); doTestClass(); } public void testSuperJavadocExactResolve() { doTestAtCaret(); }