191: Uast: support convertToAlternatives for KtProperty
This commit is contained in:
@@ -219,7 +219,7 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
||||
}
|
||||
else {
|
||||
convertNonLocalProperty(original, givenParent, expectedTypes)
|
||||
convertNonLocalProperty(original, givenParent, expectedTypes).firstOrNull()
|
||||
}
|
||||
|
||||
is KtParameter -> el<UParameter> {
|
||||
@@ -279,7 +279,9 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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) }
|
||||
|
||||
private fun convertNonLocalProperty(property: KtProperty,
|
||||
givenParent: UElement?,
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): UElement? {
|
||||
private fun convertNonLocalProperty(
|
||||
property: KtProperty,
|
||||
givenParent: UElement?,
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): Sequence<UElement> {
|
||||
val methods = LightClassUtil.getLightClassPropertyMethods(property)
|
||||
return methods.backingField?.let { backingField ->
|
||||
with(requiredType) {
|
||||
el<UField> { KotlinUField(backingField, (backingField as? KtLightElement<*,*>)?.kotlinOrigin, givenParent) }
|
||||
return requiredType.accommodate(
|
||||
alternative {
|
||||
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 {
|
||||
@@ -348,11 +356,7 @@ internal object KotlinConverter {
|
||||
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
|
||||
is KtVariableDeclaration ->
|
||||
if (element is KtProperty && !element.isLocal) {
|
||||
el<UField> {
|
||||
LightClassUtil.getLightClassBackingField(element)?.let {
|
||||
KotlinUField(it, element, givenParent)
|
||||
}
|
||||
}
|
||||
convertNonLocalProperty(element, givenParent, this).firstOrNull()
|
||||
}
|
||||
else {
|
||||
el<UVariable> {
|
||||
@@ -608,4 +612,16 @@ private fun expressionTypes(requiredType: Class<out UElement>?) = requiredType?.
|
||||
private fun elementTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST
|
||||
|
||||
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