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:
Marcin Mikosik
2026-02-05 12:54:15 +00:00
committed by intellij-monorepo-bot
parent ae32f72c59
commit 096d52cf89
6 changed files with 245 additions and 96 deletions
@@ -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
);