Uast: fake light method for uast is created only when containing class exists (KT-35310, EA-219604)

This commit is contained in:
Nicolay Mitropolsky
2020-01-08 16:13:36 +03:00
parent 5917591205
commit 23c2a5c830
5 changed files with 53 additions and 18 deletions
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -517,8 +518,12 @@ internal object KotlinConverter {
val lightMethod = LightClassUtil.getLightClassMethod(original)
if (lightMethod != null)
convertDeclaration(lightMethod, givenParent, expectedTypes)
else
KotlinUMethodWithFakeLightDelegate(original, givenParent)
else {
val ktLightClass = original.containingClassOrObject?.toLightClass()
?: original.containingKtFile.findFacadeClass()
?: return null
KotlinUMethodWithFakeLightDelegate(original, ktLightClass, givenParent)
}
}
}
@@ -22,8 +22,6 @@ import com.intellij.psi.impl.light.LightModifierList
import com.intellij.psi.impl.light.LightParameterListBuilder
import com.intellij.psi.impl.light.LightTypeParameterBuilder
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
@@ -152,14 +150,14 @@ open class KotlinUAnnotationMethod(
}
private fun buildLightMethodFake(original: KtFunction): PsiMethod = object : LightMethodBuilder(
private class UastFakeLightMethod(private val original: KtFunction, containingClass: PsiClass) : LightMethodBuilder(
original.manager, original.language, original.name,
LightParameterListBuilder(original.manager, original.language),
LightModifierList(original.manager)
) {
init {
containingClass = original.containingClassOrObject?.toLightClass() ?: original.containingKtFile.findFacadeClass()
this.containingClass = containingClass
}
private val _buildTypeParameterList by lazy {
@@ -181,8 +179,8 @@ private fun buildLightMethodFake(original: KtFunction): PsiMethod = object : Lig
override fun getParent(): PsiElement? = containingClass
}
class KotlinUMethodWithFakeLightDelegate(val original: KtFunction, givenParent: UElement?) :
KotlinUMethod(buildLightMethodFake(original), original, givenParent) {
class KotlinUMethodWithFakeLightDelegate(val original: KtFunction, containingLightClass: PsiClass, givenParent: UElement?) :
KotlinUMethod(UastFakeLightMethod(original, containingLightClass), original, givenParent) {
override val annotations: List<UAnnotation>
get() = original.annotationEntries.mapNotNull { it.toUElementOfType<UAnnotation>() }
@@ -23,8 +23,6 @@ import com.intellij.psi.impl.light.LightParameterListBuilder
import com.intellij.psi.impl.light.LightTypeParameterBuilder
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
@@ -155,14 +153,14 @@ open class KotlinUAnnotationMethod(
}
private fun buildLightMethodFake(original: KtFunction): PsiMethod = object : LightMethodBuilder(
private class UastFakeLightMethod(private val original: KtFunction, containingClass: PsiClass) : LightMethodBuilder(
original.manager, original.language, original.name,
LightParameterListBuilder(original.manager, original.language),
LightModifierList(original.manager)
) {
init {
containingClass = original.containingClassOrObject?.toLightClass() ?: original.containingKtFile.findFacadeClass()
this.containingClass = containingClass
}
private val _buildTypeParameterList by lazy {
@@ -184,8 +182,8 @@ private fun buildLightMethodFake(original: KtFunction): PsiMethod = object : Lig
override fun getParent(): PsiElement? = containingClass
}
class KotlinUMethodWithFakeLightDelegate(val original: KtFunction, givenParent: UElement?) :
KotlinUMethod(buildLightMethodFake(original), original, givenParent) {
class KotlinUMethodWithFakeLightDelegate(val original: KtFunction, containingLightClass: PsiClass, givenParent: UElement?) :
KotlinUMethod(UastFakeLightMethod(original, containingLightClass), original, givenParent) {
override val annotations: List<UAnnotation>
get() = original.annotationEntries.mapNotNull { it.toUElementOfType<UAnnotation>() }
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isInterface
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.expressions.KotlinLocalFunctionUVariable
import java.lang.ref.WeakReference
@@ -294,7 +295,17 @@ internal fun KotlinType.toPsiType(lightDeclaration: PsiModifierListOwner?, conte
val typeInfo = TypeInfo.fromString(javaType, false)
val typeText = TypeInfo.createTypeText(typeInfo) ?: return UastErrorType
return ClsTypeElementImpl(lightDeclaration ?: context, typeText, '\u0000').type
val parent: PsiElement = lightDeclaration ?: context
if (parent.containingFile == null) {
Logger.getInstance("org.jetbrains.uast.kotlin.KotlinInternalUastUtils")
.error(
"initialising ClsTypeElementImpl with null-file parent = $parent (of ${parent.javaClass}) " +
"containing class = ${parent.safeAs<PsiMethod>()?.containingClass}, " +
"lightDeclaration = $lightDeclaration (of ${lightDeclaration?.javaClass})," +
" context = $context (of ${context.javaClass})"
)
}
return ClsTypeElementImpl(parent, typeText, '\u0000').type
}
private fun KotlinType.containsLocalTypes(): Boolean {
@@ -26,11 +26,14 @@ import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.findFunctionByName
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.jetbrains.kotlin.test.testFramework.runWriteAction
import org.jetbrains.uast.*
import org.jetbrains.uast.test.env.kotlin.findUElementByTextFromPsi
import org.junit.runner.RunWith
@@ -135,18 +138,38 @@ class KotlinDetachedUastTest : KotlinLightCodeInsightFixtureTestCase() {
fun testAnonymousInnerClassWithIDELightClasses() {
val detachedClass = myFixture.configureByText("MyClass.kt","""
val detachedClass = myFixture.configureByText(
"MyClass.kt", """
class MyClass() {
private val obj = object : MyClass() {}
}
""")
"""
)
val anonymousClass = detachedClass.findUElementByTextFromPsi<UObjectLiteralExpression>("object : MyClass() {}")
.let { uObjectLiteralExpression -> uObjectLiteralExpression.declaration }
TestCase.assertEquals("UClass (name = null), UObjectLiteralExpression, UField (name = obj), UClass (name = MyClass), UFile (package = )", generateSequence<UElement>(anonymousClass, { it.uastParent }).joinToString { it.asLogString() })
TestCase.assertEquals(
"UClass (name = null), UObjectLiteralExpression, UField (name = obj), UClass (name = MyClass), UFile (package = )",
generateSequence<UElement>(anonymousClass, { it.uastParent }).joinToString { it.asLogString() })
}
fun testDontConvertDetachedFunctions() {
val ktFile = myFixture.configureByText(
"MyClass.kt", """
class MyClass() {
fun foo1() = 42
}
"""
) as KtFile
val ktClass = ktFile.declarations.filterIsInstance<KtClass>().single()//.copied()
val ktFunctionDetached = ktClass.findFunctionByName("foo1")!!
runWriteAction { ktClass.delete() }
TestCase.assertNull(ktFunctionDetached.toUElementOfType<UMethod>())
}
}
fun <T> T?.orFail(msg: String): T = this ?: error(msg)