diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index 04e11baf739..5a4042d92ff 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -56,6 +56,16 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import java.util.* import javax.swing.Icon +private class KtLightClassModifierList(containingClass: KtLightClassForSourceDeclaration, computeModifiers: () -> Set) : + KtLightModifierList(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(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 diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt index dccce7d6c26..f0348a361ab 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt @@ -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 diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt index 9c38980dcdd..5a771ef495f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt @@ -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 + ) : + KtUltraLightModifierList(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) } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt index ccc28adfe53..931f7297a92 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt @@ -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, + private val modifiers: Set +) : 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 { - 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 diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt index 7b1f149acde..96a4847891c 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt @@ -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, private val modifiers: Set +) : KtUltraLightModifierList>(owner) { + override fun hasModifierProperty(name: String) = name in modifiers + + override fun copy() = KtUltraLightSimpleModifierList(owner, modifiers) +} + +abstract class KtUltraLightModifierList>(owner: T) : + KtLightModifierList(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, private val modifiers: Set ) : KtLightModifierList>(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) } } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt index 208d0c25fa7..43d53cfac88 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt @@ -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?) : KtLightElementBase(parent), PsiAnnotation, KtLightElement { - 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? +) : 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 setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify() @@ -237,7 +235,7 @@ class KtLightEmptyAnnotationParameterList(parent: PsiElement) : KtLightElementBa } open class KtLightNullabilityAnnotation>(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))