diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt index 1bbe0ff0ff7..81ac5beb144 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -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) + } } } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt index 3d118d0e048..3bd2399d3a9 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt @@ -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 get() = original.annotationEntries.mapNotNull { it.toUElementOfType() } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.191 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.191 index 40bdeb55b9e..ef0c52de1e4 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.191 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.191 @@ -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 get() = original.annotationEntries.mapNotNull { it.toUElementOfType() } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt index bbd52200ac2..e52d13fcb49 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt @@ -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()?.containingClass}, " + + "lightDeclaration = $lightDeclaration (of ${lightDeclaration?.javaClass})," + + " context = $context (of ${context.javaClass})" + ) + } + return ClsTypeElementImpl(parent, typeText, '\u0000').type } private fun KotlinType.containsLocalTypes(): Boolean { diff --git a/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt b/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt index 373fd344446..6ed6d4eb4d1 100644 --- a/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt +++ b/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt @@ -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("object : MyClass() {}") .let { uObjectLiteralExpression -> uObjectLiteralExpression.declaration } - TestCase.assertEquals("UClass (name = null), UObjectLiteralExpression, UField (name = obj), UClass (name = MyClass), UFile (package = )", generateSequence(anonymousClass, { it.uastParent }).joinToString { it.asLogString() }) + TestCase.assertEquals( + "UClass (name = null), UObjectLiteralExpression, UField (name = obj), UClass (name = MyClass), UFile (package = )", + generateSequence(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().single()//.copied() + val ktFunctionDetached = ktClass.findFunctionByName("foo1")!! + runWriteAction { ktClass.delete() } + TestCase.assertNull(ktFunctionDetached.toUElementOfType()) + } + } + fun T?.orFail(msg: String): T = this ?: error(msg) \ No newline at end of file