IDEA-169520 Flow annotations visible in Collections interface methods

This commit is contained in:
peter
2017-03-20 17:09:05 +01:00
parent 0a889aa880
commit ea75860ac8
7 changed files with 98 additions and 53 deletions
@@ -486,7 +486,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
if (element != null) {
final PsiElement resolved = element.resolve();
if (resolved instanceof PsiClass &&
(!JavaDocInfoGenerator.isDocumentedAnnotationType(resolved) ||
(!JavaDocInfoGenerator.isDocumentedAnnotationType((PsiClass)resolved) ||
AnnotationTargetUtil.findAnnotationTarget((PsiClass)resolved, PsiAnnotation.TargetType.TYPE_USE) != null)) {
continue;
}
@@ -55,6 +55,7 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.intellij.lang.annotations.Flow;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
@@ -908,6 +909,8 @@ public class JavaDocInfoGenerator {
final PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
if (nameReferenceElement == null) continue;
final PsiElement resolved = nameReferenceElement.resolve();
if (isNonDocumentedAnnotation(annotation, resolved)) continue;
boolean inferred = AnnotationUtil.isInferredAnnotation(annotation);
String qualifiedName = annotation.getQualifiedName();
if (!(shownAnnotations.add(qualifiedName) || isRepeatableAnnotationType(resolved))) {
@@ -917,50 +920,18 @@ public class JavaDocInfoGenerator {
if (resolved instanceof PsiClass &&
qualifiedName != null && JavaDocUtil.findReferenceTarget(owner.getManager(), qualifiedName, owner) != null) {
final PsiClass annotationType = (PsiClass)resolved;
if (isDocumentedAnnotationType(annotationType)) {
if (inferred) buffer.append("<i>");
final PsiClassType type = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(annotationType, PsiSubstitutor.EMPTY);
buffer.append("@");
if (inferred && !generateLink) {
buffer.append(type.getPresentableText());
}
else {
generateType(buffer, type, owner, generateLink, useShortNames && !external);
}
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length > 0) {
buffer.append("(");
boolean first = true;
for (PsiNameValuePair pair : attributes) {
if (!first) buffer.append(",&nbsp;");
first = false;
final String name = pair.getName();
if (name != null) {
buffer.append(name);
buffer.append(" = ");
}
final PsiAnnotationMemberValue value = pair.getValue();
if (value != null) {
if (value instanceof PsiArrayInitializerMemberValue) {
buffer.append("{");
boolean firstMember = true;
for(PsiAnnotationMemberValue memberValue:((PsiArrayInitializerMemberValue)value).getInitializers()) {
if (!firstMember) buffer.append(",");
firstMember = false;
appendLinkOrText(buffer, memberValue, generateLink);
}
buffer.append("}");
}
else {
appendLinkOrText(buffer, value, generateLink);
}
}
}
buffer.append(")");
}
if (inferred) buffer.append("</i>");
buffer.append("&nbsp;");
if (inferred) buffer.append("<i>");
final PsiClassType type = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(annotationType, PsiSubstitutor.EMPTY);
buffer.append("@");
if (inferred && !generateLink) {
buffer.append(type.getPresentableText());
}
else {
generateType(buffer, type, owner, generateLink, useShortNames && !external);
}
generateAnnotationAttributes(buffer, generateLink, annotation);
if (inferred) buffer.append("</i>");
buffer.append("&nbsp;");
}
else if (external) {
if (inferred) buffer.append("<i>");
@@ -980,6 +951,45 @@ public class JavaDocInfoGenerator {
}
}
private static void generateAnnotationAttributes(StringBuilder buffer, boolean generateLink, PsiAnnotation annotation) {
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length > 0) {
buffer.append("(");
boolean first = true;
for (PsiNameValuePair pair : attributes) {
if (!first) buffer.append(",&nbsp;");
first = false;
generateAnnotationAttribute(buffer, generateLink, pair);
}
buffer.append(")");
}
}
private static void generateAnnotationAttribute(StringBuilder buffer, boolean generateLink, PsiNameValuePair pair) {
final String name = pair.getName();
if (name != null) {
buffer.append(name);
buffer.append(" = ");
}
final PsiAnnotationMemberValue value = pair.getValue();
if (value != null) {
if (value instanceof PsiArrayInitializerMemberValue) {
buffer.append("{");
boolean firstMember = true;
for(PsiAnnotationMemberValue memberValue:((PsiArrayInitializerMemberValue)value).getInitializers()) {
if (!firstMember) buffer.append(",");
firstMember = false;
appendLinkOrText(buffer, memberValue, generateLink);
}
buffer.append("}");
}
else {
appendLinkOrText(buffer, value, generateLink);
}
}
}
private static void appendLinkOrText(StringBuilder buffer,
PsiAnnotationMemberValue memberValue,
boolean generateLink) {
@@ -1006,8 +1016,18 @@ public class JavaDocInfoGenerator {
buffer.append(XmlStringUtil.escapeString(memberValue.getText()));
}
public static boolean isDocumentedAnnotationType(@Nullable PsiElement annotationType) {
return annotationType instanceof PsiClass && AnnotationUtil.isAnnotated((PsiClass)annotationType, "java.lang.annotation.Documented", false);
private static boolean isNonDocumentedAnnotation(@NotNull PsiAnnotation annotation, @Nullable PsiElement resolved) {
return resolved instanceof PsiClass
? !isDocumentedAnnotationType((PsiClass)resolved)
: isKnownNonDocumented(annotation.getQualifiedName());
}
private static boolean isKnownNonDocumented(String annoQName) {
return Flow.class.getName().equals(annoQName);
}
public static boolean isDocumentedAnnotationType(@NotNull PsiClass resolved) {
return AnnotationUtil.isAnnotated(resolved, "java.lang.annotation.Documented", false);
}
public static boolean isRepeatableAnnotationType(@Nullable PsiElement annotationType) {
@@ -0,0 +1,2 @@
<html><head><base href="placeholder"> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><PRE>class <b>Test</b>
extends <a href="psi_element://java.lang.Object"><code>Object</code></a></PRE> <pre>abc</pre></body></html>
@@ -1,4 +1,3 @@
<html><head><base href="placeholder"> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><PRE>
public&nbsp;void&nbsp;<b>foo</b>()</PRE><DD><DL><DT><b>Description copied from interface:</b>&nbsp;<a href="psi_element://Foo"><code>Foo</code></a><br>
<html><head><base href="placeholder"> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><PRE>public&nbsp;void&nbsp;<b>foo</b>()</PRE><DD><DL><DT><b>Description copied from interface:</b>&nbsp;<a href="psi_element://Foo"><code>Foo</code></a><br>
some javadoc
</DD></DL></DD><DD><DL><DT><b>Specified by:</b><DD><a href="psi_element://Foo#foo()"><code>foo</code></a> in interface <a href="psi_element://Foo"><code>Foo</code></a></DD></DL></DD></body></html>
@@ -1,2 +1 @@
<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://Bar"><code>Bar</code></a></b></small><PRE>
void&nbsp;<b>m</b>(int&nbsp;bar)</PRE><DD><DL><DT><b>Overrides:</b><DD><a href="psi_element://Foo#m(int)"><code>m</code></a> in class <a href="psi_element://Foo"><code>Foo</code></a></DD></DL></DD><DD><DL><DT><b>Parameters:</b><DD><code>bar</code> - description</DD></DL></DD></body></html>
<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://Bar"><code>Bar</code></a></b></small><PRE>void&nbsp;<b>m</b>(int&nbsp;bar)</PRE><DD><DL><DT><b>Overrides:</b><DD><a href="psi_element://Foo#m(int)"><code>m</code></a> in class <a href="psi_element://Foo"><code>Foo</code></a></DD></DL></DD><DD><DL><DT><b>Parameters:</b><DD><code>bar</code> - description</DD></DL></DD></body></html>
@@ -1,2 +1 @@
<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://Bar"><code>Bar</code></a></b></small><PRE>
&lt;U&gt;&nbsp;void&nbsp;<b>m</b>(U&nbsp;u)</PRE><DD><DL><DT><b>Overrides:</b><DD><a href="psi_element://Foo#m(java.lang.Object)"><code>m</code></a> in class <a href="psi_element://Foo"><code>Foo</code></a></DD></DL></DD><DD><DL><DT><b>Type parameters:</b><DD><code>&lt;U&gt;</code> - description</DD></DL></DD></body></html>
<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://Bar"><code>Bar</code></a></b></small><PRE>&lt;U&gt;&nbsp;void&nbsp;<b>m</b>(U&nbsp;u)</PRE><DD><DL><DT><b>Overrides:</b><DD><a href="psi_element://Foo#m(java.lang.Object)"><code>m</code></a> in class <a href="psi_element://Foo"><code>Foo</code></a></DD></DL></DD><DD><DL><DT><b>Type parameters:</b><DD><code>&lt;U&gt;</code> - description</DD></DL></DD></body></html>
@@ -16,6 +16,7 @@
package com.intellij.codeInsight.javadoc;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightTestCase;
import com.intellij.codeInsight.JavaExternalDocumentationTest;
import com.intellij.lang.java.JavaDocumentationProvider;
@@ -23,6 +24,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
@@ -35,6 +37,8 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.lang.annotations.Flow;
import java.io.File;
import java.io.IOException;
@@ -349,7 +353,29 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase {
useJava7();
verifyJavaDoc(getTestClass());
}
public void testHideNonDocumentedFlowAnnotations() throws IOException {
ModuleRootModificationUtil.setModuleSdk(myModule, removeAnnotationsJar(PsiTestUtil.addJdkAnnotations(IdeaTestUtil.getMockJdk17())));
PsiMethod mapPut = myJavaFacade.findClass(CommonClassNames.JAVA_UTIL_MAP, GlobalSearchScope.allScope(myProject))
.findMethodsByName("put", false)[0];
PsiAnnotation annotation = AnnotationUtil.findAnnotation(mapPut, Flow.class.getName());
assertNotNull(annotation);
assertNull(annotation.getNameReferenceElement().resolve());
String doc = JavaDocumentationProvider.generateExternalJavadoc(mapPut);
assertFalse(doc, doc.contains("Flow"));
}
private static Sdk removeAnnotationsJar(Sdk sdk) {
SdkModificator modificator = sdk.getSdkModificator();
VirtualFile annotationsJar = ContainerUtil.find(modificator.getRoots(OrderRootType.CLASSES), r -> r.getName().contains("annotations"));
modificator.removeRoot(annotationsJar, OrderRootType.CLASSES);
modificator.commitChanges();
return sdk;
}
public void testMatchingParameterNameFromParent() throws Exception {
configureByFile();
PsiClass psiClass = ((PsiJavaFile)myFile).getClasses()[1];