191: Uast: refactoring: all convert* methods were moved to KotlinConverter
This commit is contained in:
+170
-177
@@ -42,6 +42,8 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.expressions.UInjectionHost
|
import org.jetbrains.uast.expressions.UInjectionHost
|
||||||
|
import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclaration
|
||||||
|
import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclarationOrElement
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||||
import org.jetbrains.uast.kotlin.expressions.*
|
import org.jetbrains.uast.kotlin.expressions.*
|
||||||
@@ -87,29 +89,6 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
return convertDeclarationOrElement(element, null, elementTypes(requiredType))
|
return convertDeclarationOrElement(element, null, elementTypes(requiredType))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertDeclarationOrElement(
|
|
||||||
element: PsiElement,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Array<out Class<out UElement>>
|
|
||||||
): UElement? {
|
|
||||||
if (element is UElement) return element
|
|
||||||
|
|
||||||
if (element.isValid) {
|
|
||||||
element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.get()?.let { cachedUElement ->
|
|
||||||
return if (requiredType.isAssignableFrom(cachedUElement.javaClass)) cachedUElement else null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val uElement = convertDeclaration(element, givenParent, requiredType)
|
|
||||||
?: KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
|
||||||
/*
|
|
||||||
if (uElement != null) {
|
|
||||||
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, WeakReference(uElement))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return uElement
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMethodCallExpression(
|
override fun getMethodCallExpression(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
containingClassFqName: String?,
|
containingClassFqName: String?,
|
||||||
@@ -150,101 +129,6 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
return UastLanguagePlugin.ResolvedConstructor(uExpression, method, containingClass)
|
return UastLanguagePlugin.ResolvedConstructor(uExpression, method, containingClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun convertDeclaration(element: PsiElement,
|
|
||||||
givenParent: UElement?,
|
|
||||||
expectedTypes: Array<out Class<out UElement>>
|
|
||||||
): UElement? {
|
|
||||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? = { ctor(element as P, givenParent) }
|
|
||||||
|
|
||||||
fun <P : PsiElement, K : KtElement> buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? =
|
|
||||||
{ ctor(element as P, ktElement, givenParent) }
|
|
||||||
|
|
||||||
fun <P : PsiElement, K : KtElement> buildKtOpt(ktElement: K?, ctor: (P, K?, UElement?) -> UElement): () -> UElement? =
|
|
||||||
{ ctor(element as P, ktElement, givenParent) }
|
|
||||||
|
|
||||||
val original = element.originalElement
|
|
||||||
return with(expectedTypes) {
|
|
||||||
when (original) {
|
|
||||||
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
|
|
||||||
is KtLightClass -> when (original.kotlinOrigin) {
|
|
||||||
is KtEnumEntry -> el<UEnumConstant> {
|
|
||||||
convertEnumEntry(original.kotlinOrigin as KtEnumEntry, givenParent)
|
|
||||||
}
|
|
||||||
else -> el<UClass> { KotlinUClass.create(original, givenParent) }
|
|
||||||
}
|
|
||||||
is KtLightFieldImpl.KtLightEnumConstant -> el<UEnumConstant>(buildKtOpt(original.kotlinOrigin, ::KotlinUEnumConstant))
|
|
||||||
is KtLightField -> el<UField>(buildKtOpt(original.kotlinOrigin, ::KotlinUField))
|
|
||||||
is KtLightParameter -> el<UParameter>(buildKtOpt(original.kotlinOrigin, ::KotlinUParameter))
|
|
||||||
is UastKotlinPsiParameter -> el<UParameter>(buildKt(original.ktParameter, ::KotlinUParameter))
|
|
||||||
is UastKotlinPsiVariable -> el<UVariable>(buildKt(original.ktElement, ::KotlinUVariable))
|
|
||||||
|
|
||||||
is KtEnumEntry -> el<UEnumConstant> {
|
|
||||||
convertEnumEntry(original, givenParent)
|
|
||||||
}
|
|
||||||
is KtClassOrObject -> convertClassOrObject(original, givenParent, this).firstOrNull()
|
|
||||||
is KtFunction ->
|
|
||||||
if (original.isLocal) {
|
|
||||||
el<ULambdaExpression> {
|
|
||||||
val parent = original.parent
|
|
||||||
if (parent is KtLambdaExpression) {
|
|
||||||
KotlinULambdaExpression(parent, givenParent) // your parent is the ULambdaExpression
|
|
||||||
} else if (original.name.isNullOrEmpty()) {
|
|
||||||
createLocalFunctionLambdaExpression(original, givenParent)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val uDeclarationsExpression = createLocalFunctionDeclaration(original, givenParent)
|
|
||||||
val localFunctionVar = uDeclarationsExpression.declarations.single() as KotlinLocalFunctionUVariable
|
|
||||||
localFunctionVar.uastInitializer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
el<UMethod> {
|
|
||||||
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
|
|
||||||
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtPropertyAccessor -> el<UMethod> {
|
|
||||||
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
|
|
||||||
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtProperty ->
|
|
||||||
if (original.isLocal) {
|
|
||||||
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
convertNonLocalProperty(original, givenParent, expectedTypes).firstOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtParameter -> convertParameter(original, givenParent, this).firstOrNull()
|
|
||||||
|
|
||||||
is KtFile -> el<UFile> { KotlinUFile(original, this@KotlinUastLanguagePlugin) }
|
|
||||||
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement, this@KotlinUastLanguagePlugin) }
|
|
||||||
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
|
||||||
is KtCallExpression ->
|
|
||||||
if (expectedTypes.isAssignableFrom(KotlinUNestedAnnotation::class.java) && !expectedTypes.isAssignableFrom(UCallExpression::class.java)) {
|
|
||||||
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
|
|
||||||
} else null
|
|
||||||
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, expectedTypes)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun convertEnumEntry(original: KtEnumEntry, givenParent: UElement?): UElement? {
|
|
||||||
return LightClassUtil.getLightClassBackingField(original)?.let { psiField ->
|
|
||||||
if (psiField is KtLightFieldImpl.KtLightEnumConstant) {
|
|
||||||
KotlinUEnumConstant(psiField, psiField.kotlinOrigin, givenParent)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isExpressionValueUsed(element: UExpression): Boolean {
|
override fun isExpressionValueUsed(element: UExpression): Boolean {
|
||||||
return when (element) {
|
return when (element) {
|
||||||
is KotlinUSimpleReferenceExpression.KotlinAccessorCallExpression -> element.setterValue != null
|
is KotlinUSimpleReferenceExpression.KotlinAccessorCallExpression -> element.setterValue != null
|
||||||
@@ -269,9 +153,9 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : UElement> convertToAlternatives(element: PsiElement, requiredTypes: Array<out Class<out T>>): Sequence<T> = when {
|
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>
|
(element is KtProperty && !element.isLocal) -> KotlinConverter.convertNonLocalProperty(element, null, requiredTypes) as Sequence<T>
|
||||||
element is KtParameter -> convertParameter(element, null, requiredTypes) as Sequence<T>
|
element is KtParameter -> KotlinConverter.convertParameter(element, null, requiredTypes) as Sequence<T>
|
||||||
element is KtClassOrObject -> convertClassOrObject(element, null, requiredTypes) as Sequence<T>
|
element is KtClassOrObject -> KotlinConverter.convertClassOrObject(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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,62 +175,6 @@ 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 convertToPropertyAlternatives(
|
|
||||||
methods: LightClassUtil.PropertyAccessorsPsiMethods?,
|
|
||||||
givenParent: UElement?
|
|
||||||
): Array<UElementAlternative<*>> = if (methods != null) arrayOf(
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
) else emptyArray()
|
|
||||||
|
|
||||||
private fun convertNonLocalProperty(
|
|
||||||
property: KtProperty,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Array<out Class<out UElement>>
|
|
||||||
): Sequence<UElement> =
|
|
||||||
requiredType.accommodate(*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(property), givenParent))
|
|
||||||
|
|
||||||
|
|
||||||
private fun convertParameter(
|
|
||||||
element: KtParameter,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredTypes: Array<out Class<out UElement>>
|
|
||||||
): Sequence<UElement> = requiredTypes.accommodate(
|
|
||||||
alternative uParam@{
|
|
||||||
val ownerFunction = element.ownerFunction as? KtFunction ?: return@uParam null
|
|
||||||
val lightMethod = LightClassUtil.getLightClassMethod(ownerFunction) ?: return@uParam null
|
|
||||||
val lightParameter = lightMethod.parameterList.parameters.find { it.name == element.name } ?: return@uParam null
|
|
||||||
KotlinUParameter(lightParameter, element, givenParent)
|
|
||||||
},
|
|
||||||
*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(element), givenParent)
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun convertClassOrObject(
|
|
||||||
element: KtClassOrObject,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredTypes: Array<out Class<out UElement>>
|
|
||||||
): Sequence<UElement> {
|
|
||||||
val ktLightClass = element.toLightClass() ?: return emptySequence()
|
|
||||||
val uClass = KotlinUClass.create(ktLightClass, givenParent)
|
|
||||||
return requiredTypes.accommodate(
|
|
||||||
alternative { uClass },
|
|
||||||
alternative primaryConstructor@{
|
|
||||||
val primaryConstructor = element.primaryConstructor ?: return@primaryConstructor null
|
|
||||||
uClass.methods.asSequence()
|
|
||||||
.filter { it.sourcePsi == primaryConstructor }
|
|
||||||
.firstOrNull()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal object KotlinConverter {
|
internal object KotlinConverter {
|
||||||
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
|
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
|
||||||
@@ -598,6 +426,171 @@ internal object KotlinConverter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun convertEnumEntry(original: KtEnumEntry, givenParent: UElement?): UElement? {
|
||||||
|
return LightClassUtil.getLightClassBackingField(original)?.let { psiField ->
|
||||||
|
if (psiField is KtLightFieldImpl.KtLightEnumConstant) {
|
||||||
|
KotlinUEnumConstant(psiField, psiField.kotlinOrigin, givenParent)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun convertDeclaration(
|
||||||
|
element: PsiElement,
|
||||||
|
givenParent: UElement?,
|
||||||
|
expectedTypes: Array<out Class<out UElement>>
|
||||||
|
): UElement? {
|
||||||
|
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? = { ctor(element as P, givenParent) }
|
||||||
|
|
||||||
|
fun <P : PsiElement, K : KtElement> buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? =
|
||||||
|
{ ctor(element as P, ktElement, givenParent) }
|
||||||
|
|
||||||
|
fun <P : PsiElement, K : KtElement> buildKtOpt(ktElement: K?, ctor: (P, K?, UElement?) -> UElement): () -> UElement? =
|
||||||
|
{ ctor(element as P, ktElement, givenParent) }
|
||||||
|
|
||||||
|
val original = element.originalElement
|
||||||
|
return with(expectedTypes) {
|
||||||
|
when (original) {
|
||||||
|
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
|
||||||
|
is KtLightClass -> when (original.kotlinOrigin) {
|
||||||
|
is KtEnumEntry -> el<UEnumConstant> {
|
||||||
|
convertEnumEntry(original.kotlinOrigin as KtEnumEntry, givenParent)
|
||||||
|
}
|
||||||
|
else -> el<UClass> { KotlinUClass.create(original, givenParent) }
|
||||||
|
}
|
||||||
|
is KtLightFieldImpl.KtLightEnumConstant -> el<UEnumConstant>(buildKtOpt(original.kotlinOrigin, ::KotlinUEnumConstant))
|
||||||
|
is KtLightField -> el<UField>(buildKtOpt(original.kotlinOrigin, ::KotlinUField))
|
||||||
|
is KtLightParameter -> el<UParameter>(buildKtOpt(original.kotlinOrigin, ::KotlinUParameter))
|
||||||
|
is UastKotlinPsiParameter -> el<UParameter>(buildKt(original.ktParameter, ::KotlinUParameter))
|
||||||
|
is UastKotlinPsiVariable -> el<UVariable>(buildKt(original.ktElement, ::KotlinUVariable))
|
||||||
|
|
||||||
|
is KtEnumEntry -> el<UEnumConstant> {
|
||||||
|
convertEnumEntry(original, givenParent)
|
||||||
|
}
|
||||||
|
is KtClassOrObject -> convertClassOrObject(original, givenParent, this).firstOrNull()
|
||||||
|
is KtFunction ->
|
||||||
|
if (original.isLocal) {
|
||||||
|
el<ULambdaExpression> {
|
||||||
|
val parent = original.parent
|
||||||
|
if (parent is KtLambdaExpression) {
|
||||||
|
KotlinULambdaExpression(parent, givenParent) // your parent is the ULambdaExpression
|
||||||
|
} else if (original.name.isNullOrEmpty()) {
|
||||||
|
createLocalFunctionLambdaExpression(original, givenParent)
|
||||||
|
} else {
|
||||||
|
val uDeclarationsExpression = createLocalFunctionDeclaration(original, givenParent)
|
||||||
|
val localFunctionVar = uDeclarationsExpression.declarations.single() as KotlinLocalFunctionUVariable
|
||||||
|
localFunctionVar.uastInitializer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
el<UMethod> {
|
||||||
|
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
|
||||||
|
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is KtPropertyAccessor -> el<UMethod> {
|
||||||
|
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
|
||||||
|
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
is KtProperty ->
|
||||||
|
if (original.isLocal) {
|
||||||
|
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
||||||
|
} else {
|
||||||
|
convertNonLocalProperty(original, givenParent, expectedTypes).firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
is KtParameter -> convertParameter(original, givenParent, this).firstOrNull()
|
||||||
|
|
||||||
|
is KtFile -> el<UFile> { KotlinUFile(original) }
|
||||||
|
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement) }
|
||||||
|
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
||||||
|
is KtCallExpression ->
|
||||||
|
if (expectedTypes.isAssignableFrom(KotlinUNestedAnnotation::class.java) && !expectedTypes.isAssignableFrom(UCallExpression::class.java)) {
|
||||||
|
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
|
||||||
|
} else null
|
||||||
|
is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, expectedTypes)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun convertDeclarationOrElement(
|
||||||
|
element: PsiElement,
|
||||||
|
givenParent: UElement?,
|
||||||
|
expectedTypes: Array<out Class<out UElement>>
|
||||||
|
): UElement? {
|
||||||
|
if (element is UElement) return element
|
||||||
|
|
||||||
|
if (element.isValid) {
|
||||||
|
element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.get()?.let { cachedUElement ->
|
||||||
|
return if (expectedTypes.isAssignableFrom(cachedUElement.javaClass)) cachedUElement else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val uElement = convertDeclaration(element, givenParent, expectedTypes)
|
||||||
|
?: KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
||||||
|
/*
|
||||||
|
if (uElement != null) {
|
||||||
|
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, WeakReference(uElement))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return uElement
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertToPropertyAlternatives(
|
||||||
|
methods: LightClassUtil.PropertyAccessorsPsiMethods?,
|
||||||
|
givenParent: UElement?
|
||||||
|
): Array<UElementAlternative<*>> = if (methods != null) arrayOf(
|
||||||
|
alternative { methods.backingField?.let { KotlinUField(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, givenParent) } },
|
||||||
|
alternative { methods.getter?.let { convertDeclaration(it, givenParent, arrayOf(UMethod::class.java)) as? UMethod } },
|
||||||
|
alternative { methods.setter?.let { convertDeclaration(it, givenParent, arrayOf(UMethod::class.java)) as? UMethod } }
|
||||||
|
) else emptyArray()
|
||||||
|
|
||||||
|
fun convertNonLocalProperty(
|
||||||
|
property: KtProperty,
|
||||||
|
givenParent: UElement?,
|
||||||
|
expectedTypes: Array<out Class<out UElement>>
|
||||||
|
): Sequence<UElement> =
|
||||||
|
expectedTypes.accommodate(*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(property), givenParent))
|
||||||
|
|
||||||
|
|
||||||
|
fun convertParameter(
|
||||||
|
element: KtParameter,
|
||||||
|
givenParent: UElement?,
|
||||||
|
expectedTypes: Array<out Class<out UElement>>
|
||||||
|
): Sequence<UElement> = expectedTypes.accommodate(
|
||||||
|
alternative uParam@{
|
||||||
|
val ownerFunction = element.ownerFunction as? KtFunction ?: return@uParam null
|
||||||
|
val lightMethod = LightClassUtil.getLightClassMethod(ownerFunction) ?: return@uParam null
|
||||||
|
val lightParameter = lightMethod.parameterList.parameters.find { it.name == element.name } ?: return@uParam null
|
||||||
|
KotlinUParameter(lightParameter, element, givenParent)
|
||||||
|
},
|
||||||
|
*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(element), givenParent)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun convertClassOrObject(
|
||||||
|
element: KtClassOrObject,
|
||||||
|
givenParent: UElement?,
|
||||||
|
expectedTypes: Array<out Class<out UElement>>
|
||||||
|
): Sequence<UElement> {
|
||||||
|
val ktLightClass = element.toLightClass() ?: return emptySequence()
|
||||||
|
val uClass = KotlinUClass.create(ktLightClass, givenParent)
|
||||||
|
return expectedTypes.accommodate(
|
||||||
|
alternative { uClass },
|
||||||
|
alternative primaryConstructor@{
|
||||||
|
val primaryConstructor = element.primaryConstructor ?: return@primaryConstructor null
|
||||||
|
uClass.methods.asSequence()
|
||||||
|
.filter { it.sourcePsi == primaryConstructor }
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
|
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
|
||||||
return expression?.let { convertExpression(it, parent, DEFAULT_EXPRESSION_TYPES_LIST) } ?: UastEmptyExpression
|
return expression?.let { convertExpression(it, parent, DEFAULT_EXPRESSION_TYPES_LIST) } ?: UastEmptyExpression
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.uast.kotlin
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiComment
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
|
||||||
|
import org.jetbrains.kotlin.asJava.findFacadeClass
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightClass
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.uast.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class KotlinUFile(
|
||||||
|
override val psi: KtFile,
|
||||||
|
override val languagePlugin: UastLanguagePlugin =
|
||||||
|
UastLanguagePlugin.byLanguage(KotlinLanguage.INSTANCE) ?: KotlinUastLanguagePlugin()
|
||||||
|
) : UFile, JvmDeclarationUElementPlaceholder {
|
||||||
|
override val packageName: String
|
||||||
|
get() = psi.packageFqName.asString()
|
||||||
|
|
||||||
|
override val annotations: List<UAnnotation>
|
||||||
|
get() = psi.annotationEntries.map { KotlinUAnnotation(it, this) }
|
||||||
|
|
||||||
|
override val javaPsi: PsiElement? = null
|
||||||
|
|
||||||
|
override val sourcePsi: PsiElement? = psi
|
||||||
|
|
||||||
|
override val allCommentsInFile by lz {
|
||||||
|
val comments = ArrayList<UComment>(0)
|
||||||
|
psi.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||||
|
override fun visitComment(comment: PsiComment) {
|
||||||
|
comments += UComment(comment, this@KotlinUFile)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
comments
|
||||||
|
}
|
||||||
|
|
||||||
|
override val imports by lz { psi.importDirectives.map { KotlinUImportStatement(it, this) } }
|
||||||
|
|
||||||
|
override val classes by lz {
|
||||||
|
val facadeOrScriptClass = if (psi.isScript()) psi.script?.toLightClass() else psi.findFacadeClass()
|
||||||
|
val classes = psi.declarations.mapNotNull { (it as? KtClassOrObject)?.toLightClass()?.toUClass() }
|
||||||
|
|
||||||
|
(facadeOrScriptClass?.toUClass()?.let { listOf(it) } ?: emptyList()) + classes
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiClass.toUClass() = languagePlugin.convertOpt<UClass>(this, this@KotlinUFile)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user