mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] type annotations in class files
Step 2: apply top-level field/method/parameter annotations to types.
This commit is contained in:
+26
-2
@@ -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<ClsJavaCodeReferenceElementImpl> {
|
||||
public static final Resolver INSTANCE = new Resolver();
|
||||
|
||||
@@ -332,4 +356,4 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P
|
||||
public PsiElement getQualifier() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<PsiFieldStub> implements PsiField, PsiVariableEx, Queryable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiFieldImpl");
|
||||
|
||||
private volatile SoftReference<PsiType> myCachedType;
|
||||
private volatile Object myCachedInitializerValue; // PsiExpression on constant value for literal
|
||||
|
||||
@@ -125,26 +119,25 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> 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<PsiType>(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<PsiFieldStub> implements Ps
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiField:" + getName();
|
||||
}
|
||||
|
||||
@@ -442,5 +436,4 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
|
||||
protected boolean isVisibilitySupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<PsiMethodStub> implements PsiMethod, Queryable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiMethodImpl");
|
||||
|
||||
private SoftReference<PsiType> myCachedType;
|
||||
|
||||
public PsiMethodImpl(final PsiMethodStub stub) {
|
||||
@@ -190,30 +187,22 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> 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<PsiType>(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<PsiMethodStub> implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiMethod:" + getName();
|
||||
}
|
||||
@@ -376,4 +366,4 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
|
||||
protected boolean isVisibilitySupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,23 +141,19 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> 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<PsiType>(type);
|
||||
return type;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
return null;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
myCachedType = null;
|
||||
@@ -232,6 +228,7 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiParameter:" + getName();
|
||||
}
|
||||
@@ -322,5 +319,4 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
|
||||
List<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
|
||||
|
||||
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<PsiAnnotation> annotations) {
|
||||
if (annotations.isEmpty()) return TypeAnnotationProvider.EMPTY;
|
||||
|
||||
final ArrayList<PsiAnnotation> 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<PsiAnnotation> filtered = ContainerUtil.filter(copy, new Condition<PsiAnnotation>() {
|
||||
@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<PsiAnnotation> 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<PsiAnnotation> annotations) {
|
||||
return TypeAnnotationProvider.Static.create(copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true));
|
||||
}
|
||||
|
||||
private List<PsiType> collectTypes() {
|
||||
@@ -246,9 +206,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiAnnotation[] getApplicableAnnotations() {
|
||||
List<PsiAnnotation> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<PsiArrayType> types = new Stack<PsiArrayType>();
|
||||
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<PsiType> 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<PsiAnnotation> filtered = ContainerUtil.filter(myCandidates, new Condition<PsiAnnotation>() {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user