FIR/UAST: commonize base UClass (with bogus annotation abstraction)
This commit is contained in:
committed by
Ilya Kirillov
parent
06c20bb10e
commit
1749c90083
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.kotlin
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.uast.*
|
||||
|
||||
abstract class BaseKotlinUClass(
|
||||
psi: KtLightClass,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
final override val ktClass = psi.kotlinOrigin
|
||||
|
||||
override val javaPsi: KtLightClass = psi
|
||||
|
||||
override val sourcePsi: KtClassOrObject? = ktClass
|
||||
|
||||
override val psi = unwrap<UClass, PsiClass>(psi)
|
||||
|
||||
override fun getSourceElement() = sourcePsi ?: this
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, ktClass)
|
||||
|
||||
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override val uastAnchor by lazy { getIdentifierSourcePsi()?.let { KotlinUIdentifier(nameIdentifier, it, this) } }
|
||||
|
||||
private fun getIdentifierSourcePsi(): PsiElement? {
|
||||
ktClass?.nameIdentifier?.let { return it }
|
||||
(ktClass as? KtObjectDeclaration)?.getObjectKeyword()?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getInnerClasses(): Array<UClass> {
|
||||
// filter DefaultImpls to avoid processing same methods from original interface multiple times
|
||||
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
|
||||
return psi.innerClasses.filter {
|
||||
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass
|
||||
}.mapNotNull {
|
||||
languagePlugin?.convertOpt<UClass>(it, this)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
override fun getSuperClass(): UClass? = super.getSuperClass()
|
||||
override fun getFields(): Array<UField> = super.getFields()
|
||||
override fun getInitializers(): Array<UClassInitializer> = super.getInitializers()
|
||||
|
||||
override fun getMethods(): Array<UMethod> {
|
||||
val hasPrimaryConstructor = ktClass?.hasPrimaryConstructor() ?: false
|
||||
var secondaryConstructorsCount = 0
|
||||
|
||||
fun createUMethod(psiMethod: PsiMethod): UMethod {
|
||||
return if (psiMethod is KtLightMethod &&
|
||||
psiMethod.isConstructor) {
|
||||
if (!hasPrimaryConstructor && secondaryConstructorsCount++ == 0)
|
||||
buildSecondaryConstructorUMethod(ktClass, psiMethod, this)
|
||||
else
|
||||
buildPrimaryConstructorUMethod(ktClass, psiMethod, this)
|
||||
} else {
|
||||
languagePlugin?.convertOpt(psiMethod, this) ?: reportConvertFailure(psiMethod)
|
||||
}
|
||||
}
|
||||
|
||||
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
||||
|
||||
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)
|
||||
|
||||
// Ensure we pick the main Kotlin origin, not the auxiliary one
|
||||
val kotlinOrigin = (lightMethod as? KtLightMethod)?.kotlinOrigin ?: uMethod.sourcePsi
|
||||
handledKtDeclarations.addIfNotNull(kotlinOrigin)
|
||||
}
|
||||
|
||||
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) {
|
||||
baseResolveProviderService.baseKotlinConverter.convertDeclaration(it, this, arrayOf(UElement::class.java)) as? UMethod
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
||||
abstract fun buildPrimaryConstructorUMethod(ktClass: KtClassOrObject?, psi: KtLightMethod, givenParent: UElement?) : UMethod
|
||||
abstract fun buildSecondaryConstructorUMethod(ktClass: KtClassOrObject?, psi: KtLightMethod, givenParent: UElement?) : UMethod
|
||||
}
|
||||
@@ -19,10 +19,12 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.expressions.UInjectionHost
|
||||
import org.jetbrains.uast.kotlin.declarations.FirKotlinUAnnotation
|
||||
|
||||
internal object FirKotlinConverter : BaseKotlinConverter {
|
||||
override fun convertAnnotation(annotationEntry: KtAnnotationEntry, givenParent: UElement?): UAnnotation {
|
||||
TODO("Not yet implemented")
|
||||
// TODO: need to polish/implement annotations more
|
||||
return FirKotlinUAnnotation(annotationEntry, givenParent)
|
||||
}
|
||||
|
||||
internal fun convertDeclarationOrElement(
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.kotlin.declarations
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.ResolveResult
|
||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.KotlinAbstractUElement
|
||||
|
||||
class FirKotlinUAnnotation(
|
||||
annotationEntry: KtAnnotationEntry,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUElement(givenParent), UAnnotation, UAnchorOwner, UMultiResolvable {
|
||||
override val javaPsi = annotationEntry.toLightAnnotation()
|
||||
|
||||
override val psi: PsiElement = annotationEntry
|
||||
|
||||
override val attributeValues: List<UNamedExpression>
|
||||
get() = listOf() // TODO("Not yet implemented")
|
||||
|
||||
override val qualifiedName: String?
|
||||
get() = "not-implemented-annotation"
|
||||
|
||||
override val uastAnchor: UIdentifier?
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun findAttributeValue(name: String?): UExpression? {
|
||||
// TODO("Not yet implemented")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun findDeclaredAttributeValue(name: String?): UExpression? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun resolve(): PsiClass? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun multiResolve(): Iterable<ResolveResult> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
+6
-99
@@ -5,114 +5,21 @@
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.uast.*
|
||||
|
||||
// TODO: can be commonized once *KotlinUClass is commonized
|
||||
class FirKotlinUClass(
|
||||
override val javaPsi: KtLightClass,
|
||||
psi: KtLightClass,
|
||||
givenParent: UElement?,
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by javaPsi {
|
||||
override val ktClass: KtClassOrObject? = javaPsi.kotlinOrigin
|
||||
|
||||
override val psi = unwrap<UClass, PsiClass>(javaPsi)
|
||||
|
||||
override fun getSourceElement() = sourcePsi
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = sourcePsi?.originalElement
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier = UastLightIdentifier(psi, ktClass)
|
||||
|
||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override val uastAnchor: UIdentifier? by lz {
|
||||
getIdentifierSourcePsi()?.let {
|
||||
KotlinUIdentifier(nameIdentifier, it, this)
|
||||
}
|
||||
) : BaseKotlinUClass(psi, givenParent) {
|
||||
override fun buildPrimaryConstructorUMethod(ktClass: KtClassOrObject?, psi: KtLightMethod, givenParent: UElement?): UMethod {
|
||||
return FirKotlinConstructorUMethod(ktClass, psi, givenParent)
|
||||
}
|
||||
|
||||
private fun getIdentifierSourcePsi(): PsiElement? {
|
||||
ktClass?.nameIdentifier?.let { return it }
|
||||
(ktClass as? KtObjectDeclaration)?.getObjectKeyword()?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getInnerClasses(): Array<UClass> {
|
||||
// filter DefaultImpls to avoid processing same methods from original interface multiple times
|
||||
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
|
||||
return psi.innerClasses.filter {
|
||||
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass
|
||||
}.mapNotNull {
|
||||
languagePlugin?.convertOpt<UClass>(it, this)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
override fun getSuperClass(): UClass? {
|
||||
return super.getSuperClass()
|
||||
}
|
||||
|
||||
override fun getFields(): Array<UField> {
|
||||
return super.getFields()
|
||||
}
|
||||
|
||||
override fun getInitializers(): Array<UClassInitializer> {
|
||||
// TODO: why not just emptyList()? Kotlin class won't have <clinit>?
|
||||
return super.getInitializers()
|
||||
}
|
||||
|
||||
override fun getMethods(): Array<UMethod> {
|
||||
val hasPrimaryConstructor = ktClass?.hasPrimaryConstructor() ?: false
|
||||
var secondaryConstructorsCount = 0
|
||||
|
||||
fun createUMethod(psiMethod: PsiMethod): UMethod {
|
||||
return if (psiMethod is KtLightMethod && psiMethod.isConstructor) {
|
||||
if (!hasPrimaryConstructor && secondaryConstructorsCount++ == 0)
|
||||
FirKotlinSecondaryConstructorWithInitializersUMethod(ktClass, psiMethod, this)
|
||||
else
|
||||
FirKotlinConstructorUMethod(ktClass, psiMethod, this)
|
||||
} else {
|
||||
languagePlugin?.convertOpt(psiMethod, this) ?: reportConvertFailure(psiMethod)
|
||||
}
|
||||
}
|
||||
|
||||
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
||||
|
||||
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)
|
||||
|
||||
// Ensure we pick the main Kotlin origin, not the auxiliary one
|
||||
val kotlinOrigin = (lightMethod as? KtLightMethod)?.kotlinOrigin ?: uMethod.sourcePsi
|
||||
handledKtDeclarations.addIfNotNull(kotlinOrigin)
|
||||
}
|
||||
|
||||
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) {
|
||||
baseResolveProviderService.baseKotlinConverter.convertDeclaration(it, this, arrayOf(UElement::class.java)) as? UMethod
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
override fun buildSecondaryConstructorUMethod(ktClass: KtClassOrObject?, psi: KtLightMethod, givenParent: UElement?): UMethod {
|
||||
return FirKotlinSecondaryConstructorWithInitializersUMethod(ktClass, psi, givenParent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+5
@@ -2,16 +2,21 @@ UFile (package = )
|
||||
UClass (name = Annotation)
|
||||
UMethod (name = strings)
|
||||
UClass (name = A)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = A)
|
||||
UClass (name = AnnotationInner)
|
||||
UMethod (name = value)
|
||||
UClass (name = B1)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = B1)
|
||||
UClass (name = B2)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = B2)
|
||||
UClass (name = AnnotationArray)
|
||||
UMethod (name = value)
|
||||
UClass (name = C)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = C)
|
||||
UClass (name = C2)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = C2)
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
UFile (package = )
|
||||
UClass (name = A)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = A)
|
||||
UClass (name = MyAnnotation)
|
||||
UMethod (name = text)
|
||||
UClass (name = B)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UField (name = Companion)
|
||||
UMethod (name = B)
|
||||
UClass (name = InB)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = InB)
|
||||
UClass (name = Companion)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UMethod (name = Companion)
|
||||
UClass (name = Obj)
|
||||
UAnnotation (fqName = not-implemented-annotation)
|
||||
UField (name = INSTANCE)
|
||||
UMethod (name = Obj)
|
||||
|
||||
@@ -2,16 +2,21 @@ UFile (package = ) [public abstract annotation Annotation {...]
|
||||
UClass (name = Annotation) [public abstract annotation Annotation {...}]
|
||||
UMethod (name = strings) [public abstract fun strings() : java.lang.String[] = UastEmptyExpression]
|
||||
UClass (name = A) [public final class A {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = A) [public fun A() = UastEmptyExpression]
|
||||
UClass (name = AnnotationInner) [public abstract annotation AnnotationInner {...}]
|
||||
UMethod (name = value) [public abstract fun value() : Annotation = UastEmptyExpression]
|
||||
UClass (name = B1) [public final class B1 {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = B1) [public fun B1() = UastEmptyExpression]
|
||||
UClass (name = B2) [public final class B2 {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = B2) [public fun B2() = UastEmptyExpression]
|
||||
UClass (name = AnnotationArray) [public abstract annotation AnnotationArray {...}]
|
||||
UMethod (name = value) [public abstract fun value() : Annotation[] = UastEmptyExpression]
|
||||
UClass (name = C) [public final class C {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = C) [public fun C() = UastEmptyExpression]
|
||||
UClass (name = C2) [public final class C2 {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = C2) [public fun C2() = UastEmptyExpression]
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
UFile (package = ) [public final class A {...]
|
||||
UClass (name = A) [public final class A {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = A) [public fun A() = UastEmptyExpression]
|
||||
UClass (name = MyAnnotation) [public abstract annotation MyAnnotation {...}]
|
||||
UMethod (name = text) [public abstract fun text() : java.lang.String = UastEmptyExpression]
|
||||
UClass (name = B) [public final class B {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UField (name = Companion) [public static final var Companion: B.Companion]
|
||||
UMethod (name = B) [public fun B() = UastEmptyExpression]
|
||||
UClass (name = InB) [public static final class InB {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = InB) [public fun InB() = UastEmptyExpression]
|
||||
UClass (name = Companion) [public static final class Companion {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = Companion) [private fun Companion() = UastEmptyExpression]
|
||||
UClass (name = Obj) [public final class Obj {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UField (name = INSTANCE) [public static final var INSTANCE: Obj]
|
||||
UMethod (name = Obj) [private fun Obj() = UastEmptyExpression]
|
||||
|
||||
+5
@@ -2,16 +2,21 @@ UFile (package = ) [public abstract annotation Annotation {...]
|
||||
UClass (name = Annotation) [public abstract annotation Annotation {...}]
|
||||
UMethod (name = strings) [public abstract fun strings() : java.lang.String[] = UastEmptyExpression]
|
||||
UClass (name = A) [public final class A {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = A) [public fun A() = UastEmptyExpression]
|
||||
UClass (name = AnnotationInner) [public abstract annotation AnnotationInner {...}]
|
||||
UMethod (name = value) [public abstract fun value() : Annotation = UastEmptyExpression]
|
||||
UClass (name = B1) [public final class B1 {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = B1) [public fun B1() = UastEmptyExpression]
|
||||
UClass (name = B2) [public final class B2 {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = B2) [public fun B2() = UastEmptyExpression]
|
||||
UClass (name = AnnotationArray) [public abstract annotation AnnotationArray {...}]
|
||||
UMethod (name = value) [public abstract fun value() : Annotation[] = UastEmptyExpression]
|
||||
UClass (name = C) [public final class C {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = C) [public fun C() = UastEmptyExpression]
|
||||
UClass (name = C2) [public final class C2 {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = C2) [public fun C2() = UastEmptyExpression]
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
UFile (package = ) [public final class A {...]
|
||||
UClass (name = A) [public final class A {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = A) [public fun A() = UastEmptyExpression]
|
||||
UClass (name = MyAnnotation) [public abstract annotation MyAnnotation {...}]
|
||||
UMethod (name = text) [public abstract fun text() : java.lang.String = UastEmptyExpression]
|
||||
UClass (name = B) [public final class B {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UField (name = Companion) [public static final var Companion: B.Companion]
|
||||
UMethod (name = B) [public fun B() = UastEmptyExpression]
|
||||
UClass (name = InB) [public static final class InB {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = InB) [public fun InB() = UastEmptyExpression]
|
||||
UClass (name = Companion) [public static final class Companion {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UMethod (name = Companion) [private fun Companion() = UastEmptyExpression]
|
||||
UClass (name = Obj) [public final class Obj {...}]
|
||||
UAnnotation (fqName = not-implemented-annotation) [@not-implemented-annotation]
|
||||
UField (name = INSTANCE) [public static final var INSTANCE: Obj]
|
||||
UMethod (name = Obj) [private fun Obj() = UastEmptyExpression]
|
||||
|
||||
@@ -19,103 +19,21 @@ 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.addIfNotNull
|
||||
import org.jetbrains.uast.*
|
||||
|
||||
open class KotlinUClass(
|
||||
class KotlinUClass(
|
||||
psi: KtLightClass,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
|
||||
final override val ktClass = psi.kotlinOrigin
|
||||
|
||||
override val javaPsi: KtLightClass = psi
|
||||
|
||||
override val sourcePsi: KtClassOrObject? = ktClass
|
||||
|
||||
override val psi = unwrap<UClass, PsiClass>(psi)
|
||||
|
||||
override fun getSourceElement() = sourcePsi ?: this
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, ktClass)
|
||||
|
||||
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
override val uastAnchor by lazy { getIdentifierSourcePsi()?.let { KotlinUIdentifier(nameIdentifier, it, this) } }
|
||||
|
||||
private fun getIdentifierSourcePsi(): PsiElement? {
|
||||
ktClass?.nameIdentifier?.let { return it }
|
||||
(ktClass as? KtObjectDeclaration)?.getObjectKeyword()?.let { return it }
|
||||
return null
|
||||
) : BaseKotlinUClass(psi, givenParent) {
|
||||
override fun buildPrimaryConstructorUMethod(ktClass: KtClassOrObject?, psi: KtLightMethod, givenParent: UElement?): UMethod {
|
||||
return KotlinConstructorUMethod(ktClass, psi, givenParent)
|
||||
}
|
||||
|
||||
override fun getInnerClasses(): Array<UClass> {
|
||||
// filter DefaultImpls to avoid processing same methods from original interface multiple times
|
||||
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
|
||||
return psi.innerClasses.filter {
|
||||
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass
|
||||
}.mapNotNull {
|
||||
languagePlugin?.convertOpt<UClass>(it, this)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
override fun getSuperClass(): UClass? = super.getSuperClass()
|
||||
override fun getFields(): Array<UField> = super.getFields()
|
||||
override fun getInitializers(): Array<UClassInitializer> = super.getInitializers()
|
||||
|
||||
override fun getMethods(): Array<UMethod> {
|
||||
val hasPrimaryConstructor = ktClass?.hasPrimaryConstructor() ?: false
|
||||
var secondaryConstructorsCount = 0
|
||||
|
||||
fun createUMethod(psiMethod: PsiMethod): UMethod {
|
||||
return if (psiMethod is KtLightMethod &&
|
||||
psiMethod.isConstructor) {
|
||||
if (!hasPrimaryConstructor && secondaryConstructorsCount++ == 0)
|
||||
KotlinSecondaryConstructorWithInitializersUMethod(ktClass, psiMethod, this)
|
||||
else
|
||||
KotlinConstructorUMethod(ktClass, psiMethod, this)
|
||||
} else {
|
||||
languagePlugin?.convertOpt(psiMethod, this) ?: reportConvertFailure(psiMethod)
|
||||
}
|
||||
}
|
||||
|
||||
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
||||
|
||||
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)
|
||||
|
||||
// Ensure we pick the main Kotlin origin, not the auxiliary one
|
||||
val kotlinOrigin = (lightMethod as? KtLightMethod)?.kotlinOrigin ?: uMethod.sourcePsi
|
||||
handledKtDeclarations.addIfNotNull(kotlinOrigin)
|
||||
}
|
||||
|
||||
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) {
|
||||
baseResolveProviderService.baseKotlinConverter.convertDeclaration(it, this, arrayOf(UElement::class.java)) as? UMethod
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
override fun buildSecondaryConstructorUMethod(ktClass: KtClassOrObject?, psi: KtLightMethod, givenParent: UElement?): UMethod {
|
||||
return KotlinSecondaryConstructorWithInitializersUMethod(ktClass, psi, givenParent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
Reference in New Issue
Block a user