From a2497edceec614cdb5b76ba552f8a035f9e159f8 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 6 Jun 2016 17:23:46 +0300 Subject: [PATCH] [java] type annotations in class files Step 2: apply top-level field/method/parameter annotations to types. --- .../ClsJavaCodeReferenceElementImpl.java | 28 +++++- .../psi/impl/compiled/ClsTypeElementImpl.java | 11 ++- .../psi/impl/source/PsiFieldImpl.java | 35 +++----- .../psi/impl/source/PsiMethodImpl.java | 30 +++---- .../psi/impl/source/PsiParameterImpl.java | 20 ++--- .../psi/impl/source/PsiTypeElementImpl.java | 86 +++++-------------- .../impl/source/tree/JavaSharedImplUtil.java | 64 +++++++++++++- .../testSrc/com/intellij/psi/ClsPsiTest.java | 21 ++++- .../com/intellij/psi/JavaStubsTest.groovy | 23 +++++ 9 files changed, 195 insertions(+), 123 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java index dec3c79a06ca..e216d4cf2baa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl.compiled; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.impl.ResolveScopeManager; @@ -37,9 +38,10 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.Map; -public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements PsiJavaCodeReferenceElement { +public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements PsiAnnotatedJavaCodeReferenceElement { private final PsiElement myParent; private final String myCanonicalText; private final String myQualifiedName; @@ -89,6 +91,28 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P return myCanonicalText; } + @NotNull + @Override + public String getCanonicalText(boolean annotated, @Nullable PsiAnnotation[] annotations) { + String text = getCanonicalText(); + if (!annotated || annotations == null) return text; + + StringBuilder sb = new StringBuilder(); + + String prefix = getOuterClassRef(text); + int tailStart = 0; + if (!StringUtil.isEmpty(prefix)) { + sb.append(prefix).append('.'); + tailStart = prefix.length() + 1; + } + + PsiNameHelper.appendAnnotations(sb, Arrays.asList(annotations), true); + + sb.append(text, tailStart, text.length()); + + return sb.toString(); + } + private static class Resolver implements ResolveCache.PolyVariantContextResolver { public static final Resolver INSTANCE = new Resolver(); @@ -332,4 +356,4 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P public PsiElement getQualifier() { return null; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java index 0941c91a8597..29fd4b343586 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.intellij.psi.impl.PsiJavaParserFacadeImpl; import com.intellij.psi.impl.cache.TypeInfo; import com.intellij.psi.impl.source.PsiClassReferenceType; import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.JavaSharedImplUtil; import com.intellij.psi.impl.source.tree.TreeElement; import org.jetbrains.annotations.NotNull; @@ -148,6 +149,12 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement @NotNull private PsiType calculateType() { + PsiModifierList modifierList = myParent instanceof PsiModifierListOwner ? ((PsiModifierListOwner)myParent).getModifierList() : null; + return JavaSharedImplUtil.applyAnnotations(calculateBaseType(), modifierList); + } + + @NotNull + private PsiType calculateBaseType() { PsiType result = PsiJavaParserFacadeImpl.getPrimitiveType(myTypeText); if (result != null) return result; @@ -228,4 +235,4 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement public String toString() { return "PsiTypeElement:" + getText(); } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java index 837ca59b86e8..d11363562124 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.source; import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -42,14 +41,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class PsiFieldImpl extends JavaStubPsiElement implements PsiField, PsiVariableEx, Queryable { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiFieldImpl"); - private volatile SoftReference myCachedType; private volatile Object myCachedInitializerValue; // PsiExpression on constant value for literal @@ -125,26 +119,25 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps @Override @NotNull + @SuppressWarnings("Duplicates") public PsiType getType() { - final PsiFieldStub stub = getStub(); + PsiFieldStub stub = getStub(); if (stub != null) { PsiType type = SoftReference.dereference(myCachedType); - if (type != null) return type; - - String typeText = TypeInfo.createTypeText(stub.getType(true)); - try { + if (type == null) { + String typeText = TypeInfo.createTypeText(stub.getType(false)); + assert typeText != null : stub; type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); + type = JavaSharedImplUtil.applyAnnotations(type, getModifierList()); myCachedType = new SoftReference(type); - return type; - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; } + return type; } myCachedType = null; - return JavaSharedImplUtil.getType(getTypeElement(), getNameIdentifier()); + PsiTypeElement typeElement = getTypeElement(); + assert typeElement != null : Arrays.toString(getChildren()); + return JavaSharedImplUtil.getType(typeElement, getNameIdentifier()); } @Override @@ -396,7 +389,8 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps return true; } - public String toString(){ + @Override + public String toString() { return "PsiField:" + getName(); } @@ -442,5 +436,4 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps protected boolean isVisibilitySupported() { return true; } - -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java index 130befcf6fb6..f565fc1541d4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java @@ -19,7 +19,6 @@ import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; @@ -50,8 +49,6 @@ import java.util.List; import java.util.Map; public class PsiMethodImpl extends JavaStubPsiElement implements PsiMethod, Queryable { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiMethodImpl"); - private SoftReference myCachedType; public PsiMethodImpl(final PsiMethodStub stub) { @@ -190,30 +187,22 @@ public class PsiMethodImpl extends JavaStubPsiElement implements public PsiType getReturnType() { if (isConstructor()) return null; - final PsiMethodStub stub = getStub(); + PsiMethodStub stub = getStub(); if (stub != null) { PsiType type = SoftReference.dereference(myCachedType); - if (type != null) return type; - - final String typeText = TypeInfo.createTypeText(stub.getReturnTypeText(true)); - if (typeText == null) return null; - - try { - type = JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeFromText(typeText, this); + if (type == null) { + String typeText = TypeInfo.createTypeText(stub.getReturnTypeText(false)); + assert typeText != null : stub; + type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); + type = JavaSharedImplUtil.applyAnnotations(type, getModifierList()); myCachedType = new SoftReference(type); - return type; - } - catch (IncorrectOperationException e) { - LOG.error("stub: " + stub + "; method: " + getText(), e); - return null; } + return type; } myCachedType = null; PsiTypeElement typeElement = getReturnTypeElement(); - if (typeElement == null) return null; - PsiParameterList parameterList = getParameterList(); - return JavaSharedImplUtil.getType(typeElement, parameterList); + return typeElement != null ? JavaSharedImplUtil.getType(typeElement, getParameterList()) : null; } @Override @@ -298,6 +287,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements } } + @Override public String toString() { return "PsiMethod:" + getName(); } @@ -376,4 +366,4 @@ public class PsiMethodImpl extends JavaStubPsiElement implements protected boolean isVisibilitySupported() { return true; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java index b20660fd4ce6..5276b11f0efa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java @@ -141,23 +141,19 @@ public class PsiParameterImpl extends JavaStubPsiElement imple @Override @NotNull + @SuppressWarnings("Duplicates") public PsiType getType() { PsiParameterStub stub = getStub(); if (stub != null) { PsiType type = SoftReference.dereference(myCachedType); - if (type != null) return type; - - String typeText = TypeInfo.createTypeText(stub.getType(true)); - assert typeText != null : stub; - try { + if (type == null) { + String typeText = TypeInfo.createTypeText(stub.getType(false)); + assert typeText != null : stub; type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); + type = JavaSharedImplUtil.applyAnnotations(type, getModifierList()); myCachedType = new SoftReference(type); - return type; - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; } + return type; } myCachedType = null; @@ -232,6 +228,7 @@ public class PsiParameterImpl extends JavaStubPsiElement imple } } + @Override public String toString() { return "PsiParameter:" + getName(); } @@ -322,5 +319,4 @@ public class PsiParameterImpl extends JavaStubPsiElement imple } return this; } - -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index 99cc82f3fafe..1181489afa8a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,11 @@ package com.intellij.psi.impl.source; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.augment.PsiAugmentProvider; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.PsiJavaParserFacadeImpl; -import com.intellij.psi.impl.source.tree.CompositePsiElement; -import com.intellij.psi.impl.source.tree.ElementType; -import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; @@ -36,13 +32,11 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement { - private static final Class[] INTERMEDIATES = {PsiComment.class, PsiWhiteSpace.class, PsiAnnotation.class, PsiTypeParameterList.class}; +import static com.intellij.util.containers.ContainerUtil.copyAndClear; +public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement { @SuppressWarnings({"UnusedDeclaration"}) public PsiTypeElementImpl() { this(JavaElementType.TYPE); @@ -81,7 +75,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl } PsiType type = null; - final SmartList annotations = new SmartList(); + List annotations = new SmartList(); for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue; @@ -101,23 +95,20 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl } else if (PsiUtil.isJavaToken(child, ElementType.PRIMITIVE_TYPE_BIT_SET)) { assert type == null : this; - addTypeUseCandidateAnnotations(annotations); String text = child.getText(); - type = annotations.isEmpty() ? PsiJavaParserFacadeImpl.getPrimitiveType(text) - : new PsiPrimitiveType(text, filterTypeUse(annotations)); + type = annotations.isEmpty() ? PsiJavaParserFacadeImpl.getPrimitiveType(text) : new PsiPrimitiveType(text, createProvider(annotations)); } else if (child instanceof PsiJavaCodeReferenceElement) { assert type == null : this; - addTypeUseCandidateAnnotations(annotations); - type = new PsiClassReferenceType((PsiJavaCodeReferenceElement)child, null, filterTypeUse(annotations)); + type = new PsiClassReferenceType((PsiJavaCodeReferenceElement)child, null, createProvider(annotations)); } else if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET)) { assert type != null : this; - type = new PsiArrayType(type, filterTypeUse(annotations)); + type = new PsiArrayType(type, createProvider(annotations)); } else if (PsiUtil.isJavaToken(child, JavaTokenType.ELLIPSIS)) { assert type != null : this; - type = new PsiEllipsisType(type, filterTypeUse(annotations)); + type = new PsiEllipsisType(type, createProvider(annotations)); } if (PsiUtil.isJavaToken(child, JavaTokenType.QUEST) || @@ -134,7 +125,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl else { type = PsiWildcardType.createUnbounded(getManager()); } - type = type.annotate(filterTypeUse(annotations)); + type = type.annotate(createProvider(annotations)); break; } @@ -153,49 +144,18 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl } } - return type == null ? PsiType.NULL : type; - } + if (type == null) return PsiType.NULL; - @NotNull - private static TypeAnnotationProvider filterTypeUse(List annotations) { - if (annotations.isEmpty()) return TypeAnnotationProvider.EMPTY; - - final ArrayList copy = ContainerUtil.newArrayList(annotations); - annotations.clear(); - return new TypeAnnotationProvider() { - private volatile PsiAnnotation[] myCached; - @NotNull - @Override - public PsiAnnotation[] getAnnotations() { - PsiAnnotation[] result = myCached; - if (result == null) { - List filtered = ContainerUtil.filter(copy, new Condition() { - @Override - public boolean value(PsiAnnotation annotation) { - return PsiImplUtil.isTypeAnnotation(annotation); - } - }); - myCached = result = filtered.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : filtered.toArray(new PsiAnnotation[filtered.size()]); - } - return result; - } - }; - } - - private void addTypeUseCandidateAnnotations(List annotations) { - PsiElement parent = this; - while (parent instanceof PsiTypeElement) { - PsiElement left = PsiTreeUtil.skipSiblingsBackward(parent, INTERMEDIATES); - - if (left instanceof PsiModifierList) { - Collections.addAll(annotations, ((PsiModifierList)left).getAnnotations()); - break; - } - - if (left != null) break; - - parent = parent.getParent(); + PsiElement parent = getParent(); + if (parent instanceof PsiModifierListOwner) { + type = JavaSharedImplUtil.applyAnnotations(type, ((PsiModifierListOwner)parent).getModifierList()); } + + return type; + } + + private static TypeAnnotationProvider createProvider(List annotations) { + return TypeAnnotationProvider.Static.create(copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true)); } private List collectTypes() { @@ -246,9 +206,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl @Override @NotNull public PsiAnnotation[] getApplicableAnnotations() { - List annotations = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiAnnotation.class); - addTypeUseCandidateAnnotations(annotations); - return annotations.toArray(PsiAnnotation.ARRAY_FACTORY.create(annotations.size())); + return getType().getAnnotations(); } @Override @@ -275,4 +233,4 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl public String toString() { return "PsiTypeElement:" + getText(); } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java index 07fcb8023c55..063242381fc3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java @@ -15,9 +15,11 @@ */ package com.intellij.psi.impl.source.tree; +import com.intellij.codeInsight.AnnotationTargetUtil; import com.intellij.lang.ASTFactory; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.impl.GeneratedMarkerVisitor; import com.intellij.psi.impl.PsiImplUtil; @@ -26,6 +28,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -84,6 +87,40 @@ public class JavaSharedImplUtil { return !found || stop ? null : annotations; } + @NotNull + public static PsiType applyAnnotations(@NotNull PsiType type, @Nullable PsiModifierList modifierList) { + if (modifierList != null) { + PsiAnnotation[] annotations = modifierList.getAnnotations(); + if (annotations.length > 0) { + TypeAnnotationProvider provider = new FilteringTypeAnnotationProvider(annotations); + if (type instanceof PsiArrayType) { + Stack types = new Stack(); + do { + types.push((PsiArrayType)type); + type = ((PsiArrayType)type).getComponentType(); + } + while (type instanceof PsiArrayType); + type = type.annotate(provider); + while (!types.isEmpty()) { + PsiArrayType t = types.pop(); + type = t instanceof PsiEllipsisType ? new PsiEllipsisType(type, t.getAnnotations()) : new PsiArrayType(type, t.getAnnotations()); + } + return type; + } + else if (type instanceof PsiDisjunctionType) { + List components = ContainerUtil.newArrayList(((PsiDisjunctionType)type).getDisjunctions()); + components.set(0, components.get(0).annotate(provider)); + return ((PsiDisjunctionType)type).newDisjunctionType(components); + } + else { + return type.annotate(provider); + } + } + } + + return type; + } + public static void normalizeBrackets(@NotNull PsiVariable variable) { CompositeElement variableElement = (CompositeElement)variable.getNode(); @@ -156,4 +193,29 @@ public class JavaSharedImplUtil { } variable.addAfter(initializer, eq.getPsi()); } -} + + private static class FilteringTypeAnnotationProvider implements TypeAnnotationProvider { + private final PsiAnnotation[] myCandidates; + private volatile PsiAnnotation[] myCache; + + private FilteringTypeAnnotationProvider(PsiAnnotation[] candidates) { + myCandidates = candidates; + } + + @NotNull + @Override + public PsiAnnotation[] getAnnotations() { + PsiAnnotation[] result = myCache; + if (result == null) { + List filtered = ContainerUtil.filter(myCandidates, new Condition() { + @Override + public boolean value(PsiAnnotation annotation) { + return AnnotationTargetUtil.isTypeAnnotation(annotation); + } + }); + myCache = result = filtered.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : filtered.toArray(new PsiAnnotation[filtered.size()]); + } + return result; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java index 6a0117e8366d..fa9c681b8524 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java @@ -27,6 +27,7 @@ import com.intellij.psi.impl.java.stubs.PsiMethodStub; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtil; import com.intellij.testFramework.LightIdeaTestCase; +import com.intellij.util.ObjectUtils; import com.intellij.util.indexing.FileBasedIndex; import java.io.File; @@ -390,13 +391,31 @@ public class ClsPsiTest extends LightIdeaTestCase { assertEquals(42L, lng.computeConstantValue()); } + public void testAnnotationsOnTypes() { + PsiClass cls = getFile("../../mirror/pkg/TypeAnnotations").getClasses()[0]; + + PsiField f1 = cls.findFieldByName("f1", false); + assertNotNull(f1); + assertEquals("java.lang.@pkg.TypeAnnotations.TA(\"field type\") String", f1.getType().getCanonicalText(true)); + + PsiField f2 = cls.findFieldByName("f2", false); + assertNotNull(f2); + assertEquals("java.lang.@pkg.TypeAnnotations.MixA(\"field and type\") String", f2.getType().getCanonicalText(true)); + + PsiMethod m1 = cls.findMethodsByName("m1", false)[0]; + assertEquals("@pkg.TypeAnnotations.TA(\"return type\") int", ObjectUtils.assertNotNull(m1.getReturnType()).getCanonicalText(true)); + + PsiParameter p1 = cls.findMethodsByName("m2", false)[0].getParameterList().getParameters()[0]; + assertEquals("@pkg.TypeAnnotations.TA(\"parameter\") int", p1.getType().getCanonicalText(true)); + } + private PsiJavaFile getFile() { return getFile(getTestName(false)); } private static PsiJavaFile getFile(String name) { String path = PathManagerEx.getTestDataPath() + TEST_DATA_PATH + "/pack/" + name + ".class"; - VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path); + VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); assertNotNull(path, file); PsiFile clsFile = PsiManager.getInstance(getProject()).findFile(file); assertTrue(String.valueOf(clsFile), clsFile instanceof ClsFileImpl); diff --git a/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy b/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy index f352b2282625..8994e2fef1ea 100644 --- a/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy @@ -16,6 +16,7 @@ package com.intellij.psi import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer +import com.intellij.psi.impl.source.PsiClassImpl import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase @@ -54,4 +55,26 @@ class JavaStubsTest extends LightCodeInsightFixtureTestCase { assert !file.contentsLoaded } + public void "test applying type annotations"() { + def cls = myFixture.addClass(""" + import java.lang.annotation.*; + class Foo { + @Target(ElementType.TYPE_USE) + @interface TA { String value(); } + + private @TA String f1; + + private static @TA int m1(@TA int p1) { return 0; } + } + """.stripIndent()) + + def f1 = cls.fields[0].type + def m1 = cls.methods[0].returnType + def p1 = cls.methods[0].parameterList.parameters[0].type + assert (cls as PsiClassImpl).stub + + assert f1.getCanonicalText(true) == "java.lang.@Foo.TA String" + assert m1.getCanonicalText(true) == "@Foo.TA int" + assert p1.getCanonicalText(true) == "@Foo.TA int" + } } \ No newline at end of file