191: Uast: support convertToAlternatives for KtProperty
This commit is contained in:
@@ -219,7 +219,7 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
convertNonLocalProperty(original, givenParent, expectedTypes)
|
convertNonLocalProperty(original, givenParent, expectedTypes).firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
is KtParameter -> el<UParameter> {
|
is KtParameter -> el<UParameter> {
|
||||||
@@ -279,7 +279,9 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
return convertElement(element, null, requiredTypes)
|
return convertElement(element, null, requiredTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : UElement> convertToAlternatives(element: PsiElement, requiredTypes: Array<out Class<out T>>) = when (element) {
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : UElement> convertToAlternatives(element: PsiElement, requiredTypes: Array<out Class<out T>>): Sequence<T> = when {
|
||||||
|
(element is KtProperty && !element.isLocal) -> convertNonLocalProperty(element, null, requiredTypes) as Sequence<T>
|
||||||
else -> sequenceOf(convertElementWithParent(element, requiredTypes.nonEmptyOr(DEFAULT_TYPES_LIST)) as? T).filterNotNull()
|
else -> sequenceOf(convertElementWithParent(element, requiredTypes.nonEmptyOr(DEFAULT_TYPES_LIST)) as? T).filterNotNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,18 +300,24 @@ internal inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.
|
|||||||
|
|
||||||
internal fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
|
internal fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
|
||||||
|
|
||||||
private fun convertNonLocalProperty(property: KtProperty,
|
private fun convertNonLocalProperty(
|
||||||
givenParent: UElement?,
|
property: KtProperty,
|
||||||
requiredType: Array<out Class<out UElement>>
|
givenParent: UElement?,
|
||||||
): UElement? {
|
requiredType: Array<out Class<out UElement>>
|
||||||
|
): Sequence<UElement> {
|
||||||
val methods = LightClassUtil.getLightClassPropertyMethods(property)
|
val methods = LightClassUtil.getLightClassPropertyMethods(property)
|
||||||
return methods.backingField?.let { backingField ->
|
return requiredType.accommodate(
|
||||||
with(requiredType) {
|
alternative {
|
||||||
el<UField> { KotlinUField(backingField, (backingField as? KtLightElement<*,*>)?.kotlinOrigin, givenParent) }
|
methods.backingField?.let { KotlinUField(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, givenParent) }
|
||||||
|
},
|
||||||
|
alternative {
|
||||||
|
// TODO: make it possible to use `convertDeclaration` without `KotlinUastLanguagePlugin` creation
|
||||||
|
methods.getter?.let { KotlinUastLanguagePlugin().convertDeclaration(it, givenParent, arrayOf(UMethod::class.java)) as? UMethod }
|
||||||
|
},
|
||||||
|
alternative {
|
||||||
|
methods.setter?.let { KotlinUastLanguagePlugin().convertDeclaration(it, givenParent, arrayOf(UMethod::class.java)) as? UMethod }
|
||||||
}
|
}
|
||||||
} ?: methods.getter?.let { getter ->
|
)
|
||||||
KotlinUastLanguagePlugin().convertDeclaration(getter, givenParent, requiredType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object KotlinConverter {
|
internal object KotlinConverter {
|
||||||
@@ -348,11 +356,7 @@ internal object KotlinConverter {
|
|||||||
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
|
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
|
||||||
is KtVariableDeclaration ->
|
is KtVariableDeclaration ->
|
||||||
if (element is KtProperty && !element.isLocal) {
|
if (element is KtProperty && !element.isLocal) {
|
||||||
el<UField> {
|
convertNonLocalProperty(element, givenParent, this).firstOrNull()
|
||||||
LightClassUtil.getLightClassBackingField(element)?.let {
|
|
||||||
KotlinUField(it, element, givenParent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
el<UVariable> {
|
el<UVariable> {
|
||||||
@@ -609,3 +613,15 @@ private fun elementTypes(requiredType: Class<out UElement>?) = requiredType?.let
|
|||||||
|
|
||||||
private fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) = takeIf { it.isNotEmpty() }
|
private fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) = takeIf { it.isNotEmpty() }
|
||||||
?: default
|
?: default
|
||||||
|
|
||||||
|
private fun <U : UElement> Array<out Class<out UElement>>.accommodate(vararg makers: UElementAlternative<out U>): Sequence<UElement> {
|
||||||
|
val makersSeq = makers.asSequence()
|
||||||
|
return this.asSequence()
|
||||||
|
.flatMap { requiredType -> makersSeq.filter { requiredType.isAssignableFrom(it.uType) } }
|
||||||
|
.distinct()
|
||||||
|
.mapNotNull { it.make.invoke() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified U : UElement> alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make)
|
||||||
|
|
||||||
|
private class UElementAlternative<U : UElement>(val uType: Class<U>, val make: () -> U?)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class ClassA {
|
||||||
|
|
||||||
|
var writebleProp: Int = 0
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.uast.test.kotlin
|
||||||
|
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
import org.jetbrains.uast.*
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class KotlinUastAlternativesTest : AbstractKotlinUastTest() {
|
||||||
|
override fun check(testName: String, file: UFile) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPropertyAlternatives() {
|
||||||
|
doTest("ManyAlternatives") { name, file ->
|
||||||
|
val index = file.psi.text.indexOf("writebleProp")
|
||||||
|
val ktProperty = PsiTreeUtil.getParentOfType(file.psi.findElementAt(index), KtProperty::class.java)!!
|
||||||
|
val plugin = UastLanguagePlugin.byLanguage(ktProperty.language)!!
|
||||||
|
|
||||||
|
plugin.convertToAlternatives<UElement>(ktProperty, arrayOf(UField::class.java)).let {
|
||||||
|
assertEquals(
|
||||||
|
"@org.jetbrains.annotations.NotNull private var writebleProp: int = 0",
|
||||||
|
it.joinToString(transform = UElement::asRenderString)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.convertToAlternatives<UElement>(ktProperty, arrayOf(UMethod::class.java, UField::class.java)).let {
|
||||||
|
assertEquals(
|
||||||
|
"public final fun getWritebleProp() : int = UastEmptyExpression, " +
|
||||||
|
"public final fun setWritebleProp(@null p: int) : void = UastEmptyExpression, " +
|
||||||
|
"@org.jetbrains.annotations.NotNull private var writebleProp: int = 0",
|
||||||
|
it.joinToString(transform = UElement::asRenderString)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.convertToAlternatives<UElement>(ktProperty, arrayOf(UField::class.java, UMethod::class.java)).let {
|
||||||
|
assertEquals(
|
||||||
|
"@org.jetbrains.annotations.NotNull private var writebleProp: int = 0, " +
|
||||||
|
"public final fun getWritebleProp() : int = UastEmptyExpression, " +
|
||||||
|
"public final fun setWritebleProp(@null p: int) : void = UastEmptyExpression",
|
||||||
|
it.joinToString(transform = UElement::asRenderString)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.convertToAlternatives<UElement>(ktProperty, arrayOf(UDeclaration::class.java)).let {
|
||||||
|
assertEquals(
|
||||||
|
"@org.jetbrains.annotations.NotNull private var writebleProp: int = 0, " +
|
||||||
|
"public final fun getWritebleProp() : int = UastEmptyExpression, " +
|
||||||
|
"public final fun setWritebleProp(@null p: int) : void = UastEmptyExpression",
|
||||||
|
it.joinToString(transform = UElement::asRenderString)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user