diff --git a/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java b/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java index eb7a320cd359..da0ecbe9d625 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java @@ -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 myTypes; private final CachedValue myLubCache; - public PsiDisjunctionType(@NotNull final List types, @NotNull final PsiManager psiManager) { + public PsiDisjunctionType(@NotNull List 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() { + myLubCache = CachedValuesManager.getManager(myManager.getProject()).createCachedValue(new CachedValueProvider() { @Override public Result 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 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(); diff --git a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java index 498137e87709..bfb2c4fd816d 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java @@ -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 diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index 8bc973444dfd..5cdc217c5a98 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java @@ -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 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 flattened = flatten(conjuncts, new THashSet()); @@ -64,7 +70,7 @@ public class PsiIntersectionType extends PsiType { } if (types.size() > 1) { PsiType[] array = types.toArray(new PsiType[types.size()]); - for (Iterator iterator = types.iterator(); iterator.hasNext();) { + for (Iterator 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]; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java index d28240a22f30..5d5a9f9671bb 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java @@ -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 UNBOUNDED_WILDCARD = new Key("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; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 9105641fbf40..c9a3378d76ad 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -731,20 +731,17 @@ public class PsiImplUtil { return null; } - public static void addTypeUseAnnotationsFromModifierList(@NotNull PsiElement member, @NotNull List annotations) { - if (member instanceof PsiModifierListOwner) { - PsiModifierList modifierList = ((PsiModifierListOwner)member).getModifierList(); - if (modifierList != null) { - addTypeUseAnnotations(modifierList, annotations); - } - } - } + @Nullable + public static List getTypeUseAnnotations(@NotNull PsiModifierList modifierList) { + SmartList result = null; - public static void addTypeUseAnnotations(@NotNull PsiModifierList modifierList, @NotNull List annotations) { for (PsiAnnotation annotation : modifierList.getAnnotations()) { if (findApplicableTarget(annotation, TargetType.TYPE_USE) == TargetType.TYPE_USE) { - annotations.add(annotation); + if (result == null) result = new SmartList(); + result.add(annotation); } } + + return result; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 1fd39555af98..62df78742a0b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -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; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index e5cd665e9f57..9605d07b619c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -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 typeAnnotations = PsiImplUtil.getTypeUseAnnotations(modifierList); + if (typeAnnotations != null && typeAnnotations.size() > 0) { + annotations.addAll(typeAnnotations); + } + } } return annotations; 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 62bf03318488..4db29fea502f 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 @@ -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 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 typeAnnotations = new ArrayList(); - 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 typeElements = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiTypeElement.class); - final List types = ContainerUtil.map(typeElements, new Function() { - @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 typeAnnotations) { - final int size = typeAnnotations.size(); - return size == 0 ? PsiAnnotation.EMPTY_ARRAY : typeAnnotations.toArray(new PsiAnnotation[size]); + private PsiType calculateType() { + PsiType type = null; + SmartList annotations = new SmartList(); + + 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 types = collectTypes(); + assert types.size() > 0 : this; + type = PsiIntersectionType.createIntersection(types); + break; + } + + if (PsiUtil.isJavaToken(child, JavaTokenType.OR)) { + List 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 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(type); + private void addTypeUseAnnotations(List list) { + PsiElement parent = this; + while (parent instanceof PsiTypeElement) { + PsiElement left = PsiTreeUtil.skipSiblingsBackward(parent, PsiComment.class, PsiWhiteSpace.class, PsiAnnotation.class); + + if (left instanceof PsiModifierList) { + List 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 collectTypes() { + List typeElements = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiTypeElement.class); + return ContainerUtil.map(typeElements, new Function() { + @Override + public PsiType fun(PsiTypeElement typeElement) { + return typeElement.getType(); + } + }); } private static final Function ANNOTATION_TEXT = new Function() { @@ -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 list = new ArrayList(Arrays.asList(annotations)); - PsiImplUtil.addTypeUseAnnotationsFromModifierList(getParent(), list); - - return toAnnotationsArray(list); + List 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(); + } } 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 50b2f5b45647..9b5fcf1a81b5 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 @@ -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 allAnnotations = collectAnnotations(anchor); for (PsiAnnotation[] annotations : allAnnotations) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterTypeAnnoArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterTypeAnnoArray.java index 4d69c363e6eb..659a3bb0b844 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterTypeAnnoArray.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterTypeAnnoArray.java @@ -7,6 +7,6 @@ import static java.lang.annotation.ElementType.*; class C { { Object o = null; - @TA int @TA [] a = (@TA int[]) o; + @TA int @TA [] a = (@TA int @TA[]) o; } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy new file mode 100644 index 000000000000..076b12346804 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy @@ -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) + } +}