mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
check if annotations are type-use only when they're really needed (rarely)
This commit is contained in:
@@ -39,6 +39,10 @@ public class PsiArrayType extends PsiType.Stub {
|
||||
super(annotations);
|
||||
myComponentType = componentType;
|
||||
}
|
||||
public PsiArrayType(@NotNull PsiType componentType, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(annotations);
|
||||
myComponentType = componentType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -114,7 +118,9 @@ public class PsiArrayType extends PsiType.Stub {
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return obj != null && getClass().equals(obj.getClass()) && myComponentType.equals(((PsiArrayType)obj).getComponentType());
|
||||
return obj instanceof PsiArrayType &&
|
||||
(this instanceof PsiEllipsisType == obj instanceof PsiEllipsisType) &&
|
||||
myComponentType.equals(((PsiArrayType)obj).getComponentType());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
||||
@@ -53,6 +53,11 @@ public abstract class PsiClassType extends PsiType {
|
||||
myLanguageLevel = languageLevel;
|
||||
}
|
||||
|
||||
public PsiClassType(LanguageLevel languageLevel, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(annotations);
|
||||
myLanguageLevel = languageLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the class reference and returns the resulting class.
|
||||
*
|
||||
@@ -295,6 +300,10 @@ public abstract class PsiClassType extends PsiType {
|
||||
super(languageLevel, annotations);
|
||||
}
|
||||
|
||||
public Stub(LanguageLevel languageLevel, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(languageLevel, annotations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public final String getCanonicalText() {
|
||||
|
||||
@@ -35,6 +35,9 @@ public class PsiEllipsisType extends PsiArrayType {
|
||||
public PsiEllipsisType(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) {
|
||||
super(componentType, annotations);
|
||||
}
|
||||
public PsiEllipsisType(@NotNull PsiType componentType, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(componentType, annotations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiType createEllipsis(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) {
|
||||
@@ -71,7 +74,7 @@ public class PsiEllipsisType extends PsiArrayType {
|
||||
* @return the array type instance.
|
||||
*/
|
||||
public PsiType toArrayType() {
|
||||
return getComponentType().createArrayType(getAnnotations());
|
||||
return new PsiArrayType(getComponentType(), getAnnotationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,10 +82,6 @@ public class PsiEllipsisType extends PsiArrayType {
|
||||
return visitor.visitEllipsisType(this);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof PsiEllipsisType && super.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return super.hashCode() * 5;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ public class PsiPrimitiveType extends PsiType.Stub {
|
||||
super(annotations);
|
||||
myName = name;
|
||||
}
|
||||
public PsiPrimitiveType(@NonNls @NotNull String name, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(annotations);
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -51,10 +51,26 @@ public abstract class PsiType implements PsiAnnotationOwner {
|
||||
return ARRAY_FACTORY.create(count);
|
||||
}
|
||||
|
||||
private final PsiAnnotation[] myAnnotations;
|
||||
private final TypeAnnotationProvider myAnnotationProvider;
|
||||
|
||||
protected PsiType(@NotNull PsiAnnotation[] annotations) {
|
||||
myAnnotations = annotations;
|
||||
/**
|
||||
* Constructs a PsiType with given annotations
|
||||
*/
|
||||
protected PsiType(@NotNull final PsiAnnotation[] annotations) {
|
||||
this(annotations.length == 0 ? TypeAnnotationProvider.EMPTY : new TypeAnnotationProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiAnnotation[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a PsiType that will take its annotations from the given annotation provider.
|
||||
*/
|
||||
protected PsiType(@NotNull TypeAnnotationProvider annotations) {
|
||||
myAnnotationProvider = annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,15 +289,27 @@ public abstract class PsiType implements PsiAnnotationOwner {
|
||||
@NotNull
|
||||
public abstract PsiType[] getSuperTypes();
|
||||
|
||||
/**
|
||||
* @return provider for this type's annotations. Can be used to construct other PsiType instances
|
||||
* without actually evaluating the annotation array, which can be computationally expensive sometimes.
|
||||
*/
|
||||
@NotNull
|
||||
public final TypeAnnotationProvider getAnnotationProvider() {
|
||||
return myAnnotationProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return annotations for this type. Uses {@link #getAnnotationProvider()} to retrieve the annotations.
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiAnnotation[] getAnnotations() {
|
||||
return myAnnotations;
|
||||
return myAnnotationProvider.getAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
|
||||
for (PsiAnnotation annotation : myAnnotations) {
|
||||
for (PsiAnnotation annotation : getAnnotations()) {
|
||||
if (qualifiedName.equals(annotation.getQualifiedName())) {
|
||||
return annotation;
|
||||
}
|
||||
@@ -315,6 +343,10 @@ public abstract class PsiType implements PsiAnnotationOwner {
|
||||
super(annotations);
|
||||
}
|
||||
|
||||
public Stub(@NotNull TypeAnnotationProvider annotations) {
|
||||
super(annotations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public final String getCanonicalText() {
|
||||
|
||||
@@ -45,7 +45,7 @@ public class PsiWildcardType extends PsiType.Stub {
|
||||
myBound = bound;
|
||||
}
|
||||
|
||||
private PsiWildcardType(@NotNull PsiWildcardType type, @NotNull PsiAnnotation[] annotations) {
|
||||
private PsiWildcardType(@NotNull PsiWildcardType type, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(annotations);
|
||||
myManager = type.myManager;
|
||||
myIsExtending = type.myIsExtending;
|
||||
@@ -76,8 +76,19 @@ public class PsiWildcardType extends PsiType.Stub {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiWildcardType annotate(@NotNull PsiAnnotation[] annotations) {
|
||||
return annotations.length == 0 ? this : new PsiWildcardType(this, annotations);
|
||||
public PsiWildcardType annotate(@NotNull final PsiAnnotation[] annotations) {
|
||||
return annotations.length == 0 ? this : new PsiWildcardType(this, new TypeAnnotationProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiAnnotation[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiWildcardType annotate(@NotNull final TypeAnnotationProvider annotations) {
|
||||
return new PsiWildcardType(this, annotations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* An object that returns annotations for {@link PsiType}. Since computing type annotations might be computationally expensive sometimes,
|
||||
* this object is used to delay the calculation until annotations are really needed,
|
||||
* and to pass the annotations without calculating them when creating new types based on existing types.
|
||||
*
|
||||
* @see PsiType#getAnnotationProvider()
|
||||
* @see PsiType#PsiType(TypeAnnotationProvider)
|
||||
*/
|
||||
public interface TypeAnnotationProvider {
|
||||
TypeAnnotationProvider EMPTY = new TypeAnnotationProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiAnnotation[] getAnnotations() {
|
||||
return PsiAnnotation.EMPTY_ARRAY;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
PsiAnnotation[] getAnnotations();
|
||||
}
|
||||
@@ -1195,14 +1195,6 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
}
|
||||
throw new AssertionError("Invalid type: " + type + " of class " + type.getClass() + " " + customMessage);
|
||||
}
|
||||
for (PsiAnnotation annotation : type.getAnnotations()) {
|
||||
try {
|
||||
PsiUtilCore.ensureValid(annotation);
|
||||
}
|
||||
catch (PsiInvalidElementAccessException e) {
|
||||
throw customMessage == null? e : new RuntimeException(customMessage, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -42,7 +42,7 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx<PsiType> {
|
||||
PsiType mappedComponent = mapType(componentType);
|
||||
if (mappedComponent == null) return null;
|
||||
if (mappedComponent == componentType) return type;
|
||||
return new PsiArrayType(mappedComponent, type.getAnnotations());
|
||||
return new PsiArrayType(mappedComponent, type.getAnnotationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +51,7 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx<PsiType> {
|
||||
PsiType mappedComponent = mapType(componentType);
|
||||
if (mappedComponent == null) return null;
|
||||
if (mappedComponent == componentType) return type;
|
||||
return new PsiEllipsisType(mappedComponent, type.getAnnotations());
|
||||
return new PsiEllipsisType(mappedComponent, type.getAnnotationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -167,7 +167,7 @@ class TypeCorrector extends PsiTypeMapper {
|
||||
public PsiCorrectedClassType(LanguageLevel languageLevel,
|
||||
PsiClassType delegate,
|
||||
CorrectedResolveResult resolveResult) {
|
||||
super(languageLevel, delegate.getAnnotations());
|
||||
super(languageLevel, delegate.getAnnotationProvider());
|
||||
myDelegate = delegate;
|
||||
myResolveResult = resolveResult;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
myReference = reference;
|
||||
}
|
||||
|
||||
public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull TypeAnnotationProvider annotations) {
|
||||
super(level, annotations);
|
||||
myReference = reference;
|
||||
}
|
||||
|
||||
private static PsiAnnotation[] collectAnnotations(PsiJavaCodeReferenceElement reference) {
|
||||
List<PsiAnnotation> result = null;
|
||||
for (PsiElement child = reference.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
@@ -80,7 +85,7 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
@Override
|
||||
public PsiClassType setLanguageLevel(@NotNull final LanguageLevel languageLevel) {
|
||||
if (languageLevel.equals(myLanguageLevel)) return this;
|
||||
return new PsiClassReferenceType(myReference, languageLevel, getAnnotations());
|
||||
return new PsiClassReferenceType(myReference, languageLevel, getAnnotationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,13 +156,13 @@ public class PsiClassReferenceType extends PsiClassType.Stub {
|
||||
PsiManager manager = myReference.getManager();
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
|
||||
final PsiSubstitutor rawSubstitutor = factory.createRawSubstitutor(aClass);
|
||||
return factory.createType(aClass, rawSubstitutor, getLanguageLevel(), getAnnotations());
|
||||
return new PsiImmediateClassType(aClass, rawSubstitutor, getLanguageLevel(), getAnnotationProvider());
|
||||
}
|
||||
String qualifiedName = myReference.getQualifiedName();
|
||||
String name = myReference.getReferenceName();
|
||||
if (name == null) name = "";
|
||||
LightClassReference reference = new LightClassReference(myReference.getManager(), name, qualifiedName, myReference.getResolveScope());
|
||||
return new PsiClassReferenceType(reference, null, getAnnotations());
|
||||
return new PsiClassReferenceType(reference, null, getAnnotationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -96,6 +96,16 @@ public class PsiImmediateClassType extends PsiClassType.Stub {
|
||||
mySubstitutor = substitutor;
|
||||
assert substitutor.isValid();
|
||||
}
|
||||
public PsiImmediateClassType(@NotNull PsiClass aClass,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
@Nullable LanguageLevel level,
|
||||
@NotNull TypeAnnotationProvider annotations) {
|
||||
super(level, annotations);
|
||||
myClass = aClass;
|
||||
myManager = aClass.getManager();
|
||||
mySubstitutor = substitutor;
|
||||
assert substitutor.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiClass resolve() {
|
||||
@@ -298,6 +308,6 @@ public class PsiImmediateClassType extends PsiClassType.Stub {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType setLanguageLevel(@NotNull LanguageLevel level) {
|
||||
return level.equals(myLanguageLevel) ? this : new PsiImmediateClassType(myClass, mySubstitutor, level, getAnnotations());
|
||||
return level.equals(myLanguageLevel) ? this : new PsiImmediateClassType(myClass, mySubstitutor, level, getAnnotationProvider());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.impl.PsiJavaParserFacadeImpl;
|
||||
import com.intellij.psi.impl.source.tree.CompositePsiElement;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
@@ -34,6 +36,8 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement {
|
||||
@@ -77,7 +81,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
}
|
||||
|
||||
PsiType type = null;
|
||||
SmartList<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
|
||||
final SmartList<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
|
||||
|
||||
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue;
|
||||
@@ -97,25 +101,23 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
}
|
||||
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);
|
||||
addTypeUseCandidateAnnotations(annotations);
|
||||
String text = child.getText();
|
||||
type = annotations.isEmpty() ? PsiJavaParserFacadeImpl.getPrimitiveType(text)
|
||||
: new PsiPrimitiveType(text, filterTypeUse(annotations));
|
||||
}
|
||||
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);
|
||||
addTypeUseCandidateAnnotations(annotations);
|
||||
type = new PsiClassReferenceType((PsiJavaCodeReferenceElement)child, null, filterTypeUse(annotations));
|
||||
}
|
||||
else if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET)) {
|
||||
assert type != null : this;
|
||||
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
|
||||
type = type.createArrayType(array);
|
||||
type = new PsiArrayType(type, filterTypeUse(annotations));
|
||||
}
|
||||
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);
|
||||
type = new PsiEllipsisType(type, filterTypeUse(annotations));
|
||||
}
|
||||
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.QUEST) ||
|
||||
@@ -132,8 +134,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
else {
|
||||
type = PsiWildcardType.createUnbounded(getManager());
|
||||
}
|
||||
PsiAnnotation[] array = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true);
|
||||
type = ((PsiWildcardType)type).annotate(array);
|
||||
type = ((PsiWildcardType)type).annotate(filterTypeUse(annotations));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -155,13 +156,39 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
return type == null ? PsiType.NULL : type;
|
||||
}
|
||||
|
||||
private void addTypeUseAnnotations(List<PsiAnnotation> annotations) {
|
||||
@NotNull
|
||||
private static TypeAnnotationProvider filterTypeUse(List<PsiAnnotation> annotations) {
|
||||
if (annotations.isEmpty()) return TypeAnnotationProvider.EMPTY;
|
||||
|
||||
final ArrayList<PsiAnnotation> copy = ContainerUtil.newArrayList(annotations);
|
||||
annotations.clear();
|
||||
return new TypeAnnotationProvider() {
|
||||
private volatile PsiAnnotation[] myCached;
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiAnnotation[] getAnnotations() {
|
||||
PsiAnnotation[] result = myCached;
|
||||
if (result == null) {
|
||||
List<PsiAnnotation> filtered = ContainerUtil.filter(copy, new Condition<PsiAnnotation>() {
|
||||
@Override
|
||||
public boolean value(PsiAnnotation annotation) {
|
||||
return PsiImplUtil.isTypeAnnotation(annotation);
|
||||
}
|
||||
});
|
||||
myCached = result = filtered.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : filtered.toArray(new PsiAnnotation[filtered.size()]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void addTypeUseCandidateAnnotations(List<PsiAnnotation> annotations) {
|
||||
PsiElement parent = this;
|
||||
while (parent instanceof PsiTypeElement) {
|
||||
PsiElement left = PsiTreeUtil.skipSiblingsBackward(parent, INTERMEDIATES);
|
||||
|
||||
if (left instanceof PsiModifierList) {
|
||||
PsiImplUtil.collectTypeUseAnnotations((PsiModifierList)left, annotations);
|
||||
Collections.addAll(annotations, ((PsiModifierList)left).getAnnotations());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -220,7 +247,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
@NotNull
|
||||
public PsiAnnotation[] getApplicableAnnotations() {
|
||||
List<PsiAnnotation> annotations = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiAnnotation.class);
|
||||
addTypeUseAnnotations(annotations);
|
||||
addTypeUseCandidateAnnotations(annotations);
|
||||
return annotations.toArray(PsiAnnotation.ARRAY_FACTORY.create(annotations.size()));
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class JavaResolveCache {
|
||||
type = psiClass == null
|
||||
? type // for type with unresolved reference, leave it in the cache
|
||||
// for clients still might be able to retrieve its getCanonicalText() from the reference text
|
||||
: new PsiImmediateClassType(psiClass, result.getSubstitutor(), ((PsiClassReferenceType)type).getLanguageLevel(), type.getAnnotations());
|
||||
: new PsiImmediateClassType(psiClass, result.getSubstitutor(), ((PsiClassReferenceType)type).getLanguageLevel(), type.getAnnotationProvider());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user