mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PsiTypeElement.getType() fixed
This commit is contained in:
@@ -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;
|
||||
|
||||
+6
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user