PsiTypeElement.getType() fixed

This commit is contained in:
Roman Shevchenko
2013-04-04 19:38:46 +02:00
parent 3d75dc6664
commit fc602c65bc
11 changed files with 284 additions and 210 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -38,19 +38,18 @@ public class PsiDisjunctionType extends PsiType {
private final List<PsiType> myTypes;
private final CachedValue<PsiType> myLubCache;
public PsiDisjunctionType(@NotNull final List<PsiType> types, @NotNull final PsiManager psiManager) {
public PsiDisjunctionType(@NotNull List<PsiType> types, @NotNull PsiManager psiManager) {
super(PsiAnnotation.EMPTY_ARRAY);
myManager = psiManager;
myTypes = Collections.unmodifiableList(types);
final CachedValuesManager cacheManager = CachedValuesManager.getManager(psiManager.getProject());
myLubCache = cacheManager.createCachedValue(new CachedValueProvider<PsiType>() {
myLubCache = CachedValuesManager.getManager(myManager.getProject()).createCachedValue(new CachedValueProvider<PsiType>() {
@Override
public Result<PsiType> compute() {
PsiType lub = myTypes.get(0);
for (int i = 1; i < myTypes.size(); i++) {
lub = GenericsUtil.getLeastUpperBound(lub, myTypes.get(i), psiManager);
lub = GenericsUtil.getLeastUpperBound(lub, myTypes.get(i), myManager);
if (lub == null) {
lub = PsiType.getJavaLangObject(myManager, GlobalSearchScope.allScope(myManager.getProject()));
break;
@@ -61,6 +60,12 @@ public class PsiDisjunctionType extends PsiType {
}, false);
}
@NotNull
public static PsiType createDisjunction(@NotNull List<PsiType> types, @NotNull PsiManager psiManager) {
assert types.size() > 0;
return types.size() == 1 ? types.get(0) : new PsiDisjunctionType(types, psiManager);
}
@NotNull
public PsiType getLeastUpperBound() {
return myLubCache.getValue();
@@ -29,10 +29,19 @@ public class PsiEllipsisType extends PsiArrayType {
*
* @param componentType the type of the varargs array component.
*/
public PsiEllipsisType(PsiType componentType) {
public PsiEllipsisType(@NotNull PsiType componentType) {
super(componentType);
}
public PsiEllipsisType(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) {
super(componentType, annotations);
}
@NotNull
public static PsiType createEllipsis(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) {
return new PsiEllipsisType(componentType, annotations);
}
@Override
public String getPresentableText() {
return StringUtil.joinOrNull(getComponentType().getPresentableText(), getAnnotationsTextPrefix(false, true, true), "...");
@@ -60,7 +69,7 @@ public class PsiEllipsisType extends PsiArrayType {
* @return the array type instance.
*/
public PsiType toArrayType() {
return getComponentType().createArrayType();
return getComponentType().createArrayType(getAnnotations());
}
@Override
@@ -15,33 +15,39 @@
*/
package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.TypeConversionUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.*;
/**
* Intersection types arise in a process of computing least upper bound.
*
* @author ven
*/
// Intersection types arise in the process of computing lub.
public class PsiIntersectionType extends PsiType {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiIntersectionType");
private final PsiType[] myConjuncts;
private PsiIntersectionType(@NotNull PsiType[] conjuncts) {
super(PsiAnnotation.EMPTY_ARRAY);//todo
LOG.assertTrue(conjuncts.length != 0);
LOG.assertTrue(conjuncts.length > 1);
super(PsiAnnotation.EMPTY_ARRAY);
myConjuncts = conjuncts;
}
@NotNull
public static PsiType createIntersection(@NotNull List<PsiType> conjuncts) {
return createIntersection(conjuncts.toArray(new PsiType[conjuncts.size()]));
}
@NotNull
public static PsiType createIntersection(PsiType... conjuncts) {
assert conjuncts.length > 0;
conjuncts = flattenAndRemoveDuplicates(conjuncts);
if (conjuncts.length == 1) return conjuncts[0];
return new PsiIntersectionType(conjuncts);
}
private static PsiType[] flattenAndRemoveDuplicates(PsiType[] conjuncts) {
try {
Set<PsiType> flattened = flatten(conjuncts, new THashSet<PsiType>());
@@ -64,7 +70,7 @@ public class PsiIntersectionType extends PsiType {
}
if (types.size() > 1) {
PsiType[] array = types.toArray(new PsiType[types.size()]);
for (Iterator<PsiType> iterator = types.iterator(); iterator.hasNext();) {
for (Iterator<PsiType> iterator = types.iterator(); iterator.hasNext(); ) {
PsiType type = iterator.next();
for (PsiType existing : array) {
@@ -138,13 +144,6 @@ public class PsiIntersectionType extends PsiType {
return myConjuncts;
}
public static PsiType createIntersection(PsiType... conjuncts) {
LOG.assertTrue(conjuncts.length >= 1);
conjuncts = flattenAndRemoveDuplicates(conjuncts);
if (conjuncts.length == 1) return conjuncts[0];
return new PsiIntersectionType(conjuncts);
}
public PsiType getRepresentative() {
return myConjuncts[0];
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -30,22 +30,31 @@ import org.jetbrains.annotations.Nullable;
*/
public class PsiWildcardType extends PsiType {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiWildcardType");
private static final Key<PsiWildcardType> UNBOUNDED_WILDCARD = new Key<PsiWildcardType>("UNBOUNDED_WILDCARD");
private final PsiManager myManager;
private final PsiType myBound;
private final boolean myIsExtending;
@NonNls private static final String EXTENDS_PREFIX = "? extends ";
@NonNls private static final String SUPER_PREFIX = "? super ";
private PsiWildcardType(@NotNull PsiManager manager, boolean isExtending, PsiType bound) {
super(PsiAnnotation.EMPTY_ARRAY);//todo
private final PsiManager myManager;
private final boolean myIsExtending;
private final PsiType myBound;
private PsiWildcardType(@NotNull PsiManager manager, boolean isExtending, @Nullable PsiType bound) {
super(PsiAnnotation.EMPTY_ARRAY);
myManager = manager;
myIsExtending = isExtending;
myBound = bound;
}
private PsiWildcardType(@NotNull PsiWildcardType type, @NotNull PsiAnnotation[] annotations) {
super(annotations);
myManager = type.myManager;
myIsExtending = type.myIsExtending;
myBound = type.myBound;
}
@NotNull
public static PsiWildcardType createUnbounded(PsiManager manager) {
public static PsiWildcardType createUnbounded(@NotNull PsiManager manager) {
PsiWildcardType unboundedWildcard = manager.getUserData(UNBOUNDED_WILDCARD);
if (unboundedWildcard == null) {
unboundedWildcard = manager.putUserDataIfAbsent(UNBOUNDED_WILDCARD, new PsiWildcardType(manager, false, null));
@@ -61,9 +70,19 @@ public class PsiWildcardType extends PsiType {
@NotNull
public static PsiWildcardType createSuper(@NotNull PsiManager manager, @NotNull PsiType bound) {
LOG.assertTrue(!(bound instanceof PsiWildcardType));
return new PsiWildcardType(manager, false, bound);
}
@NotNull
public PsiWildcardType annotate(@NotNull PsiAnnotation[] annotations) {
return annotations.length == 0 ? this : new PsiWildcardType(this, annotations);
}
/**
* @deprecated implementation details (to remove in IDEA 13)
*/
@SuppressWarnings("UnusedDeclaration")
public static PsiWildcardType changeBound(@NotNull PsiWildcardType type, @NotNull PsiType newBound) {
LOG.assertTrue(type.getBound() != null);
LOG.assertTrue(newBound.isValid());
@@ -202,7 +221,7 @@ public class PsiWildcardType extends PsiType {
}
/**
* @return false for unbounded wildcards, true otherwise
* @return false for unbounded wildcards, true otherwise
*/
public boolean isBounded() {
return myBound != null;
@@ -731,20 +731,17 @@ public class PsiImplUtil {
return null;
}
public static void addTypeUseAnnotationsFromModifierList(@NotNull PsiElement member, @NotNull List<PsiAnnotation> annotations) {
if (member instanceof PsiModifierListOwner) {
PsiModifierList modifierList = ((PsiModifierListOwner)member).getModifierList();
if (modifierList != null) {
addTypeUseAnnotations(modifierList, annotations);
}
}
}
@Nullable
public static List<PsiAnnotation> getTypeUseAnnotations(@NotNull PsiModifierList modifierList) {
SmartList<PsiAnnotation> result = null;
public static void addTypeUseAnnotations(@NotNull PsiModifierList modifierList, @NotNull List<PsiAnnotation> annotations) {
for (PsiAnnotation annotation : modifierList.getAnnotations()) {
if (findApplicableTarget(annotation, TargetType.TYPE_USE) == TargetType.TYPE_USE) {
annotations.add(annotation);
if (result == null) result = new SmartList<PsiAnnotation>();
result.add(annotation);
}
}
return result;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -160,7 +160,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
final PsiWildcardType wildcard = ((PsiCapturedWildcardType)newBound).getWildcard();
if (wildcardType.isExtends() != wildcard.isExtends()) {
if (wildcard.isBounded()) {
return wildcardType.isExtends() ? PsiWildcardType.createExtends(wildcardType.getManager(), newBound)
return wildcardType.isExtends() ? PsiWildcardType.createExtends(wildcardType.getManager(), newBound)
: PsiWildcardType.createSuper(wildcardType.getManager(), newBound);
}
else {
@@ -170,7 +170,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
if (!wildcard.isBounded()) return PsiWildcardType.createUnbounded(wildcardType.getManager());
}
return PsiWildcardType.changeBound(wildcardType, newBound);
return rebound(wildcardType, newBound);
}
}
@@ -178,12 +178,29 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
if (bound.isExtends() == wildcardType.isExtends()) {
final PsiType newBoundBound = bound.getBound();
if (newBoundBound != null) {
return PsiWildcardType.changeBound(wildcardType, newBoundBound);
return rebound(wildcardType, newBoundBound);
}
}
return PsiWildcardType.createUnbounded(wildcardType.getManager());
}
private static PsiWildcardType rebound(PsiWildcardType type, PsiType newBound) {
LOG.assertTrue(type.getBound() != null);
LOG.assertTrue(newBound.isValid());
if (type.isExtends()) {
if (newBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
return PsiWildcardType.createUnbounded(type.getManager());
}
else {
return PsiWildcardType.createExtends(type.getManager(), newBound);
}
}
else {
return PsiWildcardType.createSuper(type.getManager(), newBound);
}
}
@Override
public PsiType visitPrimitiveType(PsiPrimitiveType primitiveType) {
return primitiveType;
@@ -359,7 +376,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
if (captureContext != null) {
LOG.assertTrue(substituted instanceof PsiWildcardType);
substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted == ((PsiCapturedWildcardType)oldSubstituted).getWildcard()
substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted == ((PsiCapturedWildcardType)oldSubstituted).getWildcard()
? oldSubstituted : PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext);
}
return substituted;
@@ -582,7 +582,12 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
if (!isQualified()) {
PsiModifierList modifierList = PsiImplUtil.findNeighbourModifierList(this);
if (modifierList != null) PsiImplUtil.addTypeUseAnnotations(modifierList, annotations);
if (modifierList != null) {
List<PsiAnnotation> typeAnnotations = PsiImplUtil.getTypeUseAnnotations(modifierList);
if (typeAnnotations != null && typeAnnotations.size() > 0) {
annotations.addAll(typeAnnotations);
}
}
}
return annotations;
@@ -22,38 +22,32 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
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.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.reference.SoftReference;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiTypeElementImpl");
private volatile PsiType myCachedType = null;
private volatile SoftReference<PsiType> myCachedDetachedType = null;
@SuppressWarnings({"UnusedDeclaration"})
public PsiTypeElementImpl() {
this(JavaElementType.TYPE);
}
protected PsiTypeElementImpl(final IElementType type) {
protected PsiTypeElementImpl(IElementType type) {
super(type);
}
@@ -61,11 +55,10 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
public void clearCaches() {
super.clearCaches();
myCachedType = null;
myCachedDetachedType = null;
}
@Override
public void accept(@NotNull PsiElementVisitor visitor){
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitTypeElement(this);
}
@@ -74,110 +67,128 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
}
}
public String toString(){
return "PsiTypeElement:" + getText();
}
@Override
@NotNull
public PsiType getType() {
PsiType cachedType = myCachedType;
if (cachedType != null) {
return cachedType;
}
final List<PsiAnnotation> typeAnnotations = new ArrayList<PsiAnnotation>();
TreeElement element = getFirstChildNode();
while (element != null) {
IElementType elementType = element.getElementType();
if (element.getTreeNext() == null && ElementType.PRIMITIVE_TYPE_BIT_SET.contains(elementType)) {
PsiImplUtil.addTypeUseAnnotationsFromModifierList(getParent(), typeAnnotations);
final PsiAnnotation[] array = toAnnotationsArray(typeAnnotations);
cachedType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createPrimitiveType(element.getText(), array);
}
else if (elementType == JavaElementType.TYPE) {
final IElementType tailType = getLastChildNode().getElementType();
if (tailType == JavaTokenType.ELLIPSIS) {
final PsiType componentType = ((PsiTypeElement)SourceTreeToPsiMap.treeToPsiNotNull(element)).getType();
cachedType = new PsiEllipsisType(componentType);
}
else if (tailType == JavaTokenType.RBRACKET) {
final PsiType componentType = ((PsiTypeElement)SourceTreeToPsiMap.treeToPsiNotNull(element)).getType();
cachedType = componentType.createArrayType();
}
else {
final PsiElement opElement = PsiTreeUtil.skipSiblingsForward(element.getPsi(), PsiWhiteSpace.class);
final List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiTypeElement.class);
final List<PsiType> types = ContainerUtil.map(typeElements, new Function<PsiTypeElement, PsiType>() {
@Override public PsiType fun(final PsiTypeElement psiTypeElement) { return psiTypeElement.getType(); }
});
cachedType = opElement instanceof PsiJavaToken && ((PsiJavaToken)opElement).getTokenType() == JavaTokenType.AND
? PsiIntersectionType.createIntersection(types.toArray(new PsiType[types.size()]))
: new PsiDisjunctionType(types, getManager());
}
}
else if (elementType == JavaElementType.JAVA_CODE_REFERENCE) {
PsiImplUtil.addTypeUseAnnotationsFromModifierList(getParent(), typeAnnotations);
final PsiAnnotation[] array = toAnnotationsArray(typeAnnotations);
final PsiJavaCodeReferenceElement reference = SourceTreeToPsiMap.treeToPsiNotNull(element);
cachedType = new PsiClassReferenceType(reference, null, array);
}
else if (elementType == JavaTokenType.QUEST) {
cachedType = createWildcardType();
}
else if (ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains(elementType)) {
element = element.getTreeNext();
continue;
}
else if (elementType == JavaElementType.ANNOTATION) {
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
final PsiAnnotation annotation = elementFactory.createAnnotationFromText(element.getText(), this);
typeAnnotations.add(annotation);
element = element.getTreeNext();
continue;
}
else if (elementType == JavaElementType.DIAMOND_TYPE) {
cachedType = new PsiDiamondTypeImpl(getManager(), this);
break;
}
else {
LOG.error("Unknown element type: " + elementType);
}
if (element.getTextLength() != 0) break;
element = element.getTreeNext();
}
if (cachedType == null) cachedType = PsiType.NULL;
if (cachedType != null) return cachedType;
cachedType = calculateType();
myCachedType = cachedType;
return cachedType;
}
private static PsiAnnotation[] toAnnotationsArray(List<PsiAnnotation> typeAnnotations) {
final int size = typeAnnotations.size();
return size == 0 ? PsiAnnotation.EMPTY_ARRAY : typeAnnotations.toArray(new PsiAnnotation[size]);
private PsiType calculateType() {
PsiType type = null;
SmartList<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue;
if (child instanceof PsiAnnotation) {
annotations.add((PsiAnnotation)child);
}
else if (child instanceof PsiTypeElement) {
assert type == null : this;
if (child instanceof PsiDiamondTypeElementImpl) {
type = new PsiDiamondTypeImpl(getManager(), this);
break;
}
else {
type = ((PsiTypeElement)child).getType();
}
}
else if (PsiUtil.isJavaToken(child, ElementType.PRIMITIVE_TYPE_BIT_SET)) {
assert type == null : this;
addTypeUseAnnotations(annotations);
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
type = JavaPsiFacade.getInstance(getProject()).getElementFactory().createPrimitiveType(child.getText(), array);
}
else if (child instanceof PsiJavaCodeReferenceElement) {
assert type == null : this;
addTypeUseAnnotations(annotations);
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
type = new PsiClassReferenceType((PsiJavaCodeReferenceElement)child, null, array);
}
else if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET)) {
assert type != null : this;
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
type = type.createArrayType(array);
}
else if (PsiUtil.isJavaToken(child, JavaTokenType.ELLIPSIS)) {
assert type != null : this;
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
type = PsiEllipsisType.createEllipsis(type, array);
}
if (PsiUtil.isJavaToken(child, JavaTokenType.QUEST)) {
assert type == null : this;
PsiElement next = PsiTreeUtil.skipSiblingsForward(child, PsiComment.class, PsiWhiteSpace.class);
if (next == null) {
type = PsiWildcardType.createUnbounded(getManager());
}
else {
PsiElement bound = PsiTreeUtil.skipSiblingsForward(next, PsiComment.class, PsiWhiteSpace.class);
if (PsiUtil.isJavaToken(next, JavaTokenType.EXTENDS_KEYWORD) && bound instanceof PsiTypeElement) {
type = PsiWildcardType.createExtends(getManager(), ((PsiTypeElement)bound).getType());
}
else if (PsiUtil.isJavaToken(next, JavaTokenType.SUPER_KEYWORD) && bound instanceof PsiTypeElement) {
type = PsiWildcardType.createSuper(getManager(), ((PsiTypeElement)bound).getType());
}
else {
LOG.error("next=" + next + " bound=" + bound + ": " + this);
type = PsiWildcardType.createUnbounded(getManager());
}
}
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
type = ((PsiWildcardType)type).annotate(array);
break;
}
if (PsiUtil.isJavaToken(child, JavaTokenType.AND)) {
List<PsiType> types = collectTypes();
assert types.size() > 0 : this;
type = PsiIntersectionType.createIntersection(types);
break;
}
if (PsiUtil.isJavaToken(child, JavaTokenType.OR)) {
List<PsiType> types = collectTypes();
assert types.size() > 0 : this;
type = PsiDisjunctionType.createDisjunction(types, getManager());
break;
}
}
return type == null ? PsiType.NULL : type;
}
public PsiType getDetachedType(@NotNull PsiElement context) {
SoftReference<PsiType> cached = myCachedDetachedType;
PsiType type = cached == null ? null : cached.get();
if (type != null) return type;
try {
String combinedAnnotations = getCombinedAnnotationsText();
String text = combinedAnnotations.isEmpty() ? getText().trim() : combinedAnnotations + " " + getText().trim();
type = JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeFromText(text, context);
myCachedDetachedType = new SoftReference<PsiType>(type);
private void addTypeUseAnnotations(List<PsiAnnotation> list) {
PsiElement parent = this;
while (parent instanceof PsiTypeElement) {
PsiElement left = PsiTreeUtil.skipSiblingsBackward(parent, PsiComment.class, PsiWhiteSpace.class, PsiAnnotation.class);
if (left instanceof PsiModifierList) {
List<PsiAnnotation> annotations = PsiImplUtil.getTypeUseAnnotations((PsiModifierList)left);
if (annotations != null && annotations.size() > 0) {
list.addAll(annotations);
}
break;
}
if (left != null) break;
parent = parent.getParent();
}
catch (IncorrectOperationException e) {
return getType();
}
return type;
}
@NotNull
private String getCombinedAnnotationsText() {
final boolean typeAnnotationsSupported = PsiUtil.isLanguageLevel8OrHigher(this);
if (!typeAnnotationsSupported) return "";
return StringUtil.join(getApplicableAnnotations(), ANNOTATION_TEXT, " ");
private List<PsiType> collectTypes() {
List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiTypeElement.class);
return ContainerUtil.map(typeElements, new Function<PsiTypeElement, PsiType>() {
@Override
public PsiType fun(PsiTypeElement typeElement) {
return typeElement.getType();
}
});
}
private static final Function<PsiAnnotation, String> ANNOTATION_TEXT = new Function<PsiAnnotation, String>() {
@@ -204,48 +215,11 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
catch (IncorrectOperationException e) {
String s = "Parent: " + DebugUtil.psiToString(getParent(), false);
s += "Context: " + DebugUtil.psiToString(context, false);
LOG.error(s,e);
LOG.error(s, e);
return null;
}
}
@NotNull
private PsiType createWildcardType() {
final PsiType temp;
if (getFirstChildNode().getTreeNext() == null) {
temp = PsiWildcardType.createUnbounded(getManager());
}
else if (getLastChildNode().getElementType() == JavaElementType.TYPE) {
PsiTypeElement bound = SourceTreeToPsiMap.treeToPsiNotNull(getLastChildNode());
ASTNode keyword = getFirstChildNode();
while (keyword != null &&
keyword.getElementType() != JavaTokenType.EXTENDS_KEYWORD &&
keyword.getElementType() != JavaTokenType.SUPER_KEYWORD) {
keyword = keyword.getTreeNext();
}
if (keyword != null) {
IElementType i = keyword.getElementType();
if (i == JavaTokenType.EXTENDS_KEYWORD) {
temp = PsiWildcardType.createExtends(getManager(), bound.getType());
}
else if (i == JavaTokenType.SUPER_KEYWORD) {
temp = PsiWildcardType.createSuper(getManager(), bound.getType());
}
else {
LOG.assertTrue(false);
temp = PsiWildcardType.createUnbounded(getManager());
}
}
else {
temp = PsiWildcardType.createUnbounded(getManager());
}
}
else {
temp = PsiWildcardType.createUnbounded(getManager());
}
return temp;
}
@Override
public PsiJavaCodeReferenceElement getInnermostComponentReferenceElement() {
TreeElement firstChildNode = getFirstChildNode();
@@ -259,11 +233,14 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
}
@Override
public PsiAnnotationOwner getOwner(PsiAnnotation annotation) {
PsiElement next = PsiTreeUtil.skipSiblingsForward(annotation, PsiComment.class, PsiWhiteSpace.class);
if (next != null && next.getNode().getElementType() == JavaTokenType.LBRACKET) {
return getType(); // annotation belongs to array type dimension
public PsiAnnotationOwner getOwner(@NotNull PsiAnnotation annotation) {
assert annotation.getParent() == this : annotation.getParent();
PsiElement next = PsiTreeUtil.skipSiblingsForward(annotation, PsiComment.class, PsiWhiteSpace.class, PsiAnnotation.class);
if (PsiUtil.isJavaToken(next, JavaTokenType.LBRACKET)) {
return JavaSharedImplUtil.findAnnotatedSubtype(getType(), annotation);
}
return this;
}
@@ -275,7 +252,10 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
}
@Override
public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place){
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
PsiElement lastParent,
@NotNull PsiElement place) {
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, this);
return true;
}
@@ -290,12 +270,9 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
@Override
@NotNull
public PsiAnnotation[] getApplicableAnnotations() {
PsiAnnotation[] annotations = getAnnotations();
ArrayList<PsiAnnotation> list = new ArrayList<PsiAnnotation>(Arrays.asList(annotations));
PsiImplUtil.addTypeUseAnnotationsFromModifierList(getParent(), list);
return toAnnotationsArray(list);
List<PsiAnnotation> annotations = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiAnnotation.class);
addTypeUseAnnotations(annotations);
return annotations.toArray(PsiAnnotation.ARRAY_FACTORY.create(annotations.size()));
}
@Override
@@ -348,4 +325,9 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
return result;
}
@Override
public String toString() {
return "PsiTypeElement:" + getText();
}
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.impl.GeneratedMarkerVisitor;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.PsiTypeElementImpl;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
@@ -40,13 +39,7 @@ public class JavaSharedImplUtil {
private JavaSharedImplUtil() { }
public static PsiType getType(@NotNull PsiTypeElement typeElement, @NotNull PsiElement anchor, @NotNull PsiElement context) {
PsiType type;
if (typeElement instanceof PsiTypeElementImpl) {
type = ((PsiTypeElementImpl)typeElement).getDetachedType(context);
}
else {
type = typeElement.getType();
}
PsiType type = typeElement.getType();
List<PsiAnnotation[]> allAnnotations = collectAnnotations(anchor);
for (PsiAnnotation[] annotations : allAnnotations) {
@@ -7,6 +7,6 @@ import static java.lang.annotation.ElementType.*;
class C {
{
Object o = null;
@TA <caret>int @TA [] a = (@TA int[]) o;
@TA int @TA [] a = (@TA int @TA[]) o;
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.psi
import com.intellij.psi.*
import com.intellij.testFramework.LightIdeaTestCase
class AnnotatedTypeTest extends LightIdeaTestCase {
@SuppressWarnings("GrUnresolvedAccess")
public void testTypeComposition() {
def context = createFile("typeCompositionTest.java", """
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@interface A { }
@Target({TYPE_USE}) @interface TA { }
class E1 extends Exception { }
class E2 extends Exception { }
""")
def factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(), psi
psi = factory.createStatementFromText("@TA int @TA [] a = null", context)
assertEquals("@TA int @TA []", psi.declaredElements[0].type.presentableText)
psi = factory.createStatementFromText("@A int @TA [] a = null", context)
assertEquals("int @TA []", psi.declaredElements[0].type.presentableText)
psi = factory.createStatementFromText("try { } catch (@TA E1 | @TA E2 e) { }", context)
assertEquals("@TA E1 | @TA E2", psi.catchBlockParameters[0].type.presentableText)
psi = factory.createFieldFromText("@TA String @TA [] f @TA []", context)
assertEquals("@TA String @TA [] @TA []", psi.type.presentableText)
}
}