javadoc: include all throws unchecked exceptions from all super methods (IDEA-152938)

This commit is contained in:
Anna Kozlova
2017-05-15 15:06:45 +03:00
parent 4e25ba1b33
commit d634c51afe
5 changed files with 60 additions and 9 deletions

View File

@@ -15,10 +15,7 @@
*/
package com.intellij.codeInsight.javadoc;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInsight.*;
import com.intellij.codeInsight.documentation.DocumentationManagerProtocol;
import com.intellij.codeInsight.documentation.DocumentationManagerUtil;
import com.intellij.javadoc.JavadocGeneratorRunProfile;
@@ -1723,11 +1720,36 @@ public class JavaDocInfoGenerator {
private void generateThrowsSection(StringBuilder buffer, PsiMethod method, PsiDocComment comment) {
PsiDocTag[] localTags = getThrowsTags(comment);
PsiDocTag[] thrownTags = localTags;
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(method.getProject());
Set<PsiClass> reported = new HashSet<>();
for (HierarchicalMethodSignature signature : method.getHierarchicalMethodSignature().getSuperSignatures()) {
PsiMethod superMethod = ObjectUtils.tryCast(signature.getMethod().getNavigationElement(), PsiMethod.class);
PsiDocComment docComment = superMethod != null ? superMethod.getDocComment() : null;
if (docComment != null) {
PsiDocTag[] uncheckedExceptions = Arrays.stream(getThrowsTags(docComment)).filter(tag -> {
PsiDocTagValue valueElement = tag.getValueElement();
if (valueElement == null) return false;
if (Arrays.stream(localTags)
.map(PsiDocTag::getValueElement)
.map(ObjectUtils::notNull)
.anyMatch(docTagValue -> areWeakEqual(docTagValue.getText(), valueElement.getText()))) {
return false;
}
PsiClass exClass = psiFacade.getResolveHelper().resolveReferencedClass(valueElement.getText(), docComment);
if (exClass == null) return false;
return ExceptionUtil.isUncheckedException(exClass) && reported.add(exClass);
}).toArray(PsiDocTag[]::new);
thrownTags = ArrayUtil.mergeArrays(thrownTags, uncheckedExceptions);
}
}
LinkedList<Pair<PsiDocTag, InheritDocProvider<PsiDocTag>>> collectedTags = new LinkedList<>();
List<PsiClassType> declaredThrows = new ArrayList<>(Arrays.asList(method.getThrowsList().getReferencedTypes()));
for (int i = localTags.length - 1; i > -1; i--) {
PsiDocTagValue valueElement = localTags[i].getValueElement();
for (int i = thrownTags.length - 1; i > -1; i--) {
PsiDocTagValue valueElement = thrownTags[i].getValueElement();
if (valueElement != null) {
for (Iterator<PsiClassType> iterator = declaredThrows.iterator(); iterator.hasNext();) {
@@ -1740,7 +1762,7 @@ public class JavaDocInfoGenerator {
}
Pair<PsiDocTag, InheritDocProvider<PsiDocTag>> tag = findInheritDocTag(method, exceptionLocator(valueElement.getText()));
collectedTags.addFirst(new Pair<>(localTags[i], new InheritDocProvider<PsiDocTag>() {
collectedTags.addFirst(new Pair<>(thrownTags[i], new InheritDocProvider<PsiDocTag>() {
@Override
public Pair<PsiDocTag, InheritDocProvider<PsiDocTag>> getInheritDoc() {
return tag;
@@ -1759,7 +1781,7 @@ public class JavaDocInfoGenerator {
String paramName = trouser.getCanonicalText();
Pair<PsiDocTag, InheritDocProvider<PsiDocTag>> parmTag = null;
for (PsiDocTag localTag : localTags) {
for (PsiDocTag localTag : thrownTags) {
PsiDocTagValue value = localTag.getValueElement();
if (value != null) {
String tagName = value.getText();
@@ -1779,7 +1801,7 @@ public class JavaDocInfoGenerator {
}
else {
try {
PsiDocTag tag = JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createDocTagFromText("@exception " + paramName);
PsiDocTag tag = psiFacade.getElementFactory().createDocTagFromText("@exception " + paramName);
collectedTags.addLast(Pair.create(tag, ourEmptyProvider));
}
catch (IncorrectOperationException e) {

View File

@@ -705,6 +705,11 @@ public class ExceptionUtil {
return InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION) || InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_ERROR);
}
public static boolean isUncheckedException(@NotNull PsiClass psiClass) {
return InheritanceUtil.isInheritor(psiClass, CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION) ||
InheritanceUtil.isInheritor(psiClass, CommonClassNames.JAVA_LANG_ERROR);
}
public static boolean isUncheckedExceptionOrSuperclass(@NotNull final PsiClassType type) {
return isGeneralExceptionType(type) || isUncheckedException(type);
}

View File

@@ -0,0 +1,7 @@
<html><head><base href="placeholder"> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><small><b><a href="psi_element://java.util.Collection"><code>java.util.Collection</code></a></b></small><PRE>public abstract&nbsp;boolean&nbsp;<b>contains</b>(<a href="psi_element://java.lang.Object"><code>Object</code></a>&nbsp;o)</PRE>
Returns <tt>true</tt> if this collection contains the specified
element. More formally, returns <tt>true</tt> if and only if this
collection contains at least one element <tt>e</tt> such that
<tt>(o==null ? e==null : o.equals(e))</tt>.
<DD><DL><DT><b>Parameters:</b><DD><code>o</code> - element whose presence in this collection is to be tested. </DD></DL></DD><DD><DL><DT><b>Returns:</b><DD><tt>true</tt> if this collection contains the specified element </DD></DL></DD><DD><DL><DT><b>Throws:</b><DD><a href="psi_element://java.lang.ClassCastException"><code>ClassCastException</code></a> - if the type of the specified element is incompatible with this collection (optional). <DD><a href="psi_element://java.lang.NullPointerException"><code>NullPointerException</code></a> - if the specified element is null and this collection does not support null elements (optional).</DD></DL></DD></body></html>

View File

@@ -0,0 +1,13 @@
interface I {
/**
* @throws NullPointerException blah-blah
*/
boolean contains(Object o) {}
}
interface My extends java.util.Collection, I {}
class C {
{
My m = null;
m.<caret>contains(null);
}
}

View File

@@ -401,6 +401,10 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase {
doTestAtCaret();
}
public void testDocumentationForUncheckedExceptionsInSupers() throws Exception {
doTestAtCaret();
}
public void testDumbMode() throws Exception {
DumbServiceImpl.getInstance(myProject).setDumb(true);
try {