Remove class delegate requests from annotations and modifier lists

(#EA-144876 and #EA-144882 Fixed)
This commit is contained in:
Igor Yakovlev
2019-06-20 20:11:17 +03:00
parent 3146b12471
commit 4c1d0678eb
6 changed files with 119 additions and 52 deletions
@@ -56,6 +56,16 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import java.util.*
import javax.swing.Icon
private class KtLightClassModifierList(containingClass: KtLightClassForSourceDeclaration, computeModifiers: () -> Set<String>) :
KtLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
private val modifiers by lazyPub { computeModifiers() }
override fun hasModifierProperty(name: String): Boolean =
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
}
abstract class KtLightClassForSourceDeclaration(
protected val classOrObject: KtClassOrObject,
private val forceUsingOldLightClasses: Boolean = false
@@ -182,7 +192,7 @@ abstract class KtLightClassForSourceDeclaration(
override fun getName(): String? = classOrObject.nameAsName?.asString()
private val _modifierList: PsiModifierList by lazyPub { KtLightClassModifierList(this) }
private val _modifierList: PsiModifierList by lazyPub { KtLightClassModifierList(this) { computeModifiers() } }
override fun getModifierList(): PsiModifierList? = _modifierList
@@ -437,16 +447,6 @@ abstract class KtLightClassForSourceDeclaration(
override val originKind: LightClassOriginKind
get() = LightClassOriginKind.SOURCE
private class KtLightClassModifierList(containingClass: KtLightClassForSourceDeclaration) :
KtLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
private val modifiers by lazyPub { containingClass.computeModifiers() }
override fun hasModifierProperty(name: String): Boolean =
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
}
open fun isFinal(isFinalByPsi: Boolean): Boolean {
// annotations can make class open via 'allopen' plugin
if (!isPossiblyAffectedByAllOpen() || !isFinalByPsi) return isFinalByPsi
@@ -61,7 +61,7 @@ class KtUltraLightAnnotationForDescriptor(
private val annotationDescriptor: AnnotationDescriptor,
private val ultraLightSupport: KtUltraLightSupport,
parent: PsiElement
) : KtLightAbstractAnnotation(parent, { error("clsDelegate for annotation based on descriptor: $annotationDescriptor") }) {
) : KtLightAbstractAnnotation(parent, computeDelegate = null) {
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = null
override fun getMetaData(): PsiMetaData? = null
@@ -14,6 +14,8 @@ import com.intellij.psi.impl.light.LightMethodBuilder
import org.jetbrains.kotlin.asJava.builder.LightClassData
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
import org.jetbrains.kotlin.asJava.elements.KtUltraLightModifierList
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -40,6 +42,20 @@ import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val support: KtUltraLightSupport) :
KtLightClassImpl(classOrObject) {
private class KtUltraLightClassModifierList(
private val containingClass: KtLightClassForSourceDeclaration,
private val computeModifiers: () -> Set<String>
) :
KtUltraLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
private val modifiers by lazyPub { computeModifiers() }
override fun hasModifierProperty(name: String): Boolean =
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
override fun copy(): PsiElement = KtUltraLightClassModifierList(containingClass, computeModifiers)
}
private val membersBuilder by lazyPub {
UltraLightMembersCreator(
this,
@@ -74,6 +90,12 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
override fun getDelegate(): PsiClass = forTooComplex { super.getDelegate() }
private val _modifierList: PsiModifierList? by lazyPub {
if (tooComplex) super.getModifierList() else KtUltraLightClassModifierList(this) { computeModifiers() }
}
override fun getModifierList(): PsiModifierList? = _modifierList
private fun allSuperTypes() =
getDescriptor()?.typeConstructor?.supertypes.orEmpty().asSequence()
@@ -170,7 +192,8 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
// Probably, the same should work for const vals but it doesn't at the moment (see KT-28294)
if (isCompanion && (containingClass?.isInterface == false || property.isJvmField())) continue
membersBuilder.createPropertyField(property, usedNames, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add)
membersBuilder.createPropertyField(property, usedNames, forceStatic = this.classOrObject is KtObjectDeclaration)
?.let(result::add)
}
}
@@ -12,8 +12,10 @@ import com.intellij.psi.util.TypeConversionUtil
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightSimpleModifierList
import org.jetbrains.kotlin.asJava.elements.KtUltraLightSimpleModifierList
import org.jetbrains.kotlin.codegen.PropertyCodegen
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -28,6 +30,30 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.types.KotlinType
private class KtUltraLightSimpleModifierListField(
private val support: KtUltraLightSupport,
private val declaration: KtNamedDeclaration,
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>,
private val modifiers: Set<String>
) : KtUltraLightSimpleModifierList(owner, modifiers) {
override fun hasModifierProperty(name: String): Boolean = when (name) {
PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME)
PsiModifier.TRANSIENT -> hasFieldAnnotation(TRANSIENT_ANNOTATION_FQ_NAME)
else -> super.hasModifierProperty(name)
}
private fun hasFieldAnnotation(fqName: FqName): Boolean {
val annotation = support.findAnnotation(declaration, fqName)?.first ?: return false
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: return true
val expectedTarget =
if (declaration is KtProperty && declaration.hasDelegate()) AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
else AnnotationUseSiteTarget.FIELD
return target == expectedTarget
}
override fun copy() = KtUltraLightSimpleModifierListField(support, declaration, owner, modifiers)
}
internal open class KtUltraLightField(
protected val declaration: KtNamedDeclaration,
name: String,
@@ -37,26 +63,13 @@ internal open class KtUltraLightField(
) : LightFieldBuilder(name, PsiType.NULL, declaration), KtLightField,
KtUltraLightElementWithNullabilityAnnotation<KtDeclaration, PsiField> {
private val modList = object : KtLightSimpleModifierList(this, modifiers) {
override fun hasModifierProperty(name: String): Boolean = when (name) {
PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME)
PsiModifier.TRANSIENT -> hasFieldAnnotation(TRANSIENT_ANNOTATION_FQ_NAME)
else -> super.hasModifierProperty(name)
}
private fun hasFieldAnnotation(fqName: FqName): Boolean {
val annotation = support.findAnnotation(declaration, fqName)?.first ?: return false
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: return true
val expectedTarget =
if (declaration is KtProperty && declaration.hasDelegate()) AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
else AnnotationUseSiteTarget.FIELD
return target == expectedTarget
}
private val modifierList by lazyPub {
KtUltraLightSimpleModifierListField(support, declaration, this, modifiers)
}
override fun isEquivalentTo(another: PsiElement?): Boolean = kotlinOrigin == another
override fun getModifierList(): PsiModifierList = modList
override fun getModifierList(): PsiModifierList = modifierList
override fun hasModifierProperty(name: String): Boolean =
modifierList.hasModifierProperty(name) //can be removed after IDEA platform does the same
@@ -20,12 +20,14 @@ import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiModifierListOwner
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.classes.KtUltraLightElementWithNullabilityAnnotation
import org.jetbrains.kotlin.asJava.classes.KtUltraLightNullabilityAnnotation
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.toLightAnnotation
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -91,6 +93,29 @@ abstract class KtLightModifierList<out T : KtLightElement<KtModifierListOwner, P
}
open class KtUltraLightSimpleModifierList(
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>, private val modifiers: Set<String>
) : KtUltraLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner) {
override fun hasModifierProperty(name: String) = name in modifiers
override fun copy() = KtUltraLightSimpleModifierList(owner, modifiers)
}
abstract class KtUltraLightModifierList<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner: T) :
KtLightModifierList<T>(owner) {
override val clsDelegate: PsiModifierList
get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!")
private fun throwInvalidOperation(): Nothing = throw IncorrectOperationException()
override fun setModifierProperty(name: String, value: Boolean): Unit = throwInvalidOperation()
override fun checkSetModifierProperty(name: String, value: Boolean): Unit = throwInvalidOperation()
override fun addAnnotation(qualifiedName: String): PsiAnnotation = throwInvalidOperation()
}
open class KtLightSimpleModifierList(
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>, private val modifiers: Set<String>
) : KtLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner) {
@@ -119,10 +144,17 @@ private fun lightAnnotationsForEntries(lightModifierList: KtLightModifierList<*>
.groupBy({ it.first }) { it.second }
.flatMap { (fqName, entries) ->
entries.mapIndexed { index, entry ->
KtLightAnnotationForSourceEntry(fqName, entry, lightModifierList) {
lightModifierList.clsDelegate.annotations.filter { it.qualifiedName == fqName }.getOrNull(index)
?: KtLightNonExistentAnnotation(lightModifierList)
}
val lazyClsDelegate = if (lightModifierList !is KtUltraLightModifierList) {
lazyPub {
lightModifierList.clsDelegate.annotations
.filter { it.qualifiedName == fqName }
.getOrNull(index)
?: KtLightNonExistentAnnotation(lightModifierList)
}
} else null
KtLightAnnotationForSourceEntry(fqName, entry, lightModifierList, lazyClsDelegate)
}
}
}
@@ -54,17 +54,14 @@ import org.jetbrains.kotlin.types.typeUtil.nullability
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.asJava.elements.lightAnnotations")
abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: () -> PsiAnnotation) :
abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: Lazy<PsiAnnotation>?) :
KtLightElementBase(parent), PsiAnnotation, KtLightElement<KtCallElement, PsiAnnotation> {
private val _clsDelegate: PsiAnnotation by lazyPub(computeDelegate)
override val clsDelegate: PsiAnnotation
get() {
if (!accessAnnotationsClsDelegateIsAllowed && ApplicationManager.getApplication().isUnitTestMode && this !is KtLightNonSourceAnnotation)
LOG.error("KtLightAbstractAnnotation clsDelegate requested for ${this.javaClass}")
return _clsDelegate
}
override val clsDelegate: PsiAnnotation by lazyPub {
if (!accessAnnotationsClsDelegateIsAllowed && ApplicationManager.getApplication().isUnitTestMode && this !is KtLightNonSourceAnnotation)
LOG.error("KtLightAbstractAnnotation clsDelegate requested for ${this.javaClass}")
computeDelegate?.value ?: throw IllegalStateException("Cannot get class delegate for annotation light class")
}
override fun getNameReferenceElement() = clsDelegate.nameReferenceElement
@@ -87,8 +84,12 @@ class KtLightAnnotationForSourceEntry(
private val qualifiedName: String,
override val kotlinOrigin: KtCallElement,
parent: PsiElement,
computeDelegate: () -> PsiAnnotation
) : KtLightAbstractAnnotation(parent, computeDelegate) {
private val lazyClsDelegate: Lazy<PsiAnnotation>?
) : KtLightAbstractAnnotation(parent, lazyClsDelegate) {
override fun getOwner() = parent as? PsiAnnotationOwner
override fun getMetaData() = lazyClsDelegate?.value?.metaData
override fun getQualifiedName() = qualifiedName
@@ -114,8 +115,7 @@ class KtLightAnnotationForSourceEntry(
}
if (useDefault && callEntry.key.declaresOrInheritsDefaultValue()) {
val psiElement = callEntry.key.source.getPsi()
when (psiElement) {
when (val psiElement = callEntry.key.source.getPsi()) {
is KtParameter ->
return psiElement.defaultValue?.let { convertToLightAnnotationMemberValue(this, it) }
is PsiAnnotationMethod ->
@@ -125,17 +125,15 @@ class KtLightAnnotationForSourceEntry(
return null
}
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = KtLightPsiJavaCodeReferenceElement(
kotlinOrigin.navigationElement,
{
(kotlinOrigin as? KtAnnotationEntry)?.typeReference?.reference
?: (kotlinOrigin.calleeExpression?.nameReference)?.references?.firstOrNull()
},
{ super.getNameReferenceElement() }
{ lazyClsDelegate?.value?.nameReferenceElement }
)
private val ktLightAnnotationParameterList by lazyPub { KtLightAnnotationParameterList() }
override fun getParameterList(): PsiAnnotationParameterList = ktLightAnnotationParameterList
@@ -202,7 +200,7 @@ class KtLightAnnotationForSourceEntry(
class KtLightNonSourceAnnotation(
parent: PsiElement, clsDelegate: PsiAnnotation
) : KtLightAbstractAnnotation(parent, { clsDelegate }) {
) : KtLightAbstractAnnotation(parent, lazyPub { clsDelegate }) {
override val kotlinOrigin: KtAnnotationEntry? get() = null
override fun getQualifiedName() = kotlinOrigin?.name ?: clsDelegate.qualifiedName
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
@@ -237,7 +235,7 @@ class KtLightEmptyAnnotationParameterList(parent: PsiElement) : KtLightElementBa
}
open class KtLightNullabilityAnnotation<D : KtLightElement<*, PsiModifierListOwner>>(val member: D, parent: PsiElement) :
KtLightAbstractAnnotation(parent, {
KtLightAbstractAnnotation(parent, lazyPub {
// searching for last because nullability annotations are generated after backend generates source annotations
getClsNullabilityAnnotation(member) ?: KtLightNonExistentAnnotation(member)
}) {
@@ -362,7 +360,8 @@ fun convertToLightAnnotationMemberValue(lightParent: PsiElement, argument: KtExp
annotationName,
argument,
lightParent,
{ throw UnsupportedOperationException("cls delegate is not supported for nested annotations") })
lazyClsDelegate = null
)
}
val resolvedCall = argument.getResolvedCall()
if (resolvedCall != null && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall))