diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt index c084a2ea84b..02e71c48319 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt @@ -17,8 +17,10 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration +import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.toLightGetter import org.jetbrains.kotlin.asJava.toLightSetter import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget @@ -45,6 +47,20 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : Kotl val psi = psi //TODO: `psi` is deprecated but it seems that it couldn't be simply replaced for this case var parent = psi?.parent ?: sourcePsi?.parent ?: psi?.containingFile + if (psi is PsiMethod && psi !is KtLightMethod) { // handling of synthetic things not represented in lightclasses directly + when (parent) { + is KtClassBody -> { + val grandParent = parent.parent + doConvertParent(this, grandParent)?.let { return it } + parent = grandParent + } + is KtFile -> { + parent.toUElementOfType()?.let { return it } // mutlifile facade class + } + } + + } + if (psi is KtLightClassForLocalDeclaration) { val originParent = psi.kotlinOrigin.parent parent = when (originParent) { diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 index 1ec365012ab..65d4faa6a96 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 @@ -17,8 +17,10 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration +import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.toLightGetter import org.jetbrains.kotlin.asJava.toLightSetter import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget @@ -45,6 +47,20 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : Kotl val psi = psi //TODO: `psi` is deprecated but it seems that it couldn't be simply replaced for this case var parent = psi?.parent ?: sourcePsi?.parent ?: psi?.containingFile + if (psi is PsiMethod && psi !is KtLightMethod) { // handling of synthetic things not represented in lightclasses directly + when (parent) { + is KtClassBody -> { + val grandParent = parent.parent + doConvertParent(this, grandParent)?.let { return it } + parent = grandParent + } + is KtFile -> { + parent.toUElementOfType()?.let { return it } // mutlifile facade class + } + } + + } + if (psi is KtLightClassForLocalDeclaration) { val originParent = psi.kotlinOrigin.parent parent = when (originParent) { 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 4d1fb9e423c..2e312df8c58 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -22,6 +22,9 @@ import com.intellij.openapi.util.Key import com.intellij.openapi.util.registry.Registry import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import com.intellij.psi.impl.light.LightMethodBuilder +import com.intellij.psi.impl.light.LightModifierList +import com.intellij.psi.impl.light.LightParameterListBuilder import com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.asJava.LightClassUtil @@ -513,8 +516,17 @@ internal object KotlinConverter { } } else { el { - val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null - convertDeclaration(lightMethod, givenParent, expectedTypes) + val lightMethod = LightClassUtil.getLightClassMethod(original) + if (lightMethod != null) + convertDeclaration(lightMethod, givenParent, expectedTypes) + else { + val lightFake = LightMethodBuilder( + original.manager, original.language, original.name, + LightParameterListBuilder(original.manager, original.language), + LightModifierList(original.manager) + ) + KotlinUMethod(lightFake, original, givenParent) + } } } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.183 index 79f1831e606..1d9d2724af1 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.183 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.183 @@ -21,6 +21,9 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.util.Key import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import com.intellij.psi.impl.light.LightMethodBuilder +import com.intellij.psi.impl.light.LightModifierList +import com.intellij.psi.impl.light.LightParameterListBuilder import com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.classes.KtLightClass @@ -478,8 +481,17 @@ internal object KotlinConverter { } else { el { - val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null - convertDeclaration(lightMethod, givenParent, requiredType) + val lightMethod = LightClassUtil.getLightClassMethod(original) + if (lightMethod != null) + convertDeclaration(lightMethod, givenParent, expectedTypes) + else { + val lightFake = LightMethodBuilder( + original.manager, original.language, original.name, + LightParameterListBuilder(original.manager, original.language), + LightModifierList(original.manager) + ) + KotlinUMethod(lightFake, original, givenParent) + } } } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt index 6868a52391c..8d422b778ad 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt @@ -19,12 +19,14 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.* import com.intellij.psi.impl.light.LightPsiClassBuilder import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.* import org.jetbrains.uast.internal.acceptList @@ -156,11 +158,29 @@ open class KotlinUClass private constructor( fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated - return psi.methods.asSequence() - .filterNot(::isDelegatedMethod) - .map(::createUMethod) - .toList() - .toTypedArray() + val result = ArrayList(javaPsi.methods.size) + val handledKtDeclarations = mutableSetOf() + + for (lightMethod in javaPsi.methods) { + if (isDelegatedMethod(lightMethod)) continue + val uMethod = createUMethod(lightMethod) + result.add(uMethod) + handledKtDeclarations.addIfNotNull(uMethod.sourcePsi) + } + + val ktDeclarations: List = run ktDeclarations@{ + ktClass?.let { return@ktDeclarations it.declarations } + (javaPsi as? KtLightClassForFacade)?.let { facade -> + return@ktDeclarations facade.files.flatMap { file -> file.declarations } + } + emptyList() + } + + ktDeclarations.asSequence() + .filterNot { handledKtDeclarations.contains(it) } + .mapNotNullTo(result) { KotlinConverter.convertDeclaration(it, this, arrayOf(UElement::class.java)) as? UMethod } + + return result.toTypedArray() } private fun PsiClass.isEnumEntryLightClass() = (this as? KtLightClass)?.kotlinOrigin is KtEnumEntry 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 2b346e5370b..cfb99dd6da6 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 @@ -50,7 +50,10 @@ open class KotlinUMethod( private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi - override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) + override fun getContainingFile(): PsiFile? { + kotlinOrigin?.containingFile?.let { return it } + return unwrapFakeFileForLightClass(psi.containingFile) + } override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 index c337dcb9b4c..83607e14fc8 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 @@ -48,7 +48,10 @@ open class KotlinUMethod( private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi - override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) + override fun getContainingFile(): PsiFile? { + kotlinOrigin?.containingFile?.let { return it } + return unwrapFakeFileForLightClass(psi.containingFile) + } override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) 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 d43a290a5e8..5044ed6da2c 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 @@ -48,7 +48,10 @@ open class KotlinUMethod( private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi - override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) + override fun getContainingFile(): PsiFile? { + kotlinOrigin?.containingFile?.let { return it } + return unwrapFakeFileForLightClass(psi.containingFile) + } override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) diff --git a/plugins/uast-kotlin/testData/Reified.kt b/plugins/uast-kotlin/testData/Reified.kt new file mode 100644 index 00000000000..d73c0a998c4 --- /dev/null +++ b/plugins/uast-kotlin/testData/Reified.kt @@ -0,0 +1,10 @@ +package test.pkg + +class Context { + inline fun ownSystemService1() = getSystemService(T::class.java) + inline fun ownSystemService2() = getSystemService(String::class.java) +} + + +inline fun Context.systemService1() = getSystemService(T::class.java) +inline fun Context.systemService2() = getSystemService(String::class.java) \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/Reified.log.txt b/plugins/uast-kotlin/testData/Reified.log.txt new file mode 100644 index 00000000000..c509e1eff98 --- /dev/null +++ b/plugins/uast-kotlin/testData/Reified.log.txt @@ -0,0 +1,42 @@ +UFile (package = test.pkg) + UClass (name = ReifiedKt) + UMethod (name = systemService2) + UParameter (name = $this$systemService2) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UReturnExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (getSystemService)) + USimpleNameReferenceExpression (identifier = , resolvesTo = null) + UQualifiedReferenceExpression + UClassLiteralExpression + USimpleNameReferenceExpression (identifier = java) + UMethod (name = systemService1) + UBlockExpression + UReturnExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (getSystemService)) + USimpleNameReferenceExpression (identifier = , resolvesTo = null) + UQualifiedReferenceExpression + UClassLiteralExpression + USimpleNameReferenceExpression (identifier = java) + UClass (name = Context) + UMethod (name = ownSystemService2) + UBlockExpression + UReturnExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (getSystemService)) + USimpleNameReferenceExpression (identifier = , resolvesTo = null) + UQualifiedReferenceExpression + UClassLiteralExpression + USimpleNameReferenceExpression (identifier = java) + UMethod (name = Context) + UMethod (name = ownSystemService1) + UBlockExpression + UReturnExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (getSystemService)) + USimpleNameReferenceExpression (identifier = , resolvesTo = null) + UQualifiedReferenceExpression + UClassLiteralExpression + USimpleNameReferenceExpression (identifier = java) diff --git a/plugins/uast-kotlin/testData/Reified.render.txt b/plugins/uast-kotlin/testData/Reified.render.txt new file mode 100644 index 00000000000..a11b5f51472 --- /dev/null +++ b/plugins/uast-kotlin/testData/Reified.render.txt @@ -0,0 +1,20 @@ +package test.pkg + +public final class ReifiedKt { + public static final fun systemService2(@org.jetbrains.annotations.NotNull $this$systemService2: test.pkg.Context) : error.NonExistentClass { + return (java.lang.String.java) + } + fun systemService1() { + return (java.lang.Object.java) + } +} + +public final class Context { + public final fun ownSystemService2() : error.NonExistentClass { + return (java.lang.String.java) + } + public fun Context() = UastEmptyExpression + fun ownSystemService1() { + return (java.lang.Object.java) + } +} diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index 66162a228ca..ea75394f97d 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -102,6 +102,9 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testLambdaReturn() = doTest("LambdaReturn") + + @Test + fun testReified() = doTest("Reified") } fun withForceUInjectionHostValue(call: () -> Unit) { diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.183 b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.183 index 8710639fd67..9181a11c574 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.183 +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.183 @@ -96,4 +96,7 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testLambdaReturn() = doTest("LambdaReturn") + + @Test + fun testReified() = doTest("Reified") }