From 1749c90083e4130f5dfd588ef29071b191a0b9f2 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Fri, 18 Jun 2021 01:25:13 -0700 Subject: [PATCH] FIR/UAST: commonize base UClass (with bogus annotation abstraction) --- .../kotlin/declarations/BaseKotlinUClass.kt | 111 ++++++++++++++++++ .../uast/kotlin/FirKotlinConverter.kt | 4 +- .../declarations/FirKotlinUAnnotation.kt | 49 ++++++++ .../kotlin/declarations/FirKotlinUClass.kt | 105 +---------------- .../AnnotationComplex.log.fir.txt | 5 + .../ClassAnnotation.log.fir.txt | 5 + .../AnnotationComplex.types.fir.txt | 5 + .../legacyTypes/ClassAnnotation.types.fir.txt | 5 + .../AnnotationComplex.values.fir.txt | 5 + .../ClassAnnotation.values.fir.txt | 5 + .../uast/kotlin/declarations/KotlinUClass.kt | 94 +-------------- 11 files changed, 205 insertions(+), 188 deletions(-) create mode 100644 plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/declarations/BaseKotlinUClass.kt create mode 100644 plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUAnnotation.kt diff --git a/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/declarations/BaseKotlinUClass.kt b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/declarations/BaseKotlinUClass.kt new file mode 100644 index 00000000000..5d3b9f30728 --- /dev/null +++ b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/declarations/BaseKotlinUClass.kt @@ -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(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 { + // 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(it, this) + }.toTypedArray() + } + + override fun getSuperClass(): UClass? = super.getSuperClass() + override fun getFields(): Array = super.getFields() + override fun getInitializers(): Array = super.getInitializers() + + override fun getMethods(): Array { + 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(javaPsi.methods.size) + val handledKtDeclarations = mutableSetOf() + + 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 = 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 +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt index b219e9f4c2b..17c233367c5 100644 --- a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt @@ -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( diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUAnnotation.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUAnnotation.kt new file mode 100644 index 00000000000..002ec399335 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUAnnotation.kt @@ -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 + 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 { + TODO("Not yet implemented") + } +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUClass.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUClass.kt index 635d21a0cda..8776dced8fa 100644 --- a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUClass.kt +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUClass.kt @@ -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(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 { - // 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(it, this) - }.toTypedArray() - } - - override fun getSuperClass(): UClass? { - return super.getSuperClass() - } - - override fun getFields(): Array { - return super.getFields() - } - - override fun getInitializers(): Array { - // TODO: why not just emptyList()? Kotlin class won't have ? - return super.getInitializers() - } - - override fun getMethods(): Array { - 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(javaPsi.methods.size) - val handledKtDeclarations = mutableSetOf() - - 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 = 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 { diff --git a/plugins/uast-kotlin-fir/testData/legacyRenderLog/AnnotationComplex.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacyRenderLog/AnnotationComplex.log.fir.txt index 80984a29ac9..7d79eddcbef 100644 --- a/plugins/uast-kotlin-fir/testData/legacyRenderLog/AnnotationComplex.log.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyRenderLog/AnnotationComplex.log.fir.txt @@ -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) diff --git a/plugins/uast-kotlin-fir/testData/legacyRenderLog/ClassAnnotation.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacyRenderLog/ClassAnnotation.log.fir.txt index e3e7179863c..92da0e23935 100644 --- a/plugins/uast-kotlin-fir/testData/legacyRenderLog/ClassAnnotation.log.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyRenderLog/ClassAnnotation.log.fir.txt @@ -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) diff --git a/plugins/uast-kotlin-fir/testData/legacyTypes/AnnotationComplex.types.fir.txt b/plugins/uast-kotlin-fir/testData/legacyTypes/AnnotationComplex.types.fir.txt index 5a6b97bc5a3..3ae491923ff 100644 --- a/plugins/uast-kotlin-fir/testData/legacyTypes/AnnotationComplex.types.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyTypes/AnnotationComplex.types.fir.txt @@ -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] diff --git a/plugins/uast-kotlin-fir/testData/legacyTypes/ClassAnnotation.types.fir.txt b/plugins/uast-kotlin-fir/testData/legacyTypes/ClassAnnotation.types.fir.txt index 5f116a7ec08..3afd0b924ec 100644 --- a/plugins/uast-kotlin-fir/testData/legacyTypes/ClassAnnotation.types.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyTypes/ClassAnnotation.types.fir.txt @@ -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] diff --git a/plugins/uast-kotlin-fir/testData/legacyValues/AnnotationComplex.values.fir.txt b/plugins/uast-kotlin-fir/testData/legacyValues/AnnotationComplex.values.fir.txt index 5a6b97bc5a3..3ae491923ff 100644 --- a/plugins/uast-kotlin-fir/testData/legacyValues/AnnotationComplex.values.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyValues/AnnotationComplex.values.fir.txt @@ -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] diff --git a/plugins/uast-kotlin-fir/testData/legacyValues/ClassAnnotation.values.fir.txt b/plugins/uast-kotlin-fir/testData/legacyValues/ClassAnnotation.values.fir.txt index 5f116a7ec08..3afd0b924ec 100644 --- a/plugins/uast-kotlin-fir/testData/legacyValues/ClassAnnotation.values.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyValues/ClassAnnotation.values.fir.txt @@ -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] diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt index 368043b6495..5ed1ee7caf9 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt @@ -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(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 { - // 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(it, this) - }.toTypedArray() - } - - override fun getSuperClass(): UClass? = super.getSuperClass() - override fun getFields(): Array = super.getFields() - override fun getInitializers(): Array = super.getInitializers() - - override fun getMethods(): Array { - 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(javaPsi.methods.size) - val handledKtDeclarations = mutableSetOf() - - 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 = 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 {