Uast: Uast produces reified methods on his own because light-classes doesn't (KT-34316)
This commit is contained in:
@@ -17,8 +17,10 @@
|
|||||||
package org.jetbrains.uast.kotlin
|
package org.jetbrains.uast.kotlin
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration
|
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.toLightGetter
|
||||||
import org.jetbrains.kotlin.asJava.toLightSetter
|
import org.jetbrains.kotlin.asJava.toLightSetter
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
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
|
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
|
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<UClass>()?.let { return it } // mutlifile facade class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (psi is KtLightClassForLocalDeclaration) {
|
if (psi is KtLightClassForLocalDeclaration) {
|
||||||
val originParent = psi.kotlinOrigin.parent
|
val originParent = psi.kotlinOrigin.parent
|
||||||
parent = when (originParent) {
|
parent = when (originParent) {
|
||||||
|
|||||||
@@ -17,8 +17,10 @@
|
|||||||
package org.jetbrains.uast.kotlin
|
package org.jetbrains.uast.kotlin
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration
|
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.toLightGetter
|
||||||
import org.jetbrains.kotlin.asJava.toLightSetter
|
import org.jetbrains.kotlin.asJava.toLightSetter
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
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
|
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
|
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<UClass>()?.let { return it } // mutlifile facade class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (psi is KtLightClassForLocalDeclaration) {
|
if (psi is KtLightClassForLocalDeclaration) {
|
||||||
val originParent = psi.kotlinOrigin.parent
|
val originParent = psi.kotlinOrigin.parent
|
||||||
parent = when (originParent) {
|
parent = when (originParent) {
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import com.intellij.openapi.util.Key
|
|||||||
import com.intellij.openapi.util.registry.Registry
|
import com.intellij.openapi.util.registry.Registry
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
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 com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
@@ -513,8 +516,17 @@ internal object KotlinConverter {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
el<UMethod> {
|
el<UMethod> {
|
||||||
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
|
val lightMethod = LightClassUtil.getLightClassMethod(original)
|
||||||
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import com.intellij.openapi.components.ServiceManager
|
|||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
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 com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
@@ -478,8 +481,17 @@ internal object KotlinConverter {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
el<UMethod> {
|
el<UMethod> {
|
||||||
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
|
val lightMethod = LightClassUtil.getLightClassMethod(original)
|
||||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ package org.jetbrains.uast.kotlin
|
|||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.light.LightPsiClassBuilder
|
import com.intellij.psi.impl.light.LightPsiClassBuilder
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
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.classes.KtLightClassForScript
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.internal.acceptList
|
import org.jetbrains.uast.internal.acceptList
|
||||||
@@ -156,11 +158,29 @@ open class KotlinUClass private constructor(
|
|||||||
|
|
||||||
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
||||||
|
|
||||||
return psi.methods.asSequence()
|
val result = ArrayList<UMethod>(javaPsi.methods.size)
|
||||||
.filterNot(::isDelegatedMethod)
|
val handledKtDeclarations = mutableSetOf<PsiElement>()
|
||||||
.map(::createUMethod)
|
|
||||||
.toList()
|
for (lightMethod in javaPsi.methods) {
|
||||||
.toTypedArray()
|
if (isDelegatedMethod(lightMethod)) continue
|
||||||
|
val uMethod = createUMethod(lightMethod)
|
||||||
|
result.add(uMethod)
|
||||||
|
handledKtDeclarations.addIfNotNull(uMethod.sourcePsi)
|
||||||
|
}
|
||||||
|
|
||||||
|
val ktDeclarations: List<KtDeclaration> = 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
|
private fun PsiClass.isEnumEntryLightClass() = (this as? KtLightClass)?.kotlinOrigin is KtEnumEntry
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ open class KotlinUMethod(
|
|||||||
|
|
||||||
private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi
|
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?)
|
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ open class KotlinUMethod(
|
|||||||
|
|
||||||
private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi
|
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?)
|
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ open class KotlinUMethod(
|
|||||||
|
|
||||||
private val kotlinOrigin = (psi.originalElement as? KtLightElement<*, *>)?.kotlinOrigin ?: sourcePsi
|
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?)
|
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
||||||
|
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package test.pkg
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
inline fun <reified T> ownSystemService1() = getSystemService(T::class.java)
|
||||||
|
inline fun ownSystemService2() = getSystemService(String::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline fun <reified T> Context.systemService1() = getSystemService(T::class.java)
|
||||||
|
inline fun Context.systemService2() = getSystemService(String::class.java)
|
||||||
+42
@@ -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 = <anonymous class>, 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 = <anonymous class>, 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 = <anonymous class>, 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 = <anonymous class>, resolvesTo = null)
|
||||||
|
UQualifiedReferenceExpression
|
||||||
|
UClassLiteralExpression
|
||||||
|
USimpleNameReferenceExpression (identifier = java)
|
||||||
+20
@@ -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 <anonymous class>(java.lang.String.java)
|
||||||
|
}
|
||||||
|
fun systemService1() {
|
||||||
|
return <anonymous class>(java.lang.Object.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Context {
|
||||||
|
public final fun ownSystemService2() : error.NonExistentClass {
|
||||||
|
return <anonymous class>(java.lang.String.java)
|
||||||
|
}
|
||||||
|
public fun Context() = UastEmptyExpression
|
||||||
|
fun ownSystemService1() {
|
||||||
|
return <anonymous class>(java.lang.Object.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,6 +102,9 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLambdaReturn() = doTest("LambdaReturn")
|
fun testLambdaReturn() = doTest("LambdaReturn")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReified() = doTest("Reified")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withForceUInjectionHostValue(call: () -> Unit) {
|
fun withForceUInjectionHostValue(call: () -> Unit) {
|
||||||
|
|||||||
@@ -96,4 +96,7 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLambdaReturn() = doTest("LambdaReturn")
|
fun testLambdaReturn() = doTest("LambdaReturn")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReified() = doTest("Reified")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user