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
|
||||
|
||||
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<UClass>()?.let { return it } // mutlifile facade class
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (psi is KtLightClassForLocalDeclaration) {
|
||||
val originParent = psi.kotlinOrigin.parent
|
||||
parent = when (originParent) {
|
||||
|
||||
@@ -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<UClass>()?.let { return it } // mutlifile facade class
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (psi is KtLightClassForLocalDeclaration) {
|
||||
val originParent = psi.kotlinOrigin.parent
|
||||
parent = when (originParent) {
|
||||
|
||||
@@ -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<UMethod> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<UMethod> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<UMethod>(javaPsi.methods.size)
|
||||
val handledKtDeclarations = mutableSetOf<PsiElement>()
|
||||
|
||||
for (lightMethod in javaPsi.methods) {
|
||||
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
|
||||
|
||||
@@ -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?)
|
||||
|
||||
|
||||
@@ -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?)
|
||||
|
||||
|
||||
@@ -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?)
|
||||
|
||||
|
||||
+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
|
||||
fun testLambdaReturn() = doTest("LambdaReturn")
|
||||
|
||||
@Test
|
||||
fun testReified() = doTest("Reified")
|
||||
}
|
||||
|
||||
fun withForceUInjectionHostValue(call: () -> Unit) {
|
||||
|
||||
@@ -96,4 +96,7 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
|
||||
|
||||
@Test
|
||||
fun testLambdaReturn() = doTest("LambdaReturn")
|
||||
|
||||
@Test
|
||||
fun testReified() = doTest("Reified")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user