Uast: fixes and tests for descriptors leak (KT-27663)
This commit is contained in:
committed by
Nicolay Mitropolsky
parent
e48fbe4aa3
commit
bf42bd1226
@@ -29,8 +29,6 @@ import org.jetbrains.kotlin.asJava.elements.*
|
|||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
import org.jetbrains.kotlin.asJava.toLightClass
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
@@ -226,14 +224,7 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
||||||
is KtCallExpression ->
|
is KtCallExpression ->
|
||||||
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
||||||
el<UAnnotation> {
|
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
|
||||||
val classDescriptor =
|
|
||||||
(original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
|
|
||||||
if (classDescriptor?.kind == ClassKind.ANNOTATION_CLASS)
|
|
||||||
KotlinUNestedAnnotation(original, givenParent, classDescriptor)
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
|
||||||
} else null
|
} else null
|
||||||
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, requiredType)
|
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, requiredType)
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ import org.jetbrains.kotlin.asJava.elements.*
|
|||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
import org.jetbrains.kotlin.asJava.toLightClass
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
@@ -226,14 +224,7 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
||||||
is KtCallExpression ->
|
is KtCallExpression ->
|
||||||
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
||||||
el<UAnnotation> {
|
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
|
||||||
val classDescriptor =
|
|
||||||
(original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
|
|
||||||
if (classDescriptor?.kind == ClassKind.ANNOTATION_CLASS)
|
|
||||||
KotlinUNestedAnnotation(original, givenParent, classDescriptor)
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
|
||||||
} else null
|
} else null
|
||||||
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, requiredType)
|
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, requiredType)
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
+36
-27
@@ -2,9 +2,11 @@ package org.jetbrains.uast.kotlin
|
|||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
import com.intellij.psi.PsiAnnotation
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -21,25 +23,26 @@ import org.jetbrains.uast.*
|
|||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||||
|
|
||||||
abstract class KotlinUAnnotationBase(
|
abstract class KotlinUAnnotationBase<T : KtCallElement>(
|
||||||
final override val psi: KtElement,
|
final override val sourcePsi: T,
|
||||||
givenParent: UElement?
|
givenParent: UElement?
|
||||||
) : KotlinAbstractUElement(givenParent), UAnnotationEx, UAnchorOwner {
|
) : KotlinAbstractUElement(givenParent), UAnnotationEx, UAnchorOwner {
|
||||||
|
|
||||||
abstract override val javaPsi: PsiAnnotation?
|
abstract override val javaPsi: PsiAnnotation?
|
||||||
|
|
||||||
final override val sourcePsi = psi
|
final override val psi: PsiElement = sourcePsi
|
||||||
|
|
||||||
protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
|
protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
|
||||||
|
|
||||||
private val resolvedCall: ResolvedCall<*>? by lz { psi.getResolvedCall(psi.analyze()) }
|
private val resolvedCall: ResolvedCall<*>? get () = sourcePsi.getResolvedCall(sourcePsi.analyze())
|
||||||
|
|
||||||
override val qualifiedName: String?
|
override val qualifiedName: String? by lz {
|
||||||
get() = annotationClassDescriptor.takeUnless(ErrorUtils::isError)
|
computeClassDescriptor().takeUnless(ErrorUtils::isError)
|
||||||
?.fqNameUnsafe
|
?.fqNameUnsafe
|
||||||
?.takeIf(FqNameUnsafe::isSafe)
|
?.takeIf(FqNameUnsafe::isSafe)
|
||||||
?.toSafe()
|
?.toSafe()
|
||||||
?.toString()
|
?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
override val attributeValues: List<UNamedExpression> by lz {
|
override val attributeValues: List<UNamedExpression> by lz {
|
||||||
resolvedCall?.valueArguments?.entries?.mapNotNull {
|
resolvedCall?.valueArguments?.entries?.mapNotNull {
|
||||||
@@ -55,12 +58,9 @@ abstract class KotlinUAnnotationBase(
|
|||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract val annotationClassDescriptor: ClassDescriptor?
|
protected abstract fun computeClassDescriptor(): ClassDescriptor?
|
||||||
|
|
||||||
override fun resolve(): PsiClass? {
|
override fun resolve(): PsiClass? = computeClassDescriptor()?.toSource()?.getMaybeLightElement(this) as? PsiClass
|
||||||
val descriptor = annotationClassDescriptor ?: return null
|
|
||||||
return descriptor.toSource()?.getMaybeLightElement(this) as? PsiClass
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findAttributeValue(name: String?): UExpression? =
|
override fun findAttributeValue(name: String?): UExpression? =
|
||||||
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
|
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
|
||||||
@@ -82,7 +82,7 @@ abstract class KotlinUAnnotationBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findAttributeDefaultValue(name: String): UExpression? {
|
private fun findAttributeDefaultValue(name: String): UExpression? {
|
||||||
val parameter = annotationClassDescriptor
|
val parameter = computeClassDescriptor()
|
||||||
?.unsubstitutedPrimaryConstructor
|
?.unsubstitutedPrimaryConstructor
|
||||||
?.valueParameters
|
?.valueParameters
|
||||||
?.find { it.name.asString() == name } ?: return null
|
?.find { it.name.asString() == name } ?: return null
|
||||||
@@ -103,18 +103,16 @@ abstract class KotlinUAnnotationBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KotlinUAnnotation(
|
class KotlinUAnnotation(
|
||||||
val annotationEntry: KtAnnotationEntry,
|
annotationEntry: KtAnnotationEntry,
|
||||||
givenParent: UElement?
|
givenParent: UElement?
|
||||||
) : KotlinUAnnotationBase(annotationEntry, givenParent), UAnnotation {
|
) : KotlinUAnnotationBase<KtAnnotationEntry>(annotationEntry, givenParent), UAnnotation {
|
||||||
|
|
||||||
override val javaPsi = annotationEntry.toLightAnnotation()
|
override val javaPsi = annotationEntry.toLightAnnotation()
|
||||||
|
|
||||||
private val resolvedAnnotation: AnnotationDescriptor? by lz { annotationEntry.analyze()[BindingContext.ANNOTATION, annotationEntry] }
|
override fun computeClassDescriptor(): ClassDescriptor? =
|
||||||
|
sourcePsi.analyze()[BindingContext.ANNOTATION, sourcePsi]?.annotationClass
|
||||||
|
|
||||||
override val annotationClassDescriptor: ClassDescriptor?
|
override fun annotationUseSiteTarget() = sourcePsi.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||||
get() = resolvedAnnotation?.annotationClass
|
|
||||||
|
|
||||||
override fun annotationUseSiteTarget() = annotationEntry.useSiteTarget?.getAnnotationUseSiteTarget()
|
|
||||||
|
|
||||||
override val uastAnchor by lazy {
|
override val uastAnchor by lazy {
|
||||||
KotlinUIdentifier(
|
KotlinUIdentifier(
|
||||||
@@ -128,14 +126,13 @@ class KotlinUAnnotation(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinUNestedAnnotation(
|
class KotlinUNestedAnnotation private constructor(
|
||||||
private val original: KtCallExpression,
|
original: KtCallExpression,
|
||||||
givenParent: UElement?,
|
givenParent: UElement?
|
||||||
private val classDescriptor: ClassDescriptor?
|
) : KotlinUAnnotationBase<KtCallExpression>(original, givenParent) {
|
||||||
) : KotlinUAnnotationBase(original, givenParent) {
|
|
||||||
override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
|
override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
|
||||||
override val annotationClassDescriptor: ClassDescriptor?
|
|
||||||
get() = classDescriptor
|
override fun computeClassDescriptor(): ClassDescriptor? = classDescriptor(sourcePsi)
|
||||||
|
|
||||||
override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
|
override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
|
||||||
|
|
||||||
@@ -147,6 +144,18 @@ class KotlinUNestedAnnotation(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun tryCreate(original: KtCallExpression, givenParent: UElement?): KotlinUNestedAnnotation? {
|
||||||
|
if (classDescriptor(original)?.kind == ClassKind.ANNOTATION_CLASS)
|
||||||
|
return KotlinUNestedAnnotation(original, givenParent)
|
||||||
|
else
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classDescriptor(original: KtCallExpression) =
|
||||||
|
(original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+35
-26
@@ -2,9 +2,11 @@ package org.jetbrains.uast.kotlin
|
|||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
import com.intellij.psi.PsiAnnotation
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -20,25 +22,26 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
|||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||||
|
|
||||||
abstract class KotlinUAnnotationBase(
|
abstract class KotlinUAnnotationBase<T : KtCallElement>(
|
||||||
final override val psi: KtElement,
|
final override val sourcePsi: T,
|
||||||
givenParent: UElement?
|
givenParent: UElement?
|
||||||
) : KotlinAbstractUElement(givenParent), UAnnotation {
|
) : KotlinAbstractUElement(givenParent), UAnnotation {
|
||||||
|
|
||||||
abstract override val javaPsi: PsiAnnotation?
|
abstract override val javaPsi: PsiAnnotation?
|
||||||
|
|
||||||
final override val sourcePsi = psi
|
final override val psi: PsiElement = sourcePsi
|
||||||
|
|
||||||
protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
|
protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
|
||||||
|
|
||||||
private val resolvedCall: ResolvedCall<*>? by lz { psi.getResolvedCall(psi.analyze()) }
|
private val resolvedCall: ResolvedCall<*>? get () = sourcePsi.getResolvedCall(sourcePsi.analyze())
|
||||||
|
|
||||||
override val qualifiedName: String?
|
override val qualifiedName: String? by lz {
|
||||||
get() = annotationClassDescriptor.takeUnless(ErrorUtils::isError)
|
computeClassDescriptor().takeUnless(ErrorUtils::isError)
|
||||||
?.fqNameUnsafe
|
?.fqNameUnsafe
|
||||||
?.takeIf(FqNameUnsafe::isSafe)
|
?.takeIf(FqNameUnsafe::isSafe)
|
||||||
?.toSafe()
|
?.toSafe()
|
||||||
?.toString()
|
?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
override val attributeValues: List<UNamedExpression> by lz {
|
override val attributeValues: List<UNamedExpression> by lz {
|
||||||
resolvedCall?.valueArguments?.entries?.mapNotNull {
|
resolvedCall?.valueArguments?.entries?.mapNotNull {
|
||||||
@@ -54,12 +57,9 @@ abstract class KotlinUAnnotationBase(
|
|||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract val annotationClassDescriptor: ClassDescriptor?
|
protected abstract fun computeClassDescriptor(): ClassDescriptor?
|
||||||
|
|
||||||
override fun resolve(): PsiClass? {
|
override fun resolve(): PsiClass? = computeClassDescriptor()?.toSource()?.getMaybeLightElement(this) as? PsiClass
|
||||||
val descriptor = annotationClassDescriptor ?: return null
|
|
||||||
return descriptor.toSource()?.getMaybeLightElement(this) as? PsiClass
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findAttributeValue(name: String?): UExpression? =
|
override fun findAttributeValue(name: String?): UExpression? =
|
||||||
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
|
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
|
||||||
@@ -81,7 +81,7 @@ abstract class KotlinUAnnotationBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findAttributeDefaultValue(name: String): UExpression? {
|
private fun findAttributeDefaultValue(name: String): UExpression? {
|
||||||
val parameter = annotationClassDescriptor
|
val parameter = computeClassDescriptor()
|
||||||
?.unsubstitutedPrimaryConstructor
|
?.unsubstitutedPrimaryConstructor
|
||||||
?.valueParameters
|
?.valueParameters
|
||||||
?.find { it.name.asString() == name } ?: return null
|
?.find { it.name.asString() == name } ?: return null
|
||||||
@@ -102,32 +102,41 @@ abstract class KotlinUAnnotationBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KotlinUAnnotation(
|
class KotlinUAnnotation(
|
||||||
val annotationEntry: KtAnnotationEntry,
|
annotationEntry: KtAnnotationEntry,
|
||||||
givenParent: UElement?
|
givenParent: UElement?
|
||||||
) : KotlinUAnnotationBase(annotationEntry, givenParent), UAnnotation {
|
) : KotlinUAnnotationBase<KtAnnotationEntry>(annotationEntry, givenParent), UAnnotation {
|
||||||
|
|
||||||
override val javaPsi = annotationEntry.toLightAnnotation()
|
override val javaPsi = annotationEntry.toLightAnnotation()
|
||||||
|
|
||||||
private val resolvedAnnotation: AnnotationDescriptor? by lz { annotationEntry.analyze()[BindingContext.ANNOTATION, annotationEntry] }
|
override fun computeClassDescriptor(): ClassDescriptor? =
|
||||||
|
sourcePsi.analyze()[BindingContext.ANNOTATION, sourcePsi]?.annotationClass
|
||||||
|
|
||||||
override val annotationClassDescriptor: ClassDescriptor?
|
override fun annotationUseSiteTarget() = sourcePsi.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||||
get() = resolvedAnnotation?.annotationClass
|
|
||||||
|
|
||||||
override fun annotationUseSiteTarget() = annotationEntry.useSiteTarget?.getAnnotationUseSiteTarget()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinUNestedAnnotation(
|
class KotlinUNestedAnnotation private constructor(
|
||||||
original: KtCallExpression,
|
original: KtCallExpression,
|
||||||
givenParent: UElement?,
|
givenParent: UElement?
|
||||||
private val classDescriptor: ClassDescriptor?
|
) : KotlinUAnnotationBase<KtCallExpression>(original, givenParent) {
|
||||||
) : KotlinUAnnotationBase(original, givenParent) {
|
|
||||||
override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
|
override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
|
||||||
override val annotationClassDescriptor: ClassDescriptor?
|
|
||||||
get() = classDescriptor
|
override fun computeClassDescriptor(): ClassDescriptor? = classDescriptor(sourcePsi)
|
||||||
|
|
||||||
override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
|
override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun tryCreate(original: KtCallExpression, givenParent: UElement?): KotlinUNestedAnnotation? {
|
||||||
|
if (classDescriptor(original)?.kind == ClassKind.ANNOTATION_CLASS)
|
||||||
|
return KotlinUNestedAnnotation(original, givenParent)
|
||||||
|
else
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classDescriptor(original: KtCallExpression) =
|
||||||
|
(original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -43,9 +43,8 @@ class KotlinUFunctionCallExpression(
|
|||||||
|
|
||||||
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
|
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
|
||||||
|
|
||||||
private val resolvedCall by lz {
|
private val resolvedCall
|
||||||
_resolvedCall ?: psi.getResolvedCall(psi.analyze())
|
get() = _resolvedCall ?: psi.getResolvedCall(psi.analyze())
|
||||||
}
|
|
||||||
|
|
||||||
override val receiverType by lz {
|
override val receiverType by lz {
|
||||||
val resolvedCall = this.resolvedCall ?: return@lz null
|
val resolvedCall = this.resolvedCall ?: return@lz null
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
package org.jetbrains.uast.test.kotlin
|
package org.jetbrains.uast.test.kotlin
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Conditions
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
|
import com.intellij.util.PairProcessor
|
||||||
|
import com.intellij.util.ref.DebugReflectionUtil
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||||
@@ -37,6 +43,7 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
|||||||
|
|
||||||
file.checkContainingFileForAllElements()
|
file.checkContainingFileForAllElements()
|
||||||
file.checkJvmDeclarationsImplementations()
|
file.checkJvmDeclarationsImplementations()
|
||||||
|
file.checkDescriptorsLeak()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkParentConsistency(file: UFile) {
|
private fun checkParentConsistency(file: UFile) {
|
||||||
@@ -106,6 +113,15 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun UFile.checkDescriptorsLeak() {
|
||||||
|
accept(object : UastVisitor {
|
||||||
|
override fun visitElement(node: UElement): Boolean {
|
||||||
|
checkDescriptorsLeak(node)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private fun UFile.checkJvmDeclarationsImplementations() {
|
private fun UFile.checkJvmDeclarationsImplementations() {
|
||||||
accept(object : UastVisitor {
|
accept(object : UastVisitor {
|
||||||
override fun visitElement(node: UElement): Boolean {
|
override fun visitElement(node: UElement): Boolean {
|
||||||
@@ -132,6 +148,22 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val descriptorsClasses = listOf(AnnotationDescriptor::class, DeclarationDescriptor::class)
|
||||||
|
|
||||||
|
fun checkDescriptorsLeak(node: UElement) {
|
||||||
|
DebugReflectionUtil.walkObjects(
|
||||||
|
10,
|
||||||
|
mapOf(node to node.javaClass.name),
|
||||||
|
Any::class.java,
|
||||||
|
Conditions.alwaysTrue(),
|
||||||
|
PairProcessor { value, backLink ->
|
||||||
|
descriptorsClasses.find { it.isInstance(value) }?.let {
|
||||||
|
TestCase.fail("""Leaked descriptor ${it.qualifiedName} in ${node.javaClass.name}\n$backLink""")
|
||||||
|
false
|
||||||
|
} ?: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private fun PsiFile.clearUastCaches() {
|
private fun PsiFile.clearUastCaches() {
|
||||||
accept(object : PsiRecursiveElementVisitor() {
|
accept(object : PsiRecursiveElementVisitor() {
|
||||||
override fun visitElement(element: PsiElement) {
|
override fun visitElement(element: PsiElement) {
|
||||||
|
|||||||
@@ -306,6 +306,7 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
|||||||
.toUElementOfType<UAnnotation>()
|
.toUElementOfType<UAnnotation>()
|
||||||
?: throw AssertionError("haven't got annotation from $referenceExpression(${referenceExpression?.javaClass})")
|
?: throw AssertionError("haven't got annotation from $referenceExpression(${referenceExpression?.javaClass})")
|
||||||
|
|
||||||
|
checkDescriptorsLeak(convertedUAnnotation)
|
||||||
assertEquals("Annotation", convertedUAnnotation.qualifiedName)
|
assertEquals("Annotation", convertedUAnnotation.qualifiedName)
|
||||||
val lightAnnotation = convertedUAnnotation.getAsJavaPsiElement(PsiAnnotation::class.java)
|
val lightAnnotation = convertedUAnnotation.getAsJavaPsiElement(PsiAnnotation::class.java)
|
||||||
?: throw AssertionError("can't get lightAnnotation from $convertedUAnnotation")
|
?: throw AssertionError("can't get lightAnnotation from $convertedUAnnotation")
|
||||||
|
|||||||
Reference in New Issue
Block a user