[SLC] avoid redundant empty array allocation and add new array creation
we should instantiate a new array on each request to avoid unexpected mutation from a usage side ^KT-56046
This commit is contained in:
committed by
Space Team
parent
3b9318bd3a
commit
347dc83773
+1
-1
@@ -9,7 +9,7 @@ import com.intellij.psi.PsiAnnotation
|
|||||||
import com.intellij.psi.PsiModifierList
|
import com.intellij.psi.PsiModifierList
|
||||||
|
|
||||||
internal sealed interface AnnotationsBox {
|
internal sealed interface AnnotationsBox {
|
||||||
fun annotations(owner: PsiModifierList): Array<PsiAnnotation>
|
fun annotationsArray(owner: PsiModifierList): Array<PsiAnnotation>
|
||||||
fun findAnnotation(owner: PsiModifierList, qualifiedName: String): PsiAnnotation?
|
fun findAnnotation(owner: PsiModifierList, qualifiedName: String): PsiAnnotation?
|
||||||
fun hasAnnotation(owner: PsiModifierList, qualifiedName: String): Boolean = findAnnotation(owner, qualifiedName) != null
|
fun hasAnnotation(owner: PsiModifierList, qualifiedName: String): Boolean = findAnnotation(owner, qualifiedName) != null
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,6 +9,6 @@ import com.intellij.psi.PsiAnnotation
|
|||||||
import com.intellij.psi.PsiModifierList
|
import com.intellij.psi.PsiModifierList
|
||||||
|
|
||||||
internal object EmptyAnnotationsBox : AnnotationsBox {
|
internal object EmptyAnnotationsBox : AnnotationsBox {
|
||||||
override fun annotations(owner: PsiModifierList): Array<PsiAnnotation> = PsiAnnotation.EMPTY_ARRAY
|
override fun annotationsArray(owner: PsiModifierList): Array<PsiAnnotation> = PsiAnnotation.EMPTY_ARRAY
|
||||||
override fun findAnnotation(owner: PsiModifierList, qualifiedName: String): PsiAnnotation? = null
|
override fun findAnnotation(owner: PsiModifierList, qualifiedName: String): PsiAnnotation? = null
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-18
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.light.classes.symbol.annotations
|
|||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
import com.intellij.psi.PsiAnnotation
|
||||||
import com.intellij.psi.PsiModifierList
|
import com.intellij.psi.PsiModifierList
|
||||||
|
import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
@@ -17,10 +18,10 @@ internal class LazyAnnotationsBox(
|
|||||||
private val additionalAnnotationsProvider: AdditionalAnnotationsProvider = EmptyAdditionalAnnotationsProvider,
|
private val additionalAnnotationsProvider: AdditionalAnnotationsProvider = EmptyAdditionalAnnotationsProvider,
|
||||||
private val annotationFilter: AnnotationFilter = AlwaysAllowedAnnotationFilter,
|
private val annotationFilter: AnnotationFilter = AlwaysAllowedAnnotationFilter,
|
||||||
) : AnnotationsBox {
|
) : AnnotationsBox {
|
||||||
private val annotationsArray: AtomicReference<Array<PsiAnnotation>?> = AtomicReference()
|
private val cachedCollection: AtomicReference<Collection<PsiAnnotation>?> = AtomicReference()
|
||||||
|
|
||||||
override fun annotations(owner: PsiModifierList): Array<PsiAnnotation> {
|
private fun getOrComputeCachedAnnotations(owner: PsiModifierList): Collection<PsiAnnotation> {
|
||||||
annotationsArray.get()?.let { return it }
|
cachedCollection.get()?.let { return it }
|
||||||
|
|
||||||
val annotations = annotationsProvider.annotationInfos().mapNotNullTo(SmartList<PsiAnnotation>()) { applicationInfo ->
|
val annotations = annotationsProvider.annotationInfos().mapNotNullTo(SmartList<PsiAnnotation>()) { applicationInfo ->
|
||||||
applicationInfo.classId?.let { _ ->
|
applicationInfo.classId?.let { _ ->
|
||||||
@@ -32,17 +33,14 @@ internal class LazyAnnotationsBox(
|
|||||||
additionalAnnotationsProvider.addAllAnnotations(annotations, foundQualifiers, owner)
|
additionalAnnotationsProvider.addAllAnnotations(annotations, foundQualifiers, owner)
|
||||||
|
|
||||||
val resultAnnotations = annotationFilter.filtered(annotations)
|
val resultAnnotations = annotationFilter.filtered(annotations)
|
||||||
return setAnnotationsArray(
|
cachedCollection.compareAndSet(null, resultAnnotations)
|
||||||
if (resultAnnotations.isNotEmpty()) resultAnnotations.toTypedArray<PsiAnnotation>() else PsiAnnotation.EMPTY_ARRAY
|
|
||||||
)
|
return getOrComputeCachedAnnotations(owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setAnnotationsArray(array: Array<PsiAnnotation>): Array<PsiAnnotation> =
|
override fun annotationsArray(owner: PsiModifierList): Array<PsiAnnotation> {
|
||||||
if (annotationsArray.compareAndSet(null, array)) {
|
return getOrComputeCachedAnnotations(owner).toArrayIfNotEmptyOrDefault(PsiAnnotation.EMPTY_ARRAY)
|
||||||
array
|
}
|
||||||
} else {
|
|
||||||
annotationsArray.get() ?: error("Unexpected state")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findAnnotation(
|
override fun findAnnotation(
|
||||||
owner: PsiModifierList,
|
owner: PsiModifierList,
|
||||||
@@ -52,8 +50,8 @@ internal class LazyAnnotationsBox(
|
|||||||
fun findAnnotation(owner: PsiModifierList, qualifiedName: String, withAdditionalAnnotations: Boolean): PsiAnnotation? {
|
fun findAnnotation(owner: PsiModifierList, qualifiedName: String, withAdditionalAnnotations: Boolean): PsiAnnotation? {
|
||||||
if (!annotationFilter.isAllowed(qualifiedName)) return null
|
if (!annotationFilter.isAllowed(qualifiedName)) return null
|
||||||
|
|
||||||
annotationsArray.get()?.let { array ->
|
cachedCollection.get()?.let { annotations ->
|
||||||
return array.find { it.qualifiedName == qualifiedName }
|
return annotations.find { it.qualifiedName == qualifiedName }
|
||||||
}
|
}
|
||||||
|
|
||||||
val specialAnnotationClassId = specialAnnotationsList[qualifiedName]
|
val specialAnnotationClassId = specialAnnotationsList[qualifiedName]
|
||||||
@@ -66,21 +64,21 @@ internal class LazyAnnotationsBox(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
return specialAnnotation ?: annotations(owner).find { it.qualifiedName == qualifiedName }
|
return specialAnnotation ?: getOrComputeCachedAnnotations(owner).find { it.qualifiedName == qualifiedName }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasAnnotation(owner: PsiModifierList, qualifiedName: String): Boolean {
|
override fun hasAnnotation(owner: PsiModifierList, qualifiedName: String): Boolean {
|
||||||
if (!annotationFilter.isAllowed(qualifiedName)) return false
|
if (!annotationFilter.isAllowed(qualifiedName)) return false
|
||||||
|
|
||||||
annotationsArray.get()?.let { array ->
|
cachedCollection.get()?.let { annotations ->
|
||||||
return array.any { it.qualifiedName == qualifiedName }
|
return annotations.any { it.qualifiedName == qualifiedName }
|
||||||
}
|
}
|
||||||
|
|
||||||
val specialAnnotationClassId = specialAnnotationsList[qualifiedName]
|
val specialAnnotationClassId = specialAnnotationsList[qualifiedName]
|
||||||
return if (specialAnnotationClassId != null) {
|
return if (specialAnnotationClassId != null) {
|
||||||
specialAnnotationClassId in annotationsProvider
|
specialAnnotationClassId in annotationsProvider
|
||||||
} else {
|
} else {
|
||||||
annotations(owner).any { it.qualifiedName == qualifiedName }
|
getOrComputeCachedAnnotations(owner).any { it.qualifiedName == qualifiedName }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-10
@@ -7,24 +7,23 @@ package org.jetbrains.kotlin.light.classes.symbol.annotations
|
|||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
import com.intellij.psi.PsiAnnotation
|
||||||
import com.intellij.psi.PsiModifierList
|
import com.intellij.psi.PsiModifierList
|
||||||
|
import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
internal class SimpleAnnotationsBox(private val annotationsComputer: (PsiModifierList) -> Collection<PsiAnnotation>) : AnnotationsBox {
|
internal class SimpleAnnotationsBox(private val annotationsComputer: (PsiModifierList) -> Collection<PsiAnnotation>) : AnnotationsBox {
|
||||||
private val annotations: AtomicReference<Array<PsiAnnotation>?> = AtomicReference()
|
private val cachedCollection: AtomicReference<Collection<PsiAnnotation>?> = AtomicReference()
|
||||||
|
|
||||||
private fun getOrComputeAnnotations(owner: PsiModifierList): Array<PsiAnnotation> {
|
private fun getOrComputeAnnotations(owner: PsiModifierList): Collection<PsiAnnotation> {
|
||||||
annotations.get()?.let { return it }
|
cachedCollection.get()?.let { return it }
|
||||||
|
|
||||||
val nonCachedAnnotations = annotationsComputer(owner)
|
val nonCachedAnnotations = annotationsComputer(owner)
|
||||||
val resultArray = if (nonCachedAnnotations.isEmpty()) PsiAnnotation.EMPTY_ARRAY else nonCachedAnnotations.toTypedArray()
|
cachedCollection.compareAndSet(null, nonCachedAnnotations)
|
||||||
return if (annotations.compareAndSet(null, resultArray)) {
|
return getOrComputeAnnotations(owner)
|
||||||
resultArray
|
|
||||||
} else {
|
|
||||||
getOrComputeAnnotations(owner)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun annotations(owner: PsiModifierList): Array<PsiAnnotation> = getOrComputeAnnotations(owner)
|
override fun annotationsArray(
|
||||||
|
owner: PsiModifierList,
|
||||||
|
): Array<PsiAnnotation> = getOrComputeAnnotations(owner).toArrayIfNotEmptyOrDefault(PsiAnnotation.EMPTY_ARRAY)
|
||||||
|
|
||||||
override fun findAnnotation(
|
override fun findAnnotation(
|
||||||
owner: PsiModifierList,
|
owner: PsiModifierList,
|
||||||
|
|||||||
+4
-3
@@ -8,18 +8,19 @@ package org.jetbrains.kotlin.light.classes.symbol.annotations
|
|||||||
import com.intellij.psi.PsiNameValuePair
|
import com.intellij.psi.PsiNameValuePair
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
|
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
|
||||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||||
|
import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault
|
||||||
|
|
||||||
internal class SymbolLightLazyAnnotationParameterList(
|
internal class SymbolLightLazyAnnotationParameterList(
|
||||||
parent: SymbolLightAbstractAnnotation,
|
parent: SymbolLightAbstractAnnotation,
|
||||||
private val lazyArguments: Lazy<List<KtNamedAnnotationValue>>,
|
private val lazyArguments: Lazy<List<KtNamedAnnotationValue>>,
|
||||||
) : SymbolLightAbstractAnnotationParameterList(parent) {
|
) : SymbolLightAbstractAnnotationParameterList(parent) {
|
||||||
private val _attributes: Array<PsiNameValuePair> by lazyPub {
|
private val _attributes: Collection<PsiNameValuePair> by lazyPub {
|
||||||
val attributes = lazyArguments.value.map {
|
val attributes = lazyArguments.value.map {
|
||||||
SymbolNameValuePairForAnnotationArgument(it, this)
|
SymbolNameValuePairForAnnotationArgument(it, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes.isEmpty()) PsiNameValuePair.EMPTY_ARRAY else attributes.toTypedArray()
|
attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAttributes(): Array<PsiNameValuePair> = _attributes
|
override fun getAttributes(): Array<PsiNameValuePair> = _attributes.toArrayIfNotEmptyOrDefault(PsiNameValuePair.EMPTY_ARRAY)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ internal class SymbolLightClassForEnumEntry(
|
|||||||
|
|
||||||
override fun getContainingClass(): PsiClass = enumClass
|
override fun getContainingClass(): PsiClass = enumClass
|
||||||
|
|
||||||
override fun getTypeParameters(): Array<PsiTypeParameter> = emptyArray()
|
override fun getTypeParameters(): Array<PsiTypeParameter> = PsiTypeParameter.EMPTY_ARRAY
|
||||||
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
||||||
|
|
||||||
override fun getQualifiedName(): String = "${enumConstant.containingClass.qualifiedName}.${enumConstant.name}"
|
override fun getQualifiedName(): String = "${enumConstant.containingClass.qualifiedName}.${enumConstant.name}"
|
||||||
|
|||||||
+1
-2
@@ -236,8 +236,7 @@ class SymbolLightClassForFacade(
|
|||||||
return JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope)
|
return JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSupers(): Array<PsiClass> =
|
override fun getSupers(): Array<PsiClass> = superClass?.let { arrayOf(it) } ?: PsiClass.EMPTY_ARRAY
|
||||||
superClass?.let { arrayOf(it) } ?: arrayOf()
|
|
||||||
|
|
||||||
override fun getSuperTypes(): Array<PsiClassType> =
|
override fun getSuperTypes(): Array<PsiClassType> =
|
||||||
arrayOf(PsiType.getJavaLangObject(manager, resolveScope))
|
arrayOf(PsiType.getJavaLangObject(manager, resolveScope))
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ internal class SymbolLightClassForInterfaceDefaultImpls(private val containingCl
|
|||||||
override fun hashCode(): Int = containingClass.hashCode()
|
override fun hashCode(): Int = containingClass.hashCode()
|
||||||
|
|
||||||
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
||||||
override fun getTypeParameters(): Array<PsiTypeParameter> = emptyArray()
|
override fun getTypeParameters(): Array<PsiTypeParameter> = PsiTypeParameter.EMPTY_ARRAY
|
||||||
|
|
||||||
override fun computeModifierList(): PsiModifierList = SymbolLightClassModifierList(
|
override fun computeModifierList(): PsiModifierList = SymbolLightClassModifierList(
|
||||||
containingDeclaration = this,
|
containingDeclaration = this,
|
||||||
|
|||||||
+3
-4
@@ -12,12 +12,11 @@ internal abstract class SymbolLightPsiJavaCodeReferenceElementBase(private val k
|
|||||||
PsiElement by ktElement,
|
PsiElement by ktElement,
|
||||||
PsiJavaCodeReferenceElement {
|
PsiJavaCodeReferenceElement {
|
||||||
|
|
||||||
override fun multiResolve(incompleteCode: Boolean): Array<JavaResolveResult> = emptyArray()
|
override fun multiResolve(incompleteCode: Boolean): Array<JavaResolveResult> = JavaResolveResult.EMPTY_ARRAY
|
||||||
|
|
||||||
override fun processVariants(processor: PsiScopeProcessor) {}
|
override fun processVariants(processor: PsiScopeProcessor) {}
|
||||||
|
|
||||||
override fun advancedResolve(incompleteCode: Boolean): JavaResolveResult =
|
override fun advancedResolve(incompleteCode: Boolean): JavaResolveResult = JavaResolveResult.EMPTY
|
||||||
JavaResolveResult.EMPTY
|
|
||||||
|
|
||||||
override fun getQualifier(): PsiElement? = null
|
override fun getQualifier(): PsiElement? = null
|
||||||
|
|
||||||
@@ -27,7 +26,7 @@ internal abstract class SymbolLightPsiJavaCodeReferenceElementBase(private val k
|
|||||||
|
|
||||||
override fun getParameterList(): PsiReferenceParameterList? = null
|
override fun getParameterList(): PsiReferenceParameterList? = null
|
||||||
|
|
||||||
override fun getTypeParameters(): Array<PsiType> = emptyArray()
|
override fun getTypeParameters(): Array<PsiType> = PsiType.EMPTY_ARRAY
|
||||||
|
|
||||||
override fun isQualified(): Boolean = false
|
override fun isQualified(): Boolean = false
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ internal sealed class SymbolLightModifierList<out T : KtLightElement<KtModifierL
|
|||||||
override fun hasExplicitModifier(name: String) = hasModifierProperty(name)
|
override fun hasExplicitModifier(name: String) = hasModifierProperty(name)
|
||||||
override fun hasModifierProperty(name: String): Boolean = modifiersBox.hasModifier(name)
|
override fun hasModifierProperty(name: String): Boolean = modifiersBox.hasModifier(name)
|
||||||
|
|
||||||
override fun getAnnotations(): Array<PsiAnnotation> = annotationsBox.annotations(this)
|
override fun getAnnotations(): Array<PsiAnnotation> = annotationsBox.annotationsArray(this)
|
||||||
override fun getApplicableAnnotations(): Array<PsiAnnotation> = annotations
|
override fun getApplicableAnnotations(): Array<PsiAnnotation> = annotations
|
||||||
override fun findAnnotation(qualifiedName: String): PsiAnnotation? = annotationsBox.findAnnotation(this, qualifiedName)
|
override fun findAnnotation(qualifiedName: String): PsiAnnotation? = annotationsBox.findAnnotation(this, qualifiedName)
|
||||||
override fun hasAnnotation(qualifiedName: String): Boolean = annotationsBox.hasAnnotation(this, qualifiedName)
|
override fun hasAnnotation(qualifiedName: String): Boolean = annotationsBox.hasAnnotation(this, qualifiedName)
|
||||||
|
|||||||
+4
-3
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.asJava.classes.lazyPub
|
|||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.basicIsEquivalentTo
|
import org.jetbrains.kotlin.light.classes.symbol.basicIsEquivalentTo
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.compareSymbolPointers
|
import org.jetbrains.kotlin.light.classes.symbol.compareSymbolPointers
|
||||||
|
import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.withSymbol
|
import org.jetbrains.kotlin.light.classes.symbol.withSymbol
|
||||||
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ internal class SymbolLightTypeParameterList(
|
|||||||
place: PsiElement
|
place: PsiElement
|
||||||
): Boolean = typeParameters.all { processor.execute(it, state) }
|
): Boolean = typeParameters.all { processor.execute(it, state) }
|
||||||
|
|
||||||
private val _typeParameters: Array<PsiTypeParameter> by lazyPub {
|
private val _typeParameters: Collection<PsiTypeParameter> by lazyPub {
|
||||||
symbolWithTypeParameterPointer.withSymbol(ktModule) {
|
symbolWithTypeParameterPointer.withSymbol(ktModule) {
|
||||||
it.typeParameters.mapIndexed { index, parameter ->
|
it.typeParameters.mapIndexed { index, parameter ->
|
||||||
SymbolLightTypeParameter(
|
SymbolLightTypeParameter(
|
||||||
@@ -48,11 +49,11 @@ internal class SymbolLightTypeParameterList(
|
|||||||
index = index,
|
index = index,
|
||||||
typeParameterSymbol = parameter,
|
typeParameterSymbol = parameter,
|
||||||
)
|
)
|
||||||
}.toTypedArray()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTypeParameters(): Array<PsiTypeParameter> = _typeParameters
|
override fun getTypeParameters(): Array<PsiTypeParameter> = _typeParameters.toArrayIfNotEmptyOrDefault(PsiTypeParameter.EMPTY_ARRAY)
|
||||||
|
|
||||||
override fun getTypeParameterIndex(typeParameter: PsiTypeParameter?): Int = _typeParameters.indexOf(typeParameter)
|
override fun getTypeParameterIndex(typeParameter: PsiTypeParameter?): Int = _typeParameters.indexOf(typeParameter)
|
||||||
|
|
||||||
|
|||||||
+4
@@ -271,3 +271,7 @@ internal inline fun <T : KtSymbol, R> KtSymbolPointer<T>.withSymbol(
|
|||||||
internal val KtPropertySymbol.isConstOrJvmField: Boolean get() = isConst || hasJvmFieldAnnotation()
|
internal val KtPropertySymbol.isConstOrJvmField: Boolean get() = isConst || hasJvmFieldAnnotation()
|
||||||
internal val KtPropertySymbol.isConst: Boolean get() = (this as? KtKotlinPropertySymbol)?.isConst == true
|
internal val KtPropertySymbol.isConst: Boolean get() = (this as? KtKotlinPropertySymbol)?.isConst == true
|
||||||
internal val KtPropertySymbol.isLateInit: Boolean get() = (this as? KtKotlinPropertySymbol)?.isLateInit == true
|
internal val KtPropertySymbol.isLateInit: Boolean get() = (this as? KtKotlinPropertySymbol)?.isLateInit == true
|
||||||
|
|
||||||
|
internal inline fun <reified T> Collection<T>.toArrayIfNotEmptyOrDefault(default: Array<T>): Array<T> {
|
||||||
|
return if (isNotEmpty()) toTypedArray() else default
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user