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 036ff13a5df..f10d044c1f1 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 @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.asJava.elements +import com.intellij.openapi.diagnostic.Attachment +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.* @@ -37,6 +39,8 @@ import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.TypeUtils +private val LOG = Logger.getInstance("#org.jetbrains.kotlin.asJava.elements.lightAnnotations") + abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: () -> PsiAnnotation) : KtLightElementBase(parent), PsiAnnotation, KtLightElement { override val clsDelegate by lazyPub(computeDelegate) @@ -181,13 +185,17 @@ class KtLightAnnotationForSourceEntry( valueOrigin: AnnotationValueOrigin ) : LightElementValue(delegate, parent, valueOrigin), PsiArrayInitializerMemberValue { private val _initializers by lazyPub { - delegate.initializers.mapIndexed { i, it -> - wrapAnnotationValue(it, this, { - originalExpression.let { - when (it) { - is KtCallElement -> it.valueArguments[i].getArgumentExpression()!! - is KtCollectionLiteralExpression -> it.getInnerExpressions()[i] - else -> throw UnsupportedOperationException("cant process $it of type ${it?.javaClass}") + delegate.initializers.mapIndexed { i, memberValue -> + wrapAnnotationValue(memberValue, this, { + originalExpression.let { ktOrigin -> + when (ktOrigin) { + is KtCallElement -> ktOrigin.valueArguments.getOrNull(i)?.getArgumentExpression() + is KtCollectionLiteralExpression -> ktOrigin.getInnerExpressions().getOrNull(i) + else -> null + }.also { + if (it == null) + LOG.error("error wrapping ${memberValue.javaClass} for ${ktOrigin?.javaClass} in ${ktOrigin?.containingFile}", + Attachment("source_fragments.txt", "origin: '${psiReport(ktOrigin)}', delegate: ${psiReport(delegate)}")) } } }) @@ -197,22 +205,26 @@ class KtLightAnnotationForSourceEntry( override fun getInitializers() = _initializers } - private fun wrapAnnotationValue(value: PsiAnnotationMemberValue, parent: PsiElement, ktOrigin: AnnotationValueOrigin): PsiAnnotationMemberValue { - return when { - value is PsiLiteralExpression && value.value is String -> LightStringLiteral(value, parent, ktOrigin) - value is PsiClassObjectAccessExpression -> LightClassLiteral(value, parent, ktOrigin) - value is PsiExpression -> LightExpressionValue(value, parent, ktOrigin) - value is PsiArrayInitializerMemberValue -> LightArrayInitializerValue(value, parent, ktOrigin) - value is PsiAnnotation -> KtLightAnnotationForSourceEntry( - value.qualifiedName!!, - ktOrigin().let { - it?.asKtCall() ?: throw UnsupportedOperationException("cant convert $it to KtCallElement") - }, - parent, { value } - ) - else -> LightElementValue(value, parent, ktOrigin) - } - } + private fun wrapAnnotationValue(value: PsiAnnotationMemberValue, parent: PsiElement, ktOrigin: AnnotationValueOrigin): PsiAnnotationMemberValue = + when { + value is PsiLiteralExpression && value.value is String -> LightStringLiteral(value, parent, ktOrigin) + value is PsiClassObjectAccessExpression -> LightClassLiteral(value, parent, ktOrigin) + value is PsiExpression -> LightExpressionValue(value, parent, ktOrigin) + value is PsiArrayInitializerMemberValue -> LightArrayInitializerValue(value, parent, ktOrigin) + value is PsiAnnotation -> { + val origin = ktOrigin() + val ktCallElement = origin?.asKtCall() + val qualifiedName = value.qualifiedName + if (qualifiedName != null && ktCallElement != null) + KtLightAnnotationForSourceEntry(qualifiedName, ktCallElement, parent, { value }) + else { + LOG.error("can't convert ${origin?.javaClass} to KtCallElement in ${origin?.containingFile} (value = ${value.javaClass})", + Attachment("source_fragments.txt", "origin: '${psiReport(origin)}', value: '${psiReport(value)}'")) + LightElementValue(value, parent, ktOrigin) // or maybe create a LightErrorAnnotationMemberValue instead? + } + } + else -> LightElementValue(value, parent, ktOrigin) + } override fun isPhysical() = true @@ -302,4 +314,15 @@ private fun KtElement.getResolvedCall(): ResolvedCall? { return this.getResolvedCall(context) } -private fun PsiElement.asKtCall(): KtCallElement? = (this as? KtElement)?.getResolvedCall()?.call?.callElement as? KtCallElement \ No newline at end of file +private fun PsiElement.asKtCall(): KtCallElement? = (this as? KtElement)?.getResolvedCall()?.call?.callElement as? KtCallElement + +private fun psiReport(psiElement: PsiElement?): String { + if (psiElement == null) return "null" + val text = try { + psiElement.text + } + catch (e: Exception) { + "${e.javaClass.simpleName}:${e.message}" + } + return "${psiElement.javaClass.canonicalName}[$text]" +} \ No newline at end of file