mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-384557 [java]: PsiTypeElementImpl.getType() incorrectly applies annotations to qualified types
Merge-request: IJ-MR-188692 Merged-by: Marcin Mikosik <marcin.mikosik@jetbrains.com> GitOrigin-RevId: 566d6e92c6828472a825198af38383e304b62830
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ae32f72c59
commit
096d52cf89
+8
-3
@@ -31,9 +31,11 @@ import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.PsiTypeCastExpression
|
||||
import com.intellij.psi.PsiVariable
|
||||
import com.intellij.psi.formatter.java.MultipleFieldDeclarationHelper
|
||||
import com.intellij.psi.impl.source.PsiClassReferenceType
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.PsiElementProcessor
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.PsiTreeUtil.findChildrenOfType
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
@@ -287,10 +289,13 @@ object ExtractMethodPipeline {
|
||||
}
|
||||
|
||||
private fun withFilteredAnnotations(type: PsiType, context: PsiElement?): PsiType {
|
||||
val project = type.annotations.firstOrNull()?.project ?: return type
|
||||
val project = (type.annotations.firstOrNull() ?: (type as? PsiClassReferenceType)?.reference)?.project ?: return type
|
||||
val factory = PsiElementFactory.getInstance(project)
|
||||
val typeHolder = factory.createParameter("x", type, context)
|
||||
typeHolder.type.annotations.filterNot { it.qualifiedName in annotationsToKeep }.forEach { it.delete() }
|
||||
findChildrenOfType(typeHolder, PsiAnnotation::class.java)
|
||||
.filterNotNull()
|
||||
.filterNot { it.qualifiedName in annotationsToKeep }
|
||||
.forEach { it.delete() }
|
||||
return typeHolder.type
|
||||
}
|
||||
|
||||
@@ -317,4 +322,4 @@ object ExtractMethodPipeline {
|
||||
dataOutput = withFilteredAnnotation(extractOptions.dataOutput, extractOptions.targetClass)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,15 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaSharedImplUtil.filteringTypeAnnotationProvider;
|
||||
import static com.intellij.util.ObjectUtils.notNull;
|
||||
|
||||
public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
private final ClassReferencePointer myReference;
|
||||
/**
|
||||
* Annotations that precede qualifier if qualifier exists.
|
||||
*/
|
||||
private final @NotNull TypeAnnotationProvider myQualifierAnnotationsProvider;
|
||||
private TypeNullability myNullability = null;
|
||||
|
||||
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level) {
|
||||
@@ -51,20 +56,25 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, PsiAnnotation @NotNull [] annotations) {
|
||||
super(level, annotations);
|
||||
myReference = ClassReferencePointer.constant(reference);
|
||||
myQualifierAnnotationsProvider = TypeAnnotationProvider.EMPTY;
|
||||
}
|
||||
|
||||
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull TypeAnnotationProvider provider) {
|
||||
this(ClassReferencePointer.constant(reference), level, provider);
|
||||
this(ClassReferencePointer.constant(reference), level, provider, TypeAnnotationProvider.EMPTY);
|
||||
}
|
||||
|
||||
PsiClassReferenceType(@NotNull ClassReferencePointer reference, LanguageLevel level, @NotNull TypeAnnotationProvider provider) {
|
||||
this(reference, level, provider, null);
|
||||
PsiClassReferenceType(@NotNull ClassReferencePointer reference,
|
||||
LanguageLevel level,
|
||||
@NotNull TypeAnnotationProvider provider,
|
||||
@NotNull TypeAnnotationProvider qualifierAnnotationsProvider) {
|
||||
this(reference, level, provider, qualifierAnnotationsProvider, null);
|
||||
}
|
||||
|
||||
private PsiClassReferenceType(@NotNull ClassReferencePointer reference, LanguageLevel level, @NotNull TypeAnnotationProvider provider,
|
||||
@Nullable TypeNullability nullability) {
|
||||
@NotNull TypeAnnotationProvider qualifierAnnotationsProvider, @Nullable TypeNullability nullability) {
|
||||
super(level, provider);
|
||||
myReference = reference;
|
||||
myQualifierAnnotationsProvider = qualifierAnnotationsProvider;
|
||||
myNullability = nullability;
|
||||
}
|
||||
|
||||
@@ -86,6 +96,9 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
for (PsiAnnotation annotation : getAnnotations(false)) {
|
||||
if (!annotation.isValid()) return false;
|
||||
}
|
||||
for (PsiAnnotation annotation : myQualifierAnnotationsProvider.getAnnotations()) {
|
||||
if (!annotation.isValid()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -165,7 +178,16 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
@Override
|
||||
public @NotNull PsiClassType withNullability(@NotNull TypeNullability nullability) {
|
||||
if (myNullability == nullability) return this;
|
||||
return new PsiClassReferenceType(myReference, myLanguageLevel, getAnnotationProvider(), nullability);
|
||||
return new PsiClassReferenceType(myReference, myLanguageLevel, getAnnotationProvider(), myQualifierAnnotationsProvider, nullability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this PsiClassReferenceType with annotations from qualifierAnnotations parameter,
|
||||
* which target is {@link PsiAnnotation.TargetType#TYPE_USE}, added to qualifier annotations.
|
||||
*/
|
||||
public @NotNull PsiClassReferenceType withAddedQualifierAnnotations(@NotNull PsiAnnotation @NotNull [] qualifierAnnotations) {
|
||||
TypeAnnotationProvider merged = filteringTypeAnnotationProvider(qualifierAnnotations, myQualifierAnnotationsProvider);
|
||||
return new PsiClassReferenceType(myReference, myLanguageLevel, getAnnotationProvider(), merged, myNullability);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -310,7 +332,7 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
PsiElement qualifier = ref.getQualifier();
|
||||
String qualifierInfo = "";
|
||||
if (qualifier != null) {
|
||||
PsiAnnotation[] qualifierAnnotations = getAnnotations(false);
|
||||
PsiAnnotation[] qualifierAnnotations = myQualifierAnnotationsProvider.getAnnotations();
|
||||
if (qualifierAnnotations.length > 0 && qualifier instanceof PsiJavaCodeReferenceElement &&
|
||||
((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiClass) {
|
||||
// Display qualifier if it's annotated
|
||||
@@ -341,7 +363,10 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
PsiJavaCodeReferenceElement reference = getReference();
|
||||
if (reference instanceof PsiAnnotatedJavaCodeReferenceElement) {
|
||||
PsiAnnotatedJavaCodeReferenceElement ref = (PsiAnnotatedJavaCodeReferenceElement)reference;
|
||||
PsiAnnotation[] annotations = annotated ? getAnnotations(false) : PsiAnnotation.EMPTY_ARRAY;
|
||||
PsiAnnotation[] annotations =
|
||||
annotated
|
||||
? ArrayUtil.mergeArrays(getAnnotations(false), myQualifierAnnotationsProvider.getAnnotations())
|
||||
: PsiAnnotation.EMPTY_ARRAY;
|
||||
return ref.getCanonicalText(annotated, annotations.length == 0 ? null : annotations);
|
||||
}
|
||||
return reference.getCanonicalText();
|
||||
|
||||
@@ -147,7 +147,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
}
|
||||
else if (child instanceof PsiJavaCodeReferenceElement) {
|
||||
assert type == null : this;
|
||||
type = new PsiClassReferenceType(getReferenceComputable((PsiJavaCodeReferenceElement)child), null, createProvider(annotations));
|
||||
type = getPsiClassReferenceType((PsiJavaCodeReferenceElement)child, createProvider(annotations));
|
||||
}
|
||||
else if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET)) {
|
||||
assert type != null : this;
|
||||
@@ -222,6 +222,12 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
if (modifierList == null) return type;
|
||||
PsiAnnotation[] annotations = modifierList.getAnnotations();
|
||||
if (annotations.length == 0) return type;
|
||||
if (type instanceof PsiClassReferenceType) {
|
||||
PsiJavaCodeReferenceElement innermost = getInnermostComponentReferenceElement();
|
||||
if (innermost != null && innermost.isQualified()) {
|
||||
return ((PsiClassReferenceType)type).withAddedQualifierAnnotations(annotations);
|
||||
}
|
||||
}
|
||||
return JavaSharedImplUtil.annotate(type, modifierList, annotations);
|
||||
}
|
||||
|
||||
@@ -235,7 +241,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
return (PsiModifierListOwner)parent;
|
||||
}
|
||||
}
|
||||
if (isDeepestComponentInsideArrayType(parent) || isFirstExceptionTypeInsideMultiCatch(parent)) {
|
||||
if (isArrayTypeElement(parent) || isFirstExceptionTypeInsideMultiCatch(parent)) {
|
||||
return ObjectUtils.tryCast(getNonDummyContext(parent), PsiModifierListOwner.class);
|
||||
}
|
||||
return null;
|
||||
@@ -256,7 +262,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
&& PsiTreeUtil.findSiblingForward(this, JavaTokenType.OR, null) != null;
|
||||
}
|
||||
|
||||
private static boolean isDeepestComponentInsideArrayType(PsiElement parent) {
|
||||
private static boolean isArrayTypeElement(PsiElement parent) {
|
||||
return parent instanceof PsiTypeElement
|
||||
&& PsiUtil.isJavaToken(parent.getLastChild(), TokenSet.create(JavaTokenType.RBRACKET, JavaTokenType.ELLIPSIS));
|
||||
}
|
||||
@@ -324,6 +330,18 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
PsiAugmentProvider.isInferredType(this);
|
||||
}
|
||||
|
||||
private static @NotNull PsiType getPsiClassReferenceType(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement,
|
||||
TypeAnnotationProvider provider) {
|
||||
if (psiJavaCodeReferenceElement.isQualified()) {
|
||||
return new PsiClassReferenceType(
|
||||
getReferenceComputable(psiJavaCodeReferenceElement), null, TypeAnnotationProvider.EMPTY, provider);
|
||||
}
|
||||
else {
|
||||
return new PsiClassReferenceType(
|
||||
getReferenceComputable(psiJavaCodeReferenceElement), null, provider, TypeAnnotationProvider.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull ClassReferencePointer getReferenceComputable(@NotNull PsiJavaCodeReferenceElement ref) {
|
||||
PsiElement parent = getAnchorParent(ref);
|
||||
if (parent instanceof PsiMethod || parent instanceof PsiVariable) {
|
||||
|
||||
@@ -286,6 +286,12 @@ public final class JavaSharedImplUtil {
|
||||
variable.addAfter(initializer, eq.getPsi());
|
||||
}
|
||||
|
||||
public static @NotNull TypeAnnotationProvider filteringTypeAnnotationProvider(@NotNull PsiAnnotation @NotNull [] candidates,
|
||||
@NotNull TypeAnnotationProvider originalProvider) {
|
||||
if (candidates.length == 0) return originalProvider;
|
||||
return new FilteringTypeAnnotationProvider(candidates, originalProvider);
|
||||
}
|
||||
|
||||
private static final class FilteringTypeAnnotationProvider implements TypeAnnotationProvider {
|
||||
private final PsiAnnotation[] myCandidates;
|
||||
private final TypeAnnotationProvider myOriginalProvider;
|
||||
|
||||
@@ -701,7 +701,7 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest {
|
||||
}
|
||||
|
||||
public void testAddReturnAnnotation() {
|
||||
doTest(null, null, "@org.jetbrains.annotations.NotNull java.lang.String", method -> new ParameterInfoImpl[0], false);
|
||||
doTest(null, null, "java.lang.@org.jetbrains.annotations.NotNull String", method -> new ParameterInfoImpl[0], false);
|
||||
}
|
||||
|
||||
public void testMultilineJavadoc() { // IDEA-281568
|
||||
|
||||
@@ -65,97 +65,128 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
}
|
||||
|
||||
private void doTestAddingAnnotationToTypeAtCaret(String classFile) {
|
||||
configureFromFileWithMyAnnotationAdded(classFile);
|
||||
configureFromFileWithAnnotationsAdded(classFile);
|
||||
PsiTypeElement typeElement = getPsiTypeElementAtCaret();
|
||||
WriteAction.run(() -> typeElement.addAnnotation("MyAnnotation"));
|
||||
assertTypeAnnotations(typeElement.getType(), "MyAnnotation");
|
||||
WriteAction.run(() -> typeElement.addAnnotation("A"));
|
||||
assertTypeAnnotations(typeElement.getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsSimpleTypeIsAppliedToThatType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>String foo() { return null; }
|
||||
@A public <T> @B <caret>String foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsNestedTypeQualifiedWithOuterTypeIsNotAppliedToNestedType() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
class Nested {}
|
||||
@A public <T> @B AClass.<caret>Nested foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsFullyQualifiedTypeIsNotAppliedToThatType() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@A public <T> @B java.lang.<caret>String foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsArrayTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>String[] foo() { return null; }
|
||||
@A public <T> @B <caret>String[] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsArrayTypeWithQualifiedComponentIsNotAppliedToArrayComponent() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@A public <T> @B java.lang.<caret>String[] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsArrayTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public String[<caret>] foo() { return null; }
|
||||
@A public <T> @B String[<caret>] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsArrayOfGenericTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>List<String>[] foo() { return null; }
|
||||
@A public <T> @B <caret>List<String>[] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsArrayOfGenericTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public List<String>[<caret>] foo() { return null; }
|
||||
@A public <T> @B List<String>[<caret>] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsMultidimensionalArrayTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>String[][][] foo() { return null; }
|
||||
@A public <T> @B <caret>String[][][] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsMultidimensionalArrayTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public String[][][<caret>] foo() { return null; }
|
||||
@A public <T> @B String[][][<caret>] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsGenericTypeIsAppliedToThatType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>List<String> foo() { return null; }
|
||||
@A public <T> @B <caret>List<String> foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsGenericTypeIsNotAppliedToThatTypeComponentType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public List< <caret>String> foo() { return null; }
|
||||
@A public <T> @B List< <caret>String> foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
@@ -163,175 +194,237 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsNestedGenericTypeIsAppliedToOuterType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>List<List<String>> foo() { return null; }
|
||||
@A public <T> @B <caret>List<List<String>> foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsNestedGenericTypeIsNotAppliedToInnerType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public List< <caret>List<String>> foo() { return null; }
|
||||
@A public <T> @B List< <caret>List<String>> foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsNestedGenericTypeIsNotAppliedToInnermostType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public List<List< <caret>String>> foo() { return null; }
|
||||
@A public <T> @B List<List< <caret>String>> foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsPrimitiveTypeIsAppliedToThatType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>int foo() { return 0; }
|
||||
@A public <T> @B <caret>int foo() { return 0; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsPrimitiveArrayTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public <caret>int[] foo() { return null; }
|
||||
@A public <T> @B <caret>int[] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A", "B");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMethodThatReturnsPrimitiveArrayTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
@MyAnnotation public int[<caret>] foo() { return null; }
|
||||
@A public <T> @B int[<caret>] foo() { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsSimpleTypeIsAppliedToThatType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation <caret>String param) {}
|
||||
public void foo(@A <caret>String param) {}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsNestedTypeQualifiedWithOuterTypeIsNotAppliedToNestedType() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
class Nested {}
|
||||
public void foo(@MyAnnotation AClass.<caret>Nested param) {}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsFullyQualifiedIsNotAppliedToThatType() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation java.lang.<caret>String param) {}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsArrayTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation <caret>String[] array) { return null; }
|
||||
public void foo(@A <caret>String[] array) { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsArrayTypeWithQualifiedComponentIsNotAppliedToArrayComponent() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation java.lang.<caret>String[] array) { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsArrayTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation String[<caret>] array) { return null; }
|
||||
public void foo(@A String[<caret>] array) { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsVarargIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation <caret>String... array) { return null; }
|
||||
public void foo(@A <caret>String... array) { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnParameterWhichTypeIsVarargIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo(@MyAnnotation String..<caret>. array) { return null; }
|
||||
public void foo(@A String..<caret>. array) { return null; }
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnFieldWhichTypeIsSimpleTypeIsAppliedToThatType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
private @MyAnnotation <caret>String field;
|
||||
private @A <caret>String field;
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnFieldWhichTypeIsNestedTypeQualifiedWithOuterTypeIsNotAppliedToThatType() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
class Nested {}
|
||||
private @MyAnnotation AClass.<caret>Nested field;
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnFieldWhichTypeIsFullyQualifiedIsNotAppliedToThatType() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
private @MyAnnotation java.lang.<caret>String field;
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnFieldWhichTypeIsArrayTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
private @MyAnnotation <caret>String[] array;
|
||||
private @A <caret>String[] array;
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnFieldWhichTypeIsArrayTypeWithQualifiedComponentIsNotAppliedToArrayComponent() {
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
private @MyAnnotation java.lang.<caret>String[] array;
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnFieldWhichTypeIsArrayTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
private @MyAnnotation String[<caret>] array;
|
||||
private @A String[<caret>] array;
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType());
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnVariableWhichTypeIsSimpleTypeIsAppliedToThatType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
void foo() {
|
||||
@MyAnnotation <caret>String variable;
|
||||
@A <caret>String variable;
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnVariableWhichTypeIsArrayTypeIsAppliedToArrayComponent() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
void foo() {
|
||||
@MyAnnotation <caret>String[] array;
|
||||
@A <caret>String[] array;
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnVariableWhichTypeIsArrayTypeIsNotAppliedToArrayType() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
void foo() {
|
||||
@MyAnnotation String[<caret>] array;
|
||||
@A String[<caret>] array;
|
||||
}
|
||||
}
|
||||
""");
|
||||
@@ -339,26 +432,26 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMultiCatchIsAppliedToFirstException() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo() {
|
||||
try {
|
||||
} catch (@MyAnnotation <caret>EOFException | FileNotFoundException | ObjectStreamException e) {
|
||||
} catch (@A <caret>EOFException | FileNotFoundException | ObjectStreamException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMultiCatchIsNotAppliedToMiddleException() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo() {
|
||||
try {
|
||||
} catch (@MyAnnotation EOFException | <caret>FileNotFoundException | ObjectStreamException e) {
|
||||
} catch (@A EOFException | <caret>FileNotFoundException | ObjectStreamException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -367,12 +460,12 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnMultiCatchIsNotAppliedToLastException() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo() {
|
||||
try {
|
||||
} catch (@MyAnnotation EOFException | FileNotFoundException | <caret>ObjectStreamException e) {
|
||||
} catch (@A EOFException | FileNotFoundException | <caret>ObjectStreamException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,17 +474,17 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
}
|
||||
|
||||
public void testTypeUseAnnotationOnSingleCatchIsAppliedToException() {
|
||||
configureFromFileWithMyAnnotationAdded(
|
||||
configureFromFileWithAnnotationsAdded(
|
||||
"""
|
||||
class AClass {
|
||||
public void foo() {
|
||||
try {
|
||||
} catch (@MyAnnotation <caret>EOFException e) {
|
||||
} catch (@A <caret>EOFException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "MyAnnotation");
|
||||
assertTypeAnnotations(getPsiTypeElementAtCaret().getType(), "A");
|
||||
}
|
||||
|
||||
private static void assertTypeAnnotations(PsiType psiType, String... annotation) {
|
||||
@@ -413,7 +506,7 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
return psiElement;
|
||||
}
|
||||
|
||||
private void configureFromFileWithMyAnnotationAdded(String classFile) {
|
||||
private void configureFromFileWithAnnotationsAdded(String classFile) {
|
||||
configureFromFileText(
|
||||
"AClass.java",
|
||||
"""
|
||||
@@ -424,7 +517,9 @@ public class PsiTypeElementImplTest extends LightJavaCodeInsightTestCase {
|
||||
import java.util.List;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface MyAnnotation {}
|
||||
public @interface A {}
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface B {}
|
||||
|
||||
""" + classFile
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user