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 fa7a896ee127..0e939455677a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -53,7 +53,6 @@ import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.javadoc.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.*; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; @@ -62,7 +61,6 @@ import com.intellij.ui.ColorUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtilRt; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.xml.util.XmlStringUtil; import kotlin.text.StringsKt; @@ -426,7 +424,7 @@ public class JavaDocInfoGenerator { LOG.debug(e); result.replace(result.length() - 6, result.length(), "wrong-href=\""); // display text instead of link } - result.append(ObjectUtils.notNull(reference, href)); + result.append(reference == null ? href : reference); lastRef = groupEnd; } } @@ -594,17 +592,13 @@ public class JavaDocInfoGenerator { if (generatePrologue) generatePrologue(buffer); generateVariableDefinition(buffer, recordComponent, true); - PsiRecordHeader recordHeader = ObjectUtils.tryCast(recordComponent.getParent(), PsiRecordHeader.class); - if (recordHeader == null) return; - PsiRecordComponent[] components = recordHeader.getRecordComponents(); - int recordIndex = ArrayUtil.indexOf(components, recordComponent); + if (!(recordComponent.getParent() instanceof PsiRecordHeader recordHeader)) return; + int recordIndex = ArrayUtil.indexOf(recordHeader.getRecordComponents(), recordComponent); PsiClass recordClass = recordComponent.getContainingClass(); if (recordClass == null) return; String recordComponentJavadoc = getRecordComponentJavadocFromParameterTag(recordIndex, recordClass); if (recordComponentJavadoc != null) { - buffer.append(DocumentationMarkup.CONTENT_START); - buffer.append(recordComponentJavadoc); - buffer.append(DocumentationMarkup.CONTENT_END); + buffer.append(DocumentationMarkup.CONTENT_START).append(recordComponentJavadoc).append(DocumentationMarkup.CONTENT_END); } } @@ -614,13 +608,10 @@ public class JavaDocInfoGenerator { String docForPattern = getDocForPattern(variable); if (docForPattern != null) { - buffer.append(DocumentationMarkup.CONTENT_START); - buffer.append(docForPattern); - buffer.append(DocumentationMarkup.CONTENT_END); + buffer.append(DocumentationMarkup.CONTENT_START).append(docForPattern).append(DocumentationMarkup.CONTENT_END); } } - private @Nullable String getDocForPattern(@NotNull PsiPatternVariable variable) { PsiPattern pattern = variable.getPattern(); PsiElement parent = pattern.getParent(); @@ -2631,8 +2622,7 @@ public class JavaDocInfoGenerator { } if (pair != null) { - startHeaderSection(buffer, CodeInsightBundle.message("javadoc.returns")) - .append("

"); + startHeaderSection(buffer, CodeInsightBundle.message("javadoc.returns")).append("

"); generateValue(buffer, pair.first.getDataElements(), mapProvider(pair.second, false)); buffer.append(DocumentationMarkup.SECTION_END); } @@ -2651,77 +2641,36 @@ public class JavaDocInfoGenerator { private void generateThrowsSection(StringBuilder buffer, PsiMethod method, PsiDocComment comment) { final PsiDocTag[] throwsJavadocTags = getThrowsTags(comment); - - final PsiJavaCodeReferenceElement[] methodThrows = isRendered() ? PsiJavaCodeReferenceElement.EMPTY_ARRAY - : method.getThrowsList().getReferenceElements(); - - final int totalThrowsToDocument = throwsJavadocTags.length + methodThrows.length; - if (totalThrowsToDocument == 0) return; - - final class Data { - final @NotNull PsiJavaCodeReferenceElement ref; - final @Nullable PsiDocTag tag; - - private Data(@NotNull PsiJavaCodeReferenceElement ref, @Nullable PsiDocTag tag) { - this.ref = ref; - this.tag = tag; - } - } - - final Map<@NotNull String, @NotNull Data> throwTags = new LinkedHashMap<>(totalThrowsToDocument, 1.0f); - - for (PsiDocTag tag : throwsJavadocTags) { - final PsiDocTagValue value = tag.getValueElement(); - if (value == null) continue; - - final ASTNode[] children = value.getNode().getChildren(TokenSet.create(JavaDocElementType.DOC_REFERENCE_HOLDER)); - if (children.length != 1) continue; - - final PsiJavaCodeReferenceElement element = ObjectUtils.tryCast(children[0].getFirstChildNode(), PsiJavaCodeReferenceElement.class); - if (element != null) { - throwTags.put(element.getQualifiedName(), new Data(element, tag)); - } - } - - Arrays.stream(methodThrows) - .filter(e -> !throwTags.containsKey(e.getQualifiedName())) - .forEach(e -> throwTags.put(e.getQualifiedName(), new Data(e, null))); - - if (throwTags.isEmpty()) return; + final PsiJavaCodeReferenceElement[] methodThrows = isRendered() + ? PsiJavaCodeReferenceElement.EMPTY_ARRAY + : method.getThrowsList().getReferenceElements(); + if (throwsJavadocTags.length + methodThrows.length == 0) return; startHeaderSection(buffer, CodeInsightBundle.message("javadoc.throws")); - - for (Map.Entry throwTag : throwTags.entrySet()) { - final Data value = throwTag.getValue(); - final PsiJavaCodeReferenceElement exceptionType = value.ref; - final PsiClass target = ObjectUtils.tryCast(exceptionType.resolve(), PsiClass.class); - final PsiDocTag tag = value.tag; + Set documentedExceptions = new HashSet<>(throwsJavadocTags.length); + for (PsiDocTag tag : throwsJavadocTags) { buffer.append("

"); - - final PsiElement[] elements = tag != null ? tag.getDataElements() : PsiElement.EMPTY_ARRAY; - - if (target != null) { + PsiElement[] dataElements = tag.getDataElements(); + if (dataElements.length == 0) continue; + PsiElement grandChild = dataElements[0].getFirstChild().getFirstChild(); + if (!(grandChild instanceof PsiJavaCodeReferenceElement reference)) continue; + if (reference.resolve() instanceof PsiClass target) { generateLink(buffer, target); } - else if (elements.length != 0) { - generateLink(buffer, elements[0].getText(), null, method, false); - } else { - generateUnresolvedLink(buffer, exceptionType); + generateLink(buffer, dataElements[0].getText(), null, method, false); } - - if (elements.length < 2) continue; + documentedExceptions.add(reference.getQualifiedName()); + if (dataElements.length < 2) continue; buffer.append(" – "); final Pair> tagToInheritDocProvider = - findInheritDocTag(method, exceptionLocator(exceptionType.getQualifiedName())); + findInheritDocTag(method, exceptionLocator(reference.getQualifiedName())); - generateValue(buffer, elements, 1, tagToInheritDocProvider == null ? null : new InheritDocProvider<>() { + generateValue(buffer, dataElements, 1, tagToInheritDocProvider == null ? null : new InheritDocProvider<>() { @Override public Pair> getInheritDoc() { - final PsiElement[] docElements = tagToInheritDocProvider.first.getDataElements(); - - final PsiElement[] result = Arrays.stream(docElements) + final PsiElement[] result = Arrays.stream(tagToInheritDocProvider.first.getDataElements()) .skip(1) .toArray(PsiElement[]::new); @@ -2734,25 +2683,22 @@ public class JavaDocInfoGenerator { } }); } + for (PsiJavaCodeReferenceElement exception : methodThrows) { + if (documentedExceptions.contains(exception.getQualifiedName())) continue; + buffer.append("

"); + if (exception.resolve() instanceof PsiClass target) generateLink(buffer, target); + else generateLink(buffer, exception.getText(), null, method, false); + } buffer.append(DocumentationMarkup.SECTION_END); } - private void generateUnresolvedLink(StringBuilder buffer, @NotNull PsiJavaCodeReferenceElement exceptionType) { - final String label = JavaDocUtil.getLabelText(exceptionType.getProject(), - exceptionType.getManager(), - exceptionType.getQualifiedName(), - exceptionType); - appendMaybeUnresolvedLink(buffer, null, label, myProject, false); - } - @Contract(mutates = "param1") private void generateLink(@NotNull StringBuilder buffer, @NotNull PsiClass target) { final String label = JavaDocUtil.getLabelText(target.getProject(), target.getManager(), target.getName(), target); appendMaybeUnresolvedLink(buffer, target, label, target.getProject(), false); } - private static @Nullable @NlsSafe String generateLink(@NotNull PsiElement element, - String label) { + private static @Nullable @NlsSafe String generateLink(@NotNull PsiElement element, String label) { String refText = JavaDocUtil.getReferenceText(element.getProject(), element); if (refText != null) { StringBuilder linkBuilder = new StringBuilder(); diff --git a/java/java-tests/testData/codeInsight/javadocIG/multipleThrowsSameType.html b/java/java-tests/testData/codeInsight/javadocIG/multipleThrowsSameType.html new file mode 100644 index 000000000000..0130e00e2b62 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/multipleThrowsSameType.html @@ -0,0 +1,2 @@ +

 A
public void method(
int a, + int b
)

Throws:

IllegalArgumentException – if a is negative

IllegalArgumentException – if b is negative

\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/multipleThrowsSameType.java b/java/java-tests/testData/codeInsight/javadocIG/multipleThrowsSameType.java new file mode 100644 index 000000000000..5ea76594a57c --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/multipleThrowsSameType.java @@ -0,0 +1,7 @@ +class A { + /** + * @throws java.lang.IllegalArgumentException if a is negative + * @throws java.lang.IllegalArgumentException if b is negative + */ + public void method(int a, int b) {} +} \ 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 8497b42fd796..c2656f06e0e2 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInsight.javadoc; import com.intellij.JavaTestUtil; @@ -81,6 +81,7 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase { public void testMethodTypeParameter3() { doTestAtCaret(); } public void testInheritedDocInThrows() { doTestMethod(); } public void testInheritedDocInThrows1() { doTestMethod(); } + public void testMultipleThrowsSameType() { doTestMethod(); } public void testEscapeValues() { doTestClass(); } public void testClassTypeParameter() { doTestClass(); } public void testClassTypeParameter1() { doTestClass(); }