mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Type annotations in quick-doc (IDEA-230655)
GitOrigin-RevId: e108b4f4344981ee58ab8fe460cba3f0c5f4e834
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b0d9f51d6a
commit
c957650096
@@ -1,18 +1,19 @@
|
||||
// Copyright 2000-2019 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.codeInsight.javadoc;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationTargetUtil;
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.intellij.lang.annotations.Flow;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -21,14 +22,16 @@ public class AnnotationDocGenerator {
|
||||
private static final Logger LOG = Logger.getInstance(AnnotationDocGenerator.class);
|
||||
@NotNull private final PsiAnnotation myAnnotation;
|
||||
@NotNull private final PsiJavaCodeReferenceElement myNameReference;
|
||||
@NotNull private final PsiModifierListOwner myOwner;
|
||||
@NotNull private final PsiElement myContext;
|
||||
@Nullable private final PsiClass myTargetClass;
|
||||
private final boolean myResolveNotPossible;
|
||||
|
||||
private AnnotationDocGenerator(@NotNull PsiAnnotation annotation, @NotNull PsiJavaCodeReferenceElement nameReference, @NotNull PsiModifierListOwner owner) {
|
||||
myAnnotation = annotation;
|
||||
myNameReference = nameReference;
|
||||
myOwner = owner;
|
||||
private AnnotationDocGenerator(@NotNull PsiAnnotation annotation,
|
||||
@NotNull PsiJavaCodeReferenceElement nameReference,
|
||||
@NotNull PsiElement context) {
|
||||
myAnnotation = annotation;
|
||||
myNameReference = nameReference;
|
||||
myContext = context;
|
||||
|
||||
boolean indexNotReady = false;
|
||||
PsiElement target = null;
|
||||
@@ -65,16 +68,12 @@ public class AnnotationDocGenerator {
|
||||
return AnnotationUtil.isInferredAnnotation(myAnnotation);
|
||||
}
|
||||
|
||||
public boolean isInferredFromSource() {
|
||||
return isInferred() && !(PsiUtil.preferCompiledElement(myOwner) instanceof PsiCompiledElement);
|
||||
}
|
||||
|
||||
void generateAnnotation(StringBuilder buffer, AnnotationFormat format) {
|
||||
String qualifiedName = myAnnotation.getQualifiedName();
|
||||
PsiClassType type =
|
||||
myTargetClass != null && qualifiedName != null && JavaDocUtil.findReferenceTarget(myOwner.getManager(), qualifiedName, myOwner) != null
|
||||
? JavaPsiFacade.getElementFactory(myOwner.getProject()).createType(myTargetClass, PsiSubstitutor.EMPTY)
|
||||
: null;
|
||||
PsiClassType type = myTargetClass != null && qualifiedName != null &&
|
||||
JavaDocUtil.findReferenceTarget(myContext.getManager(), qualifiedName, myContext) != null
|
||||
? JavaPsiFacade.getElementFactory(myContext.getProject()).createType(myTargetClass, PsiSubstitutor.EMPTY)
|
||||
: null;
|
||||
|
||||
boolean red = type == null && !myResolveNotPossible && !isInferred() && !isExternal();
|
||||
|
||||
@@ -169,25 +168,37 @@ public class AnnotationDocGenerator {
|
||||
|
||||
buffer.append(XmlStringUtil.escapeString(memberValue.getText()));
|
||||
}
|
||||
|
||||
public static List<AnnotationDocGenerator> getAnnotationsToShow(@NotNull PsiAnnotationOwner owner, @NotNull PsiElement context) {
|
||||
if (owner instanceof PsiModifierList) {
|
||||
return getAnnotationsToShow(((PsiModifierListOwner)((PsiModifierList)owner).getParent()));
|
||||
}
|
||||
Set<String> shownAnnotations = new HashSet<>();
|
||||
return ContainerUtil.mapNotNull(owner.getAnnotations(),
|
||||
annotation -> forAnnotation(context, shownAnnotations, annotation));
|
||||
}
|
||||
|
||||
public static List<AnnotationDocGenerator> getAnnotationsToShow(@NotNull PsiModifierListOwner owner) {
|
||||
List<AnnotationDocGenerator> infos = new ArrayList<>();
|
||||
|
||||
Set<String> shownAnnotations = new HashSet<>();
|
||||
return StreamEx.of(AnnotationUtil.getAllAnnotations(owner, false, null))
|
||||
.filter(owner instanceof PsiClass || owner instanceof PsiJavaModule ? anno -> true
|
||||
: anno -> !AnnotationTargetUtil.isTypeAnnotation(anno))
|
||||
.map(annotation -> forAnnotation(owner, shownAnnotations, annotation))
|
||||
.nonNull()
|
||||
.toList();
|
||||
}
|
||||
|
||||
for (PsiAnnotation annotation : AnnotationUtil.getAllAnnotations(owner, false, null)) {
|
||||
PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
|
||||
if (nameReferenceElement == null) continue;
|
||||
private static @Nullable AnnotationDocGenerator forAnnotation(@NotNull PsiElement context,
|
||||
@NotNull Set<String> shownAnnotations,
|
||||
@NotNull PsiAnnotation annotation) {
|
||||
PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
|
||||
if (nameReferenceElement == null) return null;
|
||||
|
||||
AnnotationDocGenerator anno = new AnnotationDocGenerator(annotation, nameReferenceElement, owner);
|
||||
AnnotationDocGenerator anno = new AnnotationDocGenerator(annotation, nameReferenceElement, context);
|
||||
if (anno.isNonDocumentedAnnotation()) return null;
|
||||
|
||||
if (anno.isNonDocumentedAnnotation()) continue;
|
||||
|
||||
if (!(shownAnnotations.add(annotation.getQualifiedName()) || JavaDocInfoGenerator.isRepeatableAnnotationType(annotation))) continue;
|
||||
|
||||
infos.add(anno);
|
||||
}
|
||||
return infos;
|
||||
if (!(shownAnnotations.add(annotation.getQualifiedName()) || JavaDocInfoGenerator.isRepeatableAnnotationType(annotation))) return null;
|
||||
return anno;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -881,6 +881,17 @@ public class JavaDocInfoGenerator {
|
||||
return modifiers.length();
|
||||
}
|
||||
|
||||
private static void generateTypeAnnotations(StringBuilder buffer, PsiAnnotationOwner owner, PsiElement context, boolean leadingSpace) {
|
||||
List<AnnotationDocGenerator> generators = AnnotationDocGenerator.getAnnotationsToShow(owner, context);
|
||||
if (leadingSpace && !generators.isEmpty()) {
|
||||
buffer.append(NBSP);
|
||||
}
|
||||
for (AnnotationDocGenerator anno : generators) {
|
||||
anno.generateAnnotation(buffer, AnnotationFormat.JavaDocShort);
|
||||
buffer.append(NBSP);
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateAnnotations(StringBuilder buffer,
|
||||
PsiModifierListOwner owner,
|
||||
SignaturePlace place,
|
||||
@@ -1820,14 +1831,10 @@ public class JavaDocInfoGenerator {
|
||||
* @return Length of the generated label.
|
||||
*/
|
||||
public static int generateType(StringBuilder buffer, PsiType type, PsiElement context, boolean generateLink, boolean useShortNames) {
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
String text = StringUtil.escapeXmlEntities(type.getCanonicalText());
|
||||
buffer.append(text);
|
||||
return text.length();
|
||||
}
|
||||
|
||||
if (type instanceof PsiArrayType) {
|
||||
int rest = generateType(buffer, ((PsiArrayType)type).getComponentType(), context, generateLink, useShortNames);
|
||||
|
||||
generateTypeAnnotations(buffer, type, context, true);
|
||||
if (type instanceof PsiEllipsisType) {
|
||||
buffer.append("...");
|
||||
return rest + 3;
|
||||
@@ -1838,6 +1845,14 @@ public class JavaDocInfoGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
generateTypeAnnotations(buffer, type, context, false);
|
||||
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
String text = StringUtil.escapeXmlEntities(type.getCanonicalText());
|
||||
buffer.append(text);
|
||||
return text.length();
|
||||
}
|
||||
|
||||
if (type instanceof PsiCapturedWildcardType) {
|
||||
type = ((PsiCapturedWildcardType)type).getWildcard();
|
||||
}
|
||||
@@ -1982,6 +1997,8 @@ public class JavaDocInfoGenerator {
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PsiTypeParameter p = parameters[i];
|
||||
|
||||
generateTypeAnnotations(buffer, p, p, false);
|
||||
|
||||
buffer.append(p.getName());
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<html><head><base href="placeholder"></head><body><div class='definition-only'><pre><a href="psi_element://Test"><code>Test</code></a><br>public <@<a href="psi_element://Test.Foo"><code>Foo</code></a>(1) T extends @<a href="psi_element://Test.Foo"><code>Foo</code></a>(2) <a href="psi_element://java.lang.CharSequence"><code>CharSequence</code></a> & @<a href="psi_element://Test.Foo"><code>Foo</code></a>(3) <a href="psi_element://java.lang.Cloneable"><code>Cloneable</code></a>> @<a href="psi_element://Test.Foo"><code>Foo</code></a>(4) <a href="psi_element://java.util.List"><code>List</code></a><@<a href="psi_element://Test.Foo"><code>Foo</code></a>(5) ? super @<a href="psi_element://Test.Foo"><code>Foo</code></a>(6) T> <b>bar</b>()</pre></div>
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.lang.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
class Test {
|
||||
public <@Foo(1) T extends @Foo(2) CharSequence & @Foo(3) Cloneable>
|
||||
@Foo(4) List<@Foo(5) ? super @Foo(6) T> <caret>bar() {return null;}
|
||||
|
||||
@Documented
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface Foo {
|
||||
int value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<html><head><base href="placeholder"></head><body><div class='definition-only'><pre><a href="psi_element://Test"><code>Test</code></a><br>public @<a href="psi_element://Foo"><code>Foo</code></a>(1) <a href="psi_element://java.lang.String"><code>String</code></a> @<a href="psi_element://Foo"><code>Foo</code></a>(2) [] <b>foo</b>()</pre></div>
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class Test {
|
||||
public @Foo(1) String @Foo(2) @Bar [] <caret>foo(){}
|
||||
}
|
||||
@Documented
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface Foo {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface Bar {}
|
||||
@@ -0,0 +1,3 @@
|
||||
<html><head><base href="placeholder"></head><body><div class='definition'><pre>@<a href="psi_element://Foo"><code>Foo</code></a>(1)
|
||||
class <b>Test</b>
|
||||
extends @<a href="psi_element://Foo"><code>Foo</code></a>(2) <a href="psi_element://java.util.List"><code>List</code></a><@<a href="psi_element://Foo"><code>Foo</code></a>(3) <a href="psi_element://java.lang.String"><code>String</code></a>></pre></div><table class='sections'></table>
|
||||
@@ -0,0 +1,12 @@
|
||||
import java.lang.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@Foo(1)
|
||||
class Test extends @Foo(2) List<@Foo(3) String> {
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface Foo {
|
||||
int value();
|
||||
}
|
||||
+3
@@ -104,6 +104,9 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase {
|
||||
public void testPackageHtml() { doTestPackageInfo(); }
|
||||
public void testSyntheticEnumValues() { doTestAtCaret(); }
|
||||
public void testVariableDoc() { doTestAtCaret(); }
|
||||
public void testTypeAnnotation() { useJava8(); doTestAtCaret(); }
|
||||
public void testTypeAnnotationArray() { useJava8(); doTestAtCaret(); }
|
||||
public void testTypeAnnotationClass() { useJava8(); doTestClass(); }
|
||||
|
||||
public void testAnonymousAndSuperJavadoc() {
|
||||
PsiClass psiClass = PsiTreeUtil.findChildOfType(getTestClass(), PsiAnonymousClass.class);
|
||||
|
||||
Reference in New Issue
Block a user