diff --git a/build.gradle.kts b/build.gradle.kts index 724f102aef0..8560b4ddc71 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -336,7 +336,9 @@ extra["tasksWithWarnings"] = listOf( ":kotlin-stdlib-jdk7:compileTestKotlin", ":kotlin-stdlib-jdk8:compileTestKotlin", ":plugins:uast-kotlin:compileKotlin", - ":plugins:uast-kotlin:compileTestKotlin" + ":plugins:uast-kotlin:compileTestKotlin", + ":plugins:uast-kotlin-fir:compileKotlin", + ":plugins:uast-kotlin-fir:compileTestKotlin" ) val tasksWithWarnings: List by extra @@ -847,11 +849,11 @@ tasks { ":idea:idea-fir:test", ":idea:idea-frontend-api:test", ":idea:idea-frontend-fir:test", - ":idea:idea-frontend-fir:idea-fir-low-level-api:test" + ":idea:idea-frontend-fir:idea-fir-low-level-api:test", + ":plugins:uast-kotlin-fir:test" ) } - register("android-ide-tests") { dependsOn("dist") dependsOn( @@ -897,7 +899,6 @@ tasks { } } - register("kaptIdeTest") { dependsOn(":kotlin-annotation-processing:test") dependsOn(":kotlin-annotation-processing-base:test") diff --git a/generators/build.gradle.kts b/generators/build.gradle.kts index d25a8369aed..6d0e8dfcf06 100644 --- a/generators/build.gradle.kts +++ b/generators/build.gradle.kts @@ -73,6 +73,8 @@ dependencies { testCompile(projectTests(":kotlinx-serialization-compiler-plugin")) testCompile(projectTests(":kotlinx-serialization-ide-plugin")) testCompile(projectTests(":plugins:fir:fir-plugin-prototype")) + testCompile(projectTests(":plugins:uast-kotlin")) + testCompile(projectTests(":plugins:uast-kotlin-fir")) testCompile(projectTests(":idea:jvm-debugger:jvm-debugger-test")) testCompile(projectTests(":generators:test-generator")) testCompile(projectTests(":idea")) diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 3e2742cb22a..9e6ce66fe37 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -200,6 +200,8 @@ import org.jetbrains.kotlinx.serialization.AbstractSerializationPluginBytecodeLi import org.jetbrains.kotlinx.serialization.AbstractSerializationPluginDiagnosticTest import org.jetbrains.kotlinx.serialization.idea.AbstractSerializationPluginIdeDiagnosticTest import org.jetbrains.kotlinx.serialization.idea.AbstractSerializationQuickFixTest +import org.jetbrains.uast.test.kotlin.AbstractFE1UastDeclarationTest +import org.jetbrains.uast.test.kotlin.AbstractFirUastDeclarationTest fun main(args: Array) { System.setProperty("java.awt.headless", "true") @@ -1842,6 +1844,20 @@ fun main(args: Array) { } } + testGroup("plugins/uast-kotlin-fir/tests", "plugins/uast-kotlin-fir/testData") { + testClass { + model("declaration") + model("legacy") + } + } + + testGroup("plugins/uast-kotlin-fir/tests", "plugins/uast-kotlin-fir/testData") { + testClass { + model("declaration") + model("legacy") + } + } + testGroup("idea/performanceTests/test", "idea/testData") { testClass { model("copyPaste/conversion", testMethod = "doPerfTest", pattern = """^([^\.]+)\.java$""") diff --git a/idea/idea-fir/build.gradle.kts b/idea/idea-fir/build.gradle.kts index 0f72eeaf168..0baa196ebfc 100644 --- a/idea/idea-fir/build.gradle.kts +++ b/idea/idea-fir/build.gradle.kts @@ -4,6 +4,7 @@ plugins { } dependencies { + compile(project(":plugins:uast-kotlin-fir")) compile(project(":idea:idea-frontend-fir")) compile(project(":idea:formatter")) compile(intellijDep()) diff --git a/idea/resources-fir/META-INF/plugin.xml b/idea/resources-fir/META-INF/plugin.xml index 2bda280069c..ff90187d1d0 100644 --- a/idea/resources-fir/META-INF/plugin.xml +++ b/idea/resources-fir/META-INF/plugin.xml @@ -127,6 +127,9 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu + + - \ No newline at end of file + diff --git a/plugins/uast-kotlin-fir/build.gradle.kts b/plugins/uast-kotlin-fir/build.gradle.kts new file mode 100644 index 00000000000..2fd5691bff7 --- /dev/null +++ b/plugins/uast-kotlin-fir/build.gradle.kts @@ -0,0 +1,45 @@ +plugins { + kotlin("jvm") + id("jps-compatible") +} + +dependencies { + implementation(kotlinStdlib()) + implementation(project(":compiler:psi")) + implementation(project(":compiler:light-classes")) + + // BEWARE: Uast should not depend on IDEA. + compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", rootProject = rootProject) } + compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") } + + implementation(project(":idea:idea-frontend-independent")) + implementation(project(":idea:idea-frontend-api")) + implementation(project(":idea:idea-frontend-fir")) + + testImplementation(toolsJar()) + testImplementation(commonDep("junit:junit")) + testCompileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") } + testImplementation(projectTests(":compiler:tests-common")) + testImplementation(projectTests(":idea:idea-test-framework")) + testImplementation(projectTests(":idea")) + testImplementation(projectTests(":idea:idea-fir")) + // To compare various aspects (e.g., render, log, type, value, etc.) against legacy UAST Kotlin + testImplementation(projectTests(":plugins:uast-kotlin")) +} + +sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } +} + +projectTest(parallel = true) { + workingDir = rootDir + val useFirIdeaPlugin = kotlinBuildProperties.useFirIdeaPlugin + doFirst { + if (!useFirIdeaPlugin) { + error("Test task in the module should be executed with -Pidea.fir.plugin=true") + } + } +} + +testsJar () diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinAbstractUElement.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinAbstractUElement.kt new file mode 100644 index 00000000000..083a3583760 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinAbstractUElement.kt @@ -0,0 +1,47 @@ +/* + * 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.PsiElement +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.kotlin.internal.FirKotlinUElementWithComments + +abstract class FirKotlinAbstractUElement( + private val givenParent: UElement? +) : FirKotlinUElementWithComments { + + final override val uastParent: UElement? by lz { + givenParent ?: convertParent() + } + + protected open fun convertParent(): UElement? { + TODO("Not yet implemented") + } + + override fun equals(other: Any?): Boolean { + if (other !is UElement) { + return false + } + + return this.sourcePsi == other.sourcePsi + } + + override fun hashCode(): Int { + return sourcePsi?.hashCode() ?: 0 + } +} + +abstract class FirKotlinAbstractUExpression( + givenParent: UElement? +) : FirKotlinAbstractUElement(givenParent), UExpression { + override val javaPsi: PsiElement? = null + + override val psi: PsiElement? + get() = sourcePsi + + // TODO: annotations +} 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 new file mode 100644 index 00000000000..ca8916dab9c --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt @@ -0,0 +1,237 @@ +/* + * 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.PsiElement +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.asJava.toPsiParameters +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.uast.* + +internal object FirKotlinConverter { + internal fun convertDeclarationOrElement( + element: PsiElement, + givenParent: UElement?, + requiredTypes: Array> + ): UElement? { + if (element is UElement) return element + + // TODO: cache inside PsiElement? + + return convertDeclaration(element, givenParent, requiredTypes) + ?: convertPsiElement(element, givenParent, requiredTypes) + } + + internal fun convertDeclaration( + element: PsiElement, + givenParent: UElement?, + requiredTypes: Array> + ): UElement? { + val original = element.originalElement + + fun

build(ctor: (P, UElement?) -> UElement): () -> UElement? = { + @Suppress("UNCHECKED_CAST") + ctor(original as P, givenParent) + } + + fun

buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? = { + @Suppress("UNCHECKED_CAST") + ctor(original as P, ktElement, givenParent) + } + + fun

buildKtOpt(ktElement: K?, ctor: (P, K?, UElement?) -> UElement): () -> UElement? = { + @Suppress("UNCHECKED_CAST") + ctor(original as P, ktElement, givenParent) + } + + return with(requiredTypes) { + when (original) { + is KtFile -> { + convertKtFile(original, givenParent, requiredTypes).firstOrNull() + } + + is KtLightClass -> { + // TODO: differentiate enum entry + el { AbstractFirKotlinUClass.create(original, givenParent) } + } + is KtClassOrObject -> { + convertClassOrObject(original, givenParent, requiredTypes).firstOrNull() + } + // TODO: KtEnumEntry + + is KtLightField -> { + // TODO: differentiate enum constant + el(buildKtOpt(original.kotlinOrigin, ::FirKotlinUField)) + } + is KtLightParameter -> { + el(buildKtOpt(original.kotlinOrigin, ::FirKotlinUParameter)) + } + is KtParameter -> { + convertParameter(original, givenParent, requiredTypes).firstOrNull() + } + is KtProperty -> { + // TODO: differentiate local + convertNonLocalProperty(original, givenParent, requiredTypes).firstOrNull() + } + is KtPropertyAccessor -> { + el { FirKotlinUMethod.create(original, givenParent) } + } + + is KtLightMethod -> { + // .Companion is needed because of KT-13934 + el(build(FirKotlinUMethod.Companion::create)) + } + is KtFunction -> { + // TODO: differentiate local + el { FirKotlinUMethod.create(original, givenParent) } + } + + // TODO: KtAnnotationEntry + // TODO: KtCallExpression (for nested annotation) + + else -> null + } + } + } + + internal fun convertKtFile( + element: KtFile, + givenParent: UElement?, + requiredTypes: Array> + ): Sequence { + return requiredTypes.accommodate( + // File + alternative { FirKotlinUFile(element) }, + // TODO: Facade + // alternative { element.findFacadeClass()?.let { AbstractFirKotlinUClass.create(it, givenParent) } } + ) + } + + internal fun convertClassOrObject( + element: KtClassOrObject, + givenParent: UElement?, + requiredTypes: Array> + ): Sequence { + val ktLightClass = element.toLightClass() ?: return emptySequence() + val uClass = AbstractFirKotlinUClass.create(ktLightClass, givenParent) + return requiredTypes.accommodate( + // Class + alternative { uClass }, + // Object + alternative primaryConstructor@{ + val primaryConstructor = element.primaryConstructor ?: return@primaryConstructor null + uClass.methods.asSequence() + .filter { it.sourcePsi == primaryConstructor } + .firstOrNull() + } + ) + } + + private fun convertToPropertyAlternatives( + methods: LightClassUtil.PropertyAccessorsPsiMethods?, + givenParent: UElement? + ): Array> = + if (methods != null) + arrayOf( + alternative { methods.backingField?.let { FirKotlinUField(it, getKotlinMemberOrigin(it), 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() + + internal fun convertNonLocalProperty( + property: KtProperty, + givenParent: UElement?, + requiredTypes: Array> + ): Sequence = + requiredTypes.accommodate(*convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(property), givenParent)) + + internal fun convertParameter( + element: KtParameter, + givenParent: UElement?, + requiredTypes: Array> + ): Sequence = + requiredTypes.accommodate( + alternative uParam@{ + val lightParameter = element.toPsiParameters().find { it.name == element.name } ?: return@uParam null + FirKotlinUParameter(lightParameter, element, givenParent) + }, + alternative catch@{ + val uCatchClause = element.parent?.parent?.safeAs()?.toUElementOfType() ?: return@catch null + uCatchClause.parameters.firstOrNull { it.sourcePsi == element} + }, + *convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(element), givenParent) + ) + + internal fun convertPsiElement( + element: PsiElement, + givenParent: UElement?, + requiredTypes: Array> + ): UElement? { + fun

build(ctor: (P, UElement?) -> UElement): () -> UElement? = { + @Suppress("UNCHECKED_CAST") + ctor(element as P, givenParent) + } + + return with(requiredTypes) { + when (element) { + is KtExpression -> { + convertExpression(element, givenParent, requiredTypes) + } + is KtImportDirective -> { + el(build(::FirKotlinUImportStatement)) + } + else -> null + } + } + } + + internal fun convertExpression( + expression: KtExpression, + givenParent: UElement?, + requiredTypes: Array> + ): UExpression? { + + fun

build(ctor: (P, UElement?) -> UExpression): () -> UExpression? { + return { + @Suppress("UNCHECKED_CAST") + ctor(expression as P, givenParent) + } + } + + return with(requiredTypes) { + when (expression) { + else -> expr(build(::FirUnknownKotlinExpression)) + } + } + } +} + +private inline fun Array>.el(f: () -> UElement?): UElement? { + return if (isAssignableFrom(ActualT::class.java)) f() else null +} + +private inline fun Array>.expr(f: () -> UExpression?): UExpression? { + return if (isAssignableFrom(ActualT::class.java)) f() else null +} + +private fun Array>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) } + +private fun Array>.accommodate(vararg makers: UElementAlternative): Sequence { + val makersSeq = makers.asSequence() + return this.asSequence() + .flatMap { requiredType -> makersSeq.filter { requiredType.isAssignableFrom(it.uType) } } + .distinct() + .mapNotNull { it.make.invoke() } +} + +private inline fun alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make) + +private class UElementAlternative(val uType: Class, val make: () -> U?) diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastLanguagePlugin.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastLanguagePlugin.kt new file mode 100644 index 00000000000..fdae17e2168 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastLanguagePlugin.kt @@ -0,0 +1,97 @@ +/* + * 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.lang.Language +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.uast.DEFAULT_TYPES_LIST +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.UastLanguagePlugin +import org.jetbrains.uast.kotlin.FirKotlinConverter.convertDeclarationOrElement + +interface FirKotlinUastResolveProviderService { + fun isJvmElement(psiElement: PsiElement): Boolean +} + +class FirKotlinUastLanguagePlugin : UastLanguagePlugin { + override val priority: Int = 10 + + override val language: Language + get() = KotlinLanguage.INSTANCE + + override fun isFileSupported(fileName: String): Boolean { + return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false) + } + + private val PsiElement.isJvmElement: Boolean + get() = service.isJvmElement(this) + + override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class?): UElement? { + if (!element.isJvmElement) return null + return convertDeclarationOrElement(element, parent, elementTypes(requiredType)) + } + + override fun convertElementWithParent(element: PsiElement, requiredType: Class?): UElement? { + if (!element.isJvmElement) return null + return convertDeclarationOrElement(element, null, elementTypes(requiredType)) + } + + @Suppress("UNCHECKED_CAST") + override fun convertElementWithParent(element: PsiElement, requiredTypes: Array>): T? { + if (!element.isJvmElement) return null + val nonEmptyRequiredTypes = requiredTypes.nonEmptyOr(DEFAULT_TYPES_LIST) + return convertDeclarationOrElement(element, null, nonEmptyRequiredTypes) as? T + } + + @Suppress("UNCHECKED_CAST") + override fun convertToAlternatives(element: PsiElement, requiredTypes: Array>): Sequence { + if (!element.isJvmElement) return emptySequence() + return when { + element is KtFile -> + FirKotlinConverter.convertKtFile(element, null, requiredTypes) as Sequence + element is KtClassOrObject -> + FirKotlinConverter.convertClassOrObject(element, null, requiredTypes) as Sequence + element is KtProperty && !element.isLocal -> + FirKotlinConverter.convertPsiElement(element, null, requiredTypes) as Sequence + element is KtParameter -> + FirKotlinConverter.convertParameter(element, null, requiredTypes) as Sequence + else -> + sequenceOf(convertElementWithParent(element, requiredTypes.nonEmptyOr(DEFAULT_TYPES_LIST)) as? T).filterNotNull() + } + } + + override fun getConstructorCallExpression( + element: PsiElement, + fqName: String + ): UastLanguagePlugin.ResolvedConstructor? { + TODO("Not yet implemented") + } + + override fun getMethodCallExpression( + element: PsiElement, + containingClassFqName: String?, + methodName: String + ): UastLanguagePlugin.ResolvedMethod? { + TODO("Not yet implemented") + } + + override fun isExpressionValueUsed(element: UExpression): Boolean { + TODO("Not yet implemented") + } +} + +private fun elementTypes(requiredType: Class?) = + requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST + +private fun Array>.nonEmptyOr(default: Array>) = + takeIf { it.isNotEmpty() } ?: default + 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 new file mode 100644 index 00000000000..5ea05f84b95 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUClass.kt @@ -0,0 +1,123 @@ +/* + * 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.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiIdentifier +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtObjectDeclaration +import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.visitor.UastVisitor + +sealed class AbstractFirKotlinUClass( + givenParent: UElement? +) : FirKotlinAbstractUElement(givenParent), UClass, UAnchorOwner { + override val uAnnotations: List + get() { + // TODO: Not yet implemented + return emptyList() + } + + override val uastDeclarations: List by lz { + mutableListOf().apply { + addAll(fields) + addAll(initializers) + addAll(methods) + addAll(innerClasses) + } + } + + abstract val ktClass: KtClassOrObject? + + override val uastSuperTypes: List + get() = ktClass?.superTypeListEntries.orEmpty().mapNotNull { it.typeReference }.map { + FirKotlinUTypeReferenceExpression(it, this) + } + + // TODO: delegateExpressions + + override fun accept(visitor: UastVisitor) { + if (visitor.visitClass(this)) return + // TODO: delegate expressions + uAnnotations.acceptList(visitor) + uastDeclarations.acceptList(visitor) + visitor.afterVisitClass(this) + } + + companion object { + fun create(psi: KtLightClass, givenParent: UElement?): UClass { + return when (psi) { + // TODO: PsiAnonymousClass + // TODO: Script + else -> + FirKotlinUClass(psi, givenParent) + } + } + } +} + +class FirKotlinUClass( + override val javaPsi: KtLightClass, + givenParent: UElement?, +) : AbstractFirKotlinUClass(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 = FirUastLightIdentifier(psi, ktClass) + + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) + + override val uastAnchor: UIdentifier? by lz { + getIdentifierSourcePsi()?.let { + FirKotlinUIdentifier(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 { + // TODO: Not yet implemented + return super.getInnerClasses() + } + + override fun getSuperClass(): UClass? { + return super.getSuperClass() + } + + override fun getFields(): Array { + // TODO: Not yet implemented + return super.getFields() + } + + override fun getInitializers(): Array { + // TODO: why not just emptyList()? Kotlin class won't have ? + return super.getInitializers() + } + + override fun getMethods(): Array { + // TODO: Not yet implemented + return super.getMethods() + } +} + +// TODO: FirKotlinUAnonymousClass or FirKotlinUAnonymousObject ? + +// TODO: FirKotlinScriptUClass + +// TODO: FirKotlinInvalidUClass diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUFile.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUFile.kt new file mode 100644 index 00000000000..b5e45f17b6f --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUFile.kt @@ -0,0 +1,45 @@ +/* + * 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.PsiElement +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.uast.* + +class FirKotlinUFile( + override val psi: KtFile, + override val languagePlugin: UastLanguagePlugin = firKotlinUastPlugin +) : UFile { + override val javaPsi: PsiElement? = null + + override val sourcePsi: KtFile = psi + + override val uAnnotations: List + get() { + // TODO: Not yet implemented + return emptyList() + } + + override val packageName: String by lz { + sourcePsi.packageFqName.asString() + } + + override val allCommentsInFile: List = comments + + override val imports: List by lz { + sourcePsi.importDirectives.map { FirKotlinUImportStatement(it, this) } + } + + override val classes: List + get() { + // TODO: Script + // TODO: Facade: getOrCreateFirLightFacade() + return sourcePsi.declarations.mapNotNull { (it as? KtClassOrObject)?.toUClass() } + } + + private fun PsiElement.toUClass() = languagePlugin.convertOpt(this, this@FirKotlinUFile) +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUIdentifier.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUIdentifier.kt new file mode 100644 index 00000000000..4013e3d1788 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUIdentifier.kt @@ -0,0 +1,53 @@ +/* + * 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.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiNameIdentifierOwner +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.psi.KtCallElement +import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtTypeReference +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.toUElement + +class FirUastLightIdentifier( + lightOwner: PsiNameIdentifierOwner, + ktDeclaration: KtDeclaration? +) : KtLightIdentifier(lightOwner, ktDeclaration) { + override fun getContainingFile(): PsiFile { + return unwrapFakeFileForLightClass(super.getContainingFile()) + } +} + +class FirKotlinUIdentifier( + override val javaPsi: PsiElement? = null, + override val sourcePsi: PsiElement?, + givenParent: UElement? +) : UIdentifier(sourcePsi, givenParent) { + override val psi: PsiElement? + get() = javaPsi ?: sourcePsi + + override val uastParent: UElement? by lz { + if (givenParent != null) return@lz givenParent + val parent = sourcePsi?.parent ?: return@lz null + getIdentifierParentForCall(parent) ?: parent.toUElement() + } + + private fun getIdentifierParentForCall(parent: PsiElement): UElement? { + val parentParent = parent.parent + if (parentParent is KtCallElement && parentParent.calleeExpression == parent) { // method identifiers in calls + return parentParent.toUElement() + } + if (parentParent is KtTypeReference && parentParent.parent is KtConstructorCalleeExpression ) { + return parentParent.parent.toUElement() + } + return null + } +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUImportStatement.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUImportStatement.kt new file mode 100644 index 00000000000..0402a98ecec --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUImportStatement.kt @@ -0,0 +1,58 @@ +/* + * 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.PsiElement +import org.jetbrains.kotlin.idea.frontend.api.analyse +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtImportDirective +import org.jetbrains.kotlin.psi.KtReferenceExpression +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UImportStatement +import org.jetbrains.uast.USimpleNameReferenceExpression + +class FirKotlinUImportStatement( + override val psi: KtImportDirective, + givenParent: UElement? +): FirKotlinAbstractUElement(givenParent), UImportStatement { + override val javaPsi: PsiElement? = null + + override val sourcePsi: KtImportDirective = psi + + override val isOnDemand: Boolean = sourcePsi.isAllUnder + + private val importRef: FirImportReference? by lz { + sourcePsi.importedReference?.let { + FirImportReference(it, sourcePsi.name ?: sourcePsi.text, this, sourcePsi) + } + } + + override val importReference: UElement? = importRef + + override fun resolve(): PsiElement? = importRef?.resolve() + + private class FirImportReference( + override val psi: KtExpression, + override val identifier: String, + givenParent: UElement?, + private val importDirective: KtImportDirective + ) : FirKotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression { + override val sourcePsi: KtExpression = psi + + override val resolvedName: String = identifier + + override fun asRenderString(): String = importDirective.importedFqName?.asString() ?: sourcePsi.text + + override fun resolve(): PsiElement? { + val reference = sourcePsi.getQualifiedElementSelector() as? KtReferenceExpression ?: return null + analyse(reference) { + return reference.mainReference.resolve() + } + } + } +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUMethod.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUMethod.kt new file mode 100644 index 00000000000..2fcfb66d83e --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUMethod.kt @@ -0,0 +1,158 @@ +/* + * 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.PsiMethod +import com.intellij.psi.PsiNameIdentifierOwner +import com.intellij.psi.PsiParameter +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.uast.* + +open class FirKotlinUMethod( + psi: PsiMethod, + final override val sourcePsi: KtDeclaration?, + givenParent: UElement? +) : FirKotlinAbstractUElement(givenParent), UMethod, UAnchorOwner, PsiMethod by psi { + constructor( + psi: KtLightMethod, + givenParent: UElement? + ) : this(psi, getKotlinMemberOrigin(psi), givenParent) + + override val psi: PsiMethod = unwrap(psi) + + override val javaPsi = psi + + override fun getSourceElement() = sourcePsi + + override val uAnnotations: List + get() { + // TODO: Not yet implemented + return emptyList() + } + + private val receiverTypeReference by lz { + when (sourcePsi) { + is KtCallableDeclaration -> sourcePsi + is KtPropertyAccessor -> sourcePsi.property + else -> null + }?.receiverTypeReference + } + + override val uastParameters: List by lz { + + fun parameterOrigin(psiParameter: PsiParameter?): KtElement? { + return when (psiParameter) { + is KtLightElement<*, *> -> psiParameter.kotlinOrigin + // TODO: UastKotlinPsiParameter? + else -> null + } + } + + val lightParams = psi.parameterList.parameters + val receiverTypeReference = + receiverTypeReference ?: return@lz lightParams.map { FirKotlinUParameter(it, parameterOrigin(it), this) } + val lightReceiver = lightParams.firstOrNull() ?: return@lz emptyList() + val uParameters = SmartList(FirKotlinReceiverUParameter(lightReceiver, receiverTypeReference, this)) + lightParams.drop(1).mapTo(uParameters) { FirKotlinUParameter(it, parameterOrigin(it), this) } + uParameters + } + + override val uastAnchor: UIdentifier? by lz { + val identifierSourcePsi = when (val sourcePsi = sourcePsi) { + is PsiNameIdentifierOwner -> sourcePsi.nameIdentifier + is KtObjectDeclaration -> sourcePsi.getObjectKeyword() + is KtPropertyAccessor -> sourcePsi.namePlaceholder + else -> sourcePsi?.navigationElement + } + FirKotlinUIdentifier(nameIdentifier, identifierSourcePsi, this) + } + + override val uastBody: UExpression? by lz { + val bodyExpression = when (sourcePsi) { + is KtFunction -> sourcePsi.bodyExpression + is KtPropertyAccessor -> sourcePsi.bodyExpression + is KtProperty -> when { + psi is KtLightMethod && psi.isGetter -> sourcePsi.getter?.bodyExpression + psi is KtLightMethod && psi.isSetter -> sourcePsi.setter?.bodyExpression + else -> null + } + else -> null + } ?: return@lz null + + UastFacade.findPlugin(this)?.convertElement(bodyExpression, this) as? UExpression + } + + override val returnTypeReference: UTypeReferenceExpression? by lz { + (sourcePsi as? KtCallableDeclaration)?.typeReference?.let { + FirKotlinUTypeReferenceExpression(it, this) { javaPsi.returnType ?: UastErrorType } + } + } + + companion object { + fun create( + psi: KtLightMethod, + givenParent: UElement? + ): FirKotlinUMethod { + return when (psi) { + is KtConstructor<*> -> + FirKotlinConstructorUMethod(psi.containingClassOrObject, psi, givenParent) + // TODO: FirKotlinUAnnotationMethod + else -> + FirKotlinUMethod(psi, givenParent) + } + } + + fun create( + sourcePsi: KtDeclaration?, + givenParent: UElement? + ): FirKotlinUMethod? { + val javaPsi = when (sourcePsi) { + is KtPropertyAccessor -> + LightClassUtil.getLightClassAccessorMethod(sourcePsi) + is KtFunction -> + LightClassUtil.getLightClassMethod(sourcePsi) + else -> null + } ?: return null + return when (sourcePsi) { + is KtConstructor<*> -> + FirKotlinConstructorUMethod(sourcePsi.containingClassOrObject, javaPsi, sourcePsi, givenParent) + // TODO: FirKotlinUAnnotationMethod + else -> + FirKotlinUMethod(javaPsi, sourcePsi, givenParent) + } + } + } +} + +class FirKotlinConstructorUMethod( + private val ktClass: KtClassOrObject?, + override val psi: PsiMethod, + kotlinOrigin: KtDeclaration?, + givenParent: UElement? +) : FirKotlinUMethod(psi, kotlinOrigin, givenParent) { + constructor( + ktClass: KtClassOrObject?, + psi: KtLightMethod, + givenParent: UElement? + ) : this(ktClass, psi, psi.kotlinOrigin, givenParent) + + override val javaPsi = psi + + val isPrimary: Boolean + get() = sourcePsi is KtPrimaryConstructor || sourcePsi is KtClassOrObject + + override val uastAnchor: UIdentifier? by lz { + FirKotlinUIdentifier( + javaPsi.nameIdentifier, + if (isPrimary) ktClass?.nameIdentifier else (sourcePsi as? KtSecondaryConstructor)?.getConstructorKeyword(), + this + ) + } +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUVariable.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUVariable.kt new file mode 100644 index 00000000000..5ca27792323 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/declarations/FirKotlinUVariable.kt @@ -0,0 +1,150 @@ +/* + * 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.elements.KtLightElement +import org.jetbrains.kotlin.psi.* +import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.visitor.UastVisitor + +sealed class AbstractFirKotlinUVariable( + givenParent: UElement? +) : FirKotlinAbstractUElement(givenParent), PsiVariable, UVariableEx, UAnchorOwner { + override val uAnnotations: List + get() { + // TODO: Not yet implemented + return emptyList() + } + + override fun getNameIdentifier(): PsiIdentifier { + val kotlinOrigin = (sourcePsi as? KtLightElement<*, *>)?.kotlinOrigin + return FirUastLightIdentifier(psi, kotlinOrigin as? KtDeclaration) + } + + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) + + override val uastAnchor: UIdentifier? by lz { + val identifierSourcePsi = when (val sourcePsi = sourcePsi) { + is KtNamedDeclaration -> sourcePsi.nameIdentifier + is KtTypeReference -> sourcePsi.typeElement?.let { + // receiver param in extension function + (it as? KtUserType)?.referenceExpression?.getIdentifier() ?: it + } ?: sourcePsi + is KtNameReferenceExpression -> sourcePsi.getReferencedNameElement() + is KtBinaryExpression, is KtCallExpression -> null // e.g. `foo("Lorem ipsum") ?: foo("dolor sit amet")` + is KtDestructuringDeclaration -> sourcePsi.valOrVarKeyword + is KtLambdaExpression -> sourcePsi.functionLiteral.lBrace + else -> sourcePsi + } ?: return@lz null + FirKotlinUIdentifier(nameIdentifier, identifierSourcePsi, this) + } + + override val typeReference: UTypeReferenceExpression? by lz { + (sourcePsi as? KtCallableDeclaration)?.typeReference?.let { + FirKotlinUTypeReferenceExpression(it, this) { type } + } + } + + private val kotlinOrigin by lz { getKotlinMemberOrigin(psi.originalElement) ?: sourcePsi } + + override val uastInitializer: UExpression? by lz { + val initializerExpression = when (val kotlinOrigin = kotlinOrigin) { + is KtProperty -> + kotlinOrigin.initializer + is KtParameter -> + kotlinOrigin.defaultValue + is KtVariableDeclaration -> + kotlinOrigin.initializer + else -> null + } ?: return@lz null + + UastFacade.findPlugin(this)?.convertElement(initializerExpression, this) as? UExpression + } + + // TODO: delegateExpression +} + +open class FirKotlinUParameter( + psi: PsiParameter, + override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractFirKotlinUVariable(givenParent), UParameterEx, PsiParameter by psi { + override val psi = unwrap(psi) + + override val javaPsi: PsiParameter = this.psi + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } +} + +class FirKotlinReceiverUParameter( + psi: PsiParameter, + private val receiver: KtTypeReference, + givenParent: UElement? +) : FirKotlinUParameter(psi, receiver, givenParent) { + override val uAnnotations: List + get() { + // TODO: Not yet implemented: take annotations on receiver with RECEIVER use site target + return emptyList() + } +} + +class FirKotlinUField( + psi: PsiField, + override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractFirKotlinUVariable(givenParent), UFieldEx, PsiField by psi { + override fun getSourceElement(): PsiElement { + return sourcePsi ?: this + } + + override val psi = unwrap(psi) + + override val javaPsi: PsiField = this.psi + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitField(this)) return + uAnnotations.acceptList(visitor) + uastInitializer?.accept(visitor) + // TODO: delegateExpression + visitor.afterVisitField(this) + } +} + +// TODO: FirKotlinU(Annotated)LocalVariable + +// TODO: FirKotlinUEnumConstant diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/expressions/FirKotlinUTypeReferenceExpression.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/expressions/FirKotlinUTypeReferenceExpression.kt new file mode 100644 index 00000000000..ebd82a844ab --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/expressions/FirKotlinUTypeReferenceExpression.kt @@ -0,0 +1,30 @@ +/* + * 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.PsiType +import org.jetbrains.kotlin.psi.KtTypeReference +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UTypeReferenceExpression +import org.jetbrains.uast.UastErrorType + +class FirKotlinUTypeReferenceExpression( + override val sourcePsi: KtTypeReference, + givenParent: UElement?, + private val typeSupplier: (() -> PsiType)? = null, +) : FirKotlinAbstractUExpression(givenParent), UTypeReferenceExpression { + override val type: PsiType by lz { + typeSupplier?.invoke() ?: sourcePsi.toPsiType(uastParent ?: this) + } +} + +private fun KtTypeReference?.toPsiType( + source: UElement, +): PsiType { + if (this == null) return UastErrorType + // TODO: use type conversions in firLightUtils.kt + return PsiType.NULL +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/expressions/FirUnknownKotlinExpression.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/expressions/FirUnknownKotlinExpression.kt new file mode 100644 index 00000000000..cbb313df44f --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/expressions/FirUnknownKotlinExpression.kt @@ -0,0 +1,18 @@ +/* + * 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 org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.kotlin.FirKotlinAbstractUExpression + +class FirUnknownKotlinExpression( + override val sourcePsi: KtExpression, + givenParent: UElement? +) : FirKotlinAbstractUExpression(givenParent), UExpression { + override fun asLogString() = "[!] FirUnknownKotlinExpression ($sourcePsi)" +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/FirCliKotlinUastResolveProviderService.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/FirCliKotlinUastResolveProviderService.kt new file mode 100644 index 00000000000..36cb0b1b891 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/FirCliKotlinUastResolveProviderService.kt @@ -0,0 +1,14 @@ +/* + * 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.internal + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.kotlin.FirKotlinUastResolveProviderService + +class FirCliKotlinUastResolveProviderService : FirKotlinUastResolveProviderService { + // Currently, UAST CLI is used by Android Lint, i.e., everything is a JVM element. + override fun isJvmElement(psiElement: PsiElement): Boolean = true +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/FirKotlinUElementWithComments.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/FirKotlinUElementWithComments.kt new file mode 100644 index 00000000000..e5e2a2afcbf --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/FirKotlinUElementWithComments.kt @@ -0,0 +1,39 @@ +/* + * 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.internal + +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.psi.KtValueArgument +import org.jetbrains.uast.UComment +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression + +interface FirKotlinUElementWithComments : UElement { + override val comments: List + get() { + val psi = sourcePsi ?: return emptyList() + val childrenComments = psi.children.filterIsInstance().map { UComment(it, this) } + if (this !is UExpression) return childrenComments + val childrenAndSiblingComments = childrenComments + + psi.nearestCommentSibling(forward = true)?.let { listOf(UComment(it, this)) }.orEmpty() + + psi.nearestCommentSibling(forward = false)?.let { listOf(UComment(it, this)) }.orEmpty() + val parent = psi.parent as? KtValueArgument ?: return childrenAndSiblingComments + + return childrenAndSiblingComments + + parent.nearestCommentSibling(forward = true)?.let { listOf(UComment(it, this)) }.orEmpty() + + parent.nearestCommentSibling(forward = false)?.let { listOf(UComment(it, this)) }.orEmpty() + } + + private fun PsiElement.nearestCommentSibling(forward: Boolean): PsiComment? { + var sibling = if (forward) nextSibling else prevSibling + while (sibling is PsiWhiteSpace && !sibling.text.contains('\n')) { + sibling = if (forward) sibling.nextSibling else sibling.prevSibling + } + return sibling as? PsiComment + } +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt new file mode 100644 index 00000000000..7be11ee4cb1 --- /dev/null +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/internal/firKotlinInternalUastUtils.kt @@ -0,0 +1,45 @@ +/* + * 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.openapi.components.ServiceManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.asJava.elements.KtLightMember +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.uast.UDeclaration +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UastLanguagePlugin + +internal fun lz(initializer: () -> T) = + lazy(LazyThreadSafetyMode.SYNCHRONIZED, initializer) + +internal inline fun unwrap(element: P): P { + val unwrapped = if (element is T) element.javaPsi else element + assert(unwrapped !is UElement) + return unwrapped as P +} + +internal fun unwrapFakeFileForLightClass(file: PsiFile): PsiFile = (file as? FakeFileForLightClass)?.ktFile ?: file + +val firKotlinUastPlugin: UastLanguagePlugin by lz { + UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } + ?: FirKotlinUastLanguagePlugin() +} + +internal val PsiElement.service: FirKotlinUastResolveProviderService + get() { + return ServiceManager.getService(project, FirKotlinUastResolveProviderService::class.java) + } + +internal fun getKotlinMemberOrigin(element: PsiElement?): KtDeclaration? { + (element as? KtLightMember<*>)?.lightMemberOrigin?.auxiliaryOriginalElement?.let { return it } + (element as? KtLightElement<*, *>)?.kotlinOrigin?.let { return it as? KtDeclaration } + return null +} diff --git a/plugins/uast-kotlin-fir/testData/declaration/facade.kt b/plugins/uast-kotlin-fir/testData/declaration/facade.kt new file mode 100644 index 00000000000..51b821e8c08 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/facade.kt @@ -0,0 +1,10 @@ +@file:JvmName("Utils") +@file:JvmMultifileClass + +package declaration + +fun foo(): Int = 42 + +fun String.buzz(): String { + return "$this... zzz..." +} diff --git a/plugins/uast-kotlin-fir/testData/declaration/facade.log.fe10.txt b/plugins/uast-kotlin-fir/testData/declaration/facade.log.fe10.txt new file mode 100644 index 00000000000..6fae02834b0 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/facade.log.fe10.txt @@ -0,0 +1,18 @@ +UFile (package = declaration) + UAnnotation (fqName = kotlin.jvm.JvmName) + UNamedExpression (name = name) + ULiteralExpression (value = "Utils") + UAnnotation (fqName = kotlin.jvm.JvmMultifileClass) + UClass (name = Utils) + UMethod (name = foo) + UBlockExpression + UReturnExpression + ULiteralExpression (value = 42) + UMethod (name = buzz) + UParameter (name = $this$buzz) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UReturnExpression + UPolyadicExpression (operator = +) + UThisExpression (label = null) + ULiteralExpression (value = "... zzz...") diff --git a/plugins/uast-kotlin-fir/testData/declaration/facade.log.fir.txt b/plugins/uast-kotlin-fir/testData/declaration/facade.log.fir.txt new file mode 100644 index 00000000000..dfddf529b8b --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/facade.log.fir.txt @@ -0,0 +1 @@ +UFile (package = declaration) diff --git a/plugins/uast-kotlin-fir/testData/declaration/facade.render.fe10.txt b/plugins/uast-kotlin-fir/testData/declaration/facade.render.fe10.txt new file mode 100644 index 00000000000..75f7f723894 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/facade.render.fe10.txt @@ -0,0 +1,12 @@ +@kotlin.jvm.JvmName(name = "Utils") +@kotlin.jvm.JvmMultifileClass +package declaration + +public final class Utils { + public static final fun foo() : int { + return 42 + } + public static final fun buzz(@org.jetbrains.annotations.NotNull $this$buzz: java.lang.String) : java.lang.String { + return this + "... zzz..." + } +} diff --git a/plugins/uast-kotlin-fir/testData/declaration/facade.render.fir.txt b/plugins/uast-kotlin-fir/testData/declaration/facade.render.fir.txt new file mode 100644 index 00000000000..a9dea72c41a --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/facade.render.fir.txt @@ -0,0 +1,2 @@ +package declaration + diff --git a/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.kt b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.kt new file mode 100644 index 00000000000..6adf5100d35 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.kt @@ -0,0 +1,4 @@ +package declaration + +import java.lang.Thread.* +import java.util.* diff --git a/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.log.fe10.txt b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.log.fe10.txt new file mode 100644 index 00000000000..943ca2fb42d --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.log.fe10.txt @@ -0,0 +1,3 @@ +UFile (package = declaration) + UImportStatement (isOnDemand = true) + UImportStatement (isOnDemand = true) diff --git a/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.log.fir.txt b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.log.fir.txt new file mode 100644 index 00000000000..943ca2fb42d --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.log.fir.txt @@ -0,0 +1,3 @@ +UFile (package = declaration) + UImportStatement (isOnDemand = true) + UImportStatement (isOnDemand = true) diff --git a/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.render.fe10.txt b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.render.fe10.txt new file mode 100644 index 00000000000..657a89721a8 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.render.fe10.txt @@ -0,0 +1,4 @@ +package declaration + +import java.lang.Thread +import java.util diff --git a/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.render.fir.txt b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.render.fir.txt new file mode 100644 index 00000000000..657a89721a8 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/importOnDemand.render.fir.txt @@ -0,0 +1,4 @@ +package declaration + +import java.lang.Thread +import java.util diff --git a/plugins/uast-kotlin-fir/testData/declaration/objects.kt b/plugins/uast-kotlin-fir/testData/declaration/objects.kt new file mode 100644 index 00000000000..bbdce4a141d --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/objects.kt @@ -0,0 +1,27 @@ +import java.lang.Runnable +import java.lang.Thread + +val topRunnable = object : Runnable { + override fun run() { + println("I'm running") + } +} + +object RunnableManager { + val tasks : MutableList = mutableListOf() + + fun register(runnable : Runnable) { + tasks.add(runnable) + } + + fun runAll() { + for (t : tasks) { + Thread(t).start() + } + } +} + +fun main() { + RunnableManager.register(topRunnable) + RunnableManager.runAll() +} diff --git a/plugins/uast-kotlin-fir/testData/declaration/objects.log.fe10.txt b/plugins/uast-kotlin-fir/testData/declaration/objects.log.fe10.txt new file mode 100644 index 00000000000..0c376f2f6dc --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/objects.log.fe10.txt @@ -0,0 +1,62 @@ +UFile (package = ) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UClass (name = ObjectsKt) + UField (name = topRunnable) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UObjectLiteralExpression + UClass (name = null) + UMethod (name = run) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + ULiteralExpression (value = "I'm running") + UMethod (name = ) + UMethod (name = getTopRunnable) + UMethod (name = main) + UBlockExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = RunnableManager) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (register)) + USimpleNameReferenceExpression (identifier = register, resolvesTo = null) + USimpleNameReferenceExpression (identifier = topRunnable) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = RunnableManager) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (runAll)) + USimpleNameReferenceExpression (identifier = runAll, resolvesTo = null) + UClass (name = RunnableManager) + UField (name = tasks) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (mutableListOf)) + USimpleNameReferenceExpression (identifier = mutableListOf, resolvesTo = null) + UField (name = INSTANCE) + UAnnotation (fqName = null) + UMethod (name = getTasks) + UMethod (name = register) + UParameter (name = runnable) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = tasks) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (add)) + USimpleNameReferenceExpression (identifier = add, resolvesTo = null) + USimpleNameReferenceExpression (identifier = runnable) + UMethod (name = runAll) + UBlockExpression + UForEachExpression + UastEmptyExpression + UBlockExpression + UQualifiedReferenceExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (Thread)) + USimpleNameReferenceExpression (identifier = , resolvesTo = null) + USimpleNameReferenceExpression (identifier = t) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (start)) + USimpleNameReferenceExpression (identifier = , resolvesTo = null) + UMethod (name = RunnableManager) diff --git a/plugins/uast-kotlin-fir/testData/declaration/objects.log.fir.txt b/plugins/uast-kotlin-fir/testData/declaration/objects.log.fir.txt new file mode 100644 index 00000000000..5f1f32eee49 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/objects.log.fir.txt @@ -0,0 +1,14 @@ +UFile (package = ) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UClass (name = RunnableManager) + UField (name = INSTANCE) + UField (name = tasks) + [!] FirUnknownKotlinExpression (CALL_EXPRESSION) + UMethod (name = RunnableManager) + UMethod (name = getTasks) + UMethod (name = register) + UParameter (name = runnable) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = runAll) + [!] FirUnknownKotlinExpression (BLOCK) diff --git a/plugins/uast-kotlin-fir/testData/declaration/objects.render.fe10.txt b/plugins/uast-kotlin-fir/testData/declaration/objects.render.fe10.txt new file mode 100644 index 00000000000..ca5321f4b64 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/objects.render.fe10.txt @@ -0,0 +1,30 @@ +import java.lang.Runnable +import java.lang.Thread + +public final class ObjectsKt { + @org.jetbrains.annotations.NotNull private static final var topRunnable: java.lang.Runnable = anonymous object : Runnable { + override fun run() { + println("I'm running") + } + } + public static final fun getTopRunnable() : java.lang.Runnable = UastEmptyExpression + public static final fun main() : void { + RunnableManager.register(topRunnable) + RunnableManager.runAll() + } +} + +public final class RunnableManager { + @org.jetbrains.annotations.NotNull private static final var tasks: java.util.List = mutableListOf() + @null public static final var INSTANCE: RunnableManager + public final fun getTasks() : java.util.List = UastEmptyExpression + public final fun register(@org.jetbrains.annotations.NotNull runnable: java.lang.Runnable) : void { + tasks.add(runnable) + } + public final fun runAll() : void { + for (t : UastEmptyExpression) { + (t).() + } + } + private fun RunnableManager() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin-fir/testData/declaration/objects.render.fir.txt b/plugins/uast-kotlin-fir/testData/declaration/objects.render.fir.txt new file mode 100644 index 00000000000..874a7533c12 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/declaration/objects.render.fir.txt @@ -0,0 +1,11 @@ +import java.lang.Runnable +import java.lang.Thread + +public final class RunnableManager { + public static final var INSTANCE: RunnableManager + private final var tasks: java.util.List = [!] FirUnknownKotlinExpression (CALL_EXPRESSION) + private fun RunnableManager() = UastEmptyExpression + public final fun getTasks() : java.util.List = UastEmptyExpression + public final fun register(runnable: java.lang.Runnable) : void = [!] FirUnknownKotlinExpression (BLOCK) + public final fun runAll() : void = [!] FirUnknownKotlinExpression (BLOCK) +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Constructors.kt b/plugins/uast-kotlin-fir/testData/legacy/Constructors.kt new file mode 100644 index 00000000000..728ba7aee4c --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Constructors.kt @@ -0,0 +1,81 @@ +class A(val str: String) { + + constructor(i: Int) : this(i.toString()) + +} + +class AWithInit(val str: String) { + + init { + println() + } + + constructor(i: Int) : this(i.toString()) + +} + +class AWith2Init(val str: String) { + + init { + println(1) + } + + init { + println(2) + } + + constructor(i: Int) : this(i.toString()) + +} + +class AOnlyInit { + + init { + println(1) + } + + init { + println(2) + } +} + +class AWithSecondary { + + lateinit var a: String + + constructor(i: Int) { + a = i.toString() + } + + constructor(s: String) { + a = s + } + +} + +class AWithSecondaryInit { + + lateinit var a: String + + init { + println() + } + + constructor(i: Int) { + a = i.toString() + } + + constructor(s: String) { + a = s + var local: String = s + local.toString() + } + +} + +class AWithFieldInit(i: Int) { + val a: String + init { + a = i.toString() + } +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Constructors.log.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/Constructors.log.fe10.txt new file mode 100644 index 00000000000..84fc9fc8821 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Constructors.log.fe10.txt @@ -0,0 +1,177 @@ +UFile (package = ) + UClass (name = A) + UField (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getStr) + UMethod (name = A) + UParameter (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = A) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (this)) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: A) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UClass (name = AWithInit) + UField (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getStr) + UMethod (name = AWithInit) + UParameter (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + UMethod (name = AWithInit) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (this)) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: AWithInit) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UClass (name = AWith2Init) + UField (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getStr) + UMethod (name = AWith2Init) + UParameter (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + ULiteralExpression (value = 1) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + ULiteralExpression (value = 2) + UMethod (name = AWith2Init) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (this)) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: AWith2Init) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UClass (name = AOnlyInit) + UMethod (name = AOnlyInit) + UBlockExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + ULiteralExpression (value = 1) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + ULiteralExpression (value = 2) + UClass (name = AWithSecondary) + UField (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getA) + UMethod (name = setA) + UParameter (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = AWithSecondary) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: Object) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UMethod (name = AWithSecondary) + UParameter (name = s) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: Object) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + USimpleNameReferenceExpression (identifier = s) + UClass (name = AWithSecondaryInit) + UField (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getA) + UMethod (name = setA) + UParameter (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = AWithSecondaryInit) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: Object) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UMethod (name = AWithSecondaryInit) + UParameter (name = s) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = , resolvesTo = PsiClass: Object) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + USimpleNameReferenceExpression (identifier = s) + UDeclarationsExpression + ULocalVariable (name = local) + USimpleNameReferenceExpression (identifier = s) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = local) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UClass (name = AWithFieldInit) + UField (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UMethod (name = getA) + UMethod (name = AWithFieldInit) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UBlockExpression + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) diff --git a/plugins/uast-kotlin-fir/testData/legacy/Constructors.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/Constructors.log.fir.txt new file mode 100644 index 00000000000..e71c4ed944c --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Constructors.log.fir.txt @@ -0,0 +1,51 @@ +UFile (package = ) + UClass (name = A) + UField (name = str) + UMethod (name = A) + UParameter (name = str) + UMethod (name = A) + UParameter (name = i) + UMethod (name = getStr) + UClass (name = AWithInit) + UField (name = str) + UMethod (name = AWithInit) + UParameter (name = str) + UMethod (name = AWithInit) + UParameter (name = i) + UMethod (name = getStr) + UClass (name = AWith2Init) + UField (name = str) + UMethod (name = AWith2Init) + UParameter (name = str) + UMethod (name = AWith2Init) + UParameter (name = i) + UMethod (name = getStr) + UClass (name = AOnlyInit) + UMethod (name = AOnlyInit) + UClass (name = AWithSecondary) + UField (name = a) + UMethod (name = AWithSecondary) + UParameter (name = i) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = AWithSecondary) + UParameter (name = s) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = getA) + UMethod (name = setA) + UParameter (name = value) + UClass (name = AWithSecondaryInit) + UField (name = a) + UMethod (name = AWithSecondaryInit) + UParameter (name = i) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = AWithSecondaryInit) + UParameter (name = s) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = getA) + UMethod (name = setA) + UParameter (name = value) + UClass (name = AWithFieldInit) + UField (name = a) + UMethod (name = AWithFieldInit) + UParameter (name = i) + UMethod (name = getA) diff --git a/plugins/uast-kotlin-fir/testData/legacy/Constructors.render.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/Constructors.render.fe10.txt new file mode 100644 index 00000000000..08fbd4652bc --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Constructors.render.fe10.txt @@ -0,0 +1,91 @@ +public final class A { + @org.jetbrains.annotations.NotNull private final var str: java.lang.String + public final fun getStr() : java.lang.String = UastEmptyExpression + public fun A(@org.jetbrains.annotations.NotNull str: java.lang.String) = UastEmptyExpression + public fun A(@org.jetbrains.annotations.NotNull i: int) { + (i.toString()) + } +} + +public final class AWithInit { + @org.jetbrains.annotations.NotNull private final var str: java.lang.String + public final fun getStr() : java.lang.String = UastEmptyExpression + public fun AWithInit(@org.jetbrains.annotations.NotNull str: java.lang.String) { + { + println() + } + } + public fun AWithInit(@org.jetbrains.annotations.NotNull i: int) { + (i.toString()) + } +} + +public final class AWith2Init { + @org.jetbrains.annotations.NotNull private final var str: java.lang.String + public final fun getStr() : java.lang.String = UastEmptyExpression + public fun AWith2Init(@org.jetbrains.annotations.NotNull str: java.lang.String) { + { + println(1) + } + { + println(2) + } + } + public fun AWith2Init(@org.jetbrains.annotations.NotNull i: int) { + (i.toString()) + } +} + +public final class AOnlyInit { + public fun AOnlyInit() { + { + println(1) + } + { + println(2) + } + } +} + +public final class AWithSecondary { + @org.jetbrains.annotations.NotNull public var a: java.lang.String + public final fun getA() : java.lang.String = UastEmptyExpression + public final fun setA(@org.jetbrains.annotations.NotNull a: java.lang.String) : void = UastEmptyExpression + public fun AWithSecondary(@org.jetbrains.annotations.NotNull i: int) { + () + a = i.toString() + } + public fun AWithSecondary(@org.jetbrains.annotations.NotNull s: java.lang.String) { + () + a = s + } +} + +public final class AWithSecondaryInit { + @org.jetbrains.annotations.NotNull public var a: java.lang.String + public final fun getA() : java.lang.String = UastEmptyExpression + public final fun setA(@org.jetbrains.annotations.NotNull a: java.lang.String) : void = UastEmptyExpression + public fun AWithSecondaryInit(@org.jetbrains.annotations.NotNull i: int) { + () + { + println() + } + a = i.toString() + } + public fun AWithSecondaryInit(@org.jetbrains.annotations.NotNull s: java.lang.String) { + () + a = s + var local: java.lang.String = s + local.toString() + } +} + +public final class AWithFieldInit { + @org.jetbrains.annotations.NotNull private final var a: java.lang.String + public final fun getA() : java.lang.String = UastEmptyExpression + public fun AWithFieldInit(@org.jetbrains.annotations.NotNull i: int) { + { + a = i.toString() + } + } +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Constructors.render.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/Constructors.render.fir.txt new file mode 100644 index 00000000000..94caaed36c7 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Constructors.render.fir.txt @@ -0,0 +1,46 @@ +public final class A { + private final var str: java.lang.String + public fun A(str: java.lang.String) = UastEmptyExpression + public fun A(i: int) = UastEmptyExpression + public final fun getStr() : java.lang.String = UastEmptyExpression +} + +public final class AWithInit { + private final var str: java.lang.String + public fun AWithInit(str: java.lang.String) = UastEmptyExpression + public fun AWithInit(i: int) = UastEmptyExpression + public final fun getStr() : java.lang.String = UastEmptyExpression +} + +public final class AWith2Init { + private final var str: java.lang.String + public fun AWith2Init(str: java.lang.String) = UastEmptyExpression + public fun AWith2Init(i: int) = UastEmptyExpression + public final fun getStr() : java.lang.String = UastEmptyExpression +} + +public final class AOnlyInit { + public fun AOnlyInit() = UastEmptyExpression +} + +public final class AWithSecondary { + private var a: java.lang.String + public fun AWithSecondary(i: int) = [!] FirUnknownKotlinExpression (BLOCK) + public fun AWithSecondary(s: java.lang.String) = [!] FirUnknownKotlinExpression (BLOCK) + public final fun getA() : java.lang.String = UastEmptyExpression + public final fun setA(value: java.lang.String) : void = UastEmptyExpression +} + +public final class AWithSecondaryInit { + private var a: java.lang.String + public fun AWithSecondaryInit(i: int) = [!] FirUnknownKotlinExpression (BLOCK) + public fun AWithSecondaryInit(s: java.lang.String) = [!] FirUnknownKotlinExpression (BLOCK) + public final fun getA() : java.lang.String = UastEmptyExpression + public final fun setA(value: java.lang.String) : void = UastEmptyExpression +} + +public final class AWithFieldInit { + private final var a: java.lang.String + public fun AWithFieldInit(i: int) = UastEmptyExpression + public final fun getA() : java.lang.String = UastEmptyExpression +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Imports.kt b/plugins/uast-kotlin-fir/testData/legacy/Imports.kt new file mode 100644 index 00000000000..2a3a8414ad6 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Imports.kt @@ -0,0 +1,6 @@ +import java.lang.Thread.currentThread +import java.lang.Thread.NORM_PRIORITY +import java.lang.Thread.UncaughtExceptionHandler +import java.lang.Thread.sleep +import kotlin.collections.emptyList +import kotlin.Int.Companion.SIZE_BYTES diff --git a/plugins/uast-kotlin-fir/testData/legacy/Imports.log.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/Imports.log.fe10.txt new file mode 100644 index 00000000000..b560126f9d2 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Imports.log.fe10.txt @@ -0,0 +1,7 @@ +UFile (package = ) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) diff --git a/plugins/uast-kotlin-fir/testData/legacy/Imports.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/Imports.log.fir.txt new file mode 100644 index 00000000000..b560126f9d2 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Imports.log.fir.txt @@ -0,0 +1,7 @@ +UFile (package = ) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) + UImportStatement (isOnDemand = false) diff --git a/plugins/uast-kotlin-fir/testData/legacy/Imports.render.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/Imports.render.fe10.txt new file mode 100644 index 00000000000..2a3a8414ad6 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Imports.render.fe10.txt @@ -0,0 +1,6 @@ +import java.lang.Thread.currentThread +import java.lang.Thread.NORM_PRIORITY +import java.lang.Thread.UncaughtExceptionHandler +import java.lang.Thread.sleep +import kotlin.collections.emptyList +import kotlin.Int.Companion.SIZE_BYTES diff --git a/plugins/uast-kotlin-fir/testData/legacy/Imports.render.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/Imports.render.fir.txt new file mode 100644 index 00000000000..2a3a8414ad6 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Imports.render.fir.txt @@ -0,0 +1,6 @@ +import java.lang.Thread.currentThread +import java.lang.Thread.NORM_PRIORITY +import java.lang.Thread.UncaughtExceptionHandler +import java.lang.Thread.sleep +import kotlin.collections.emptyList +import kotlin.Int.Companion.SIZE_BYTES diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.kt b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.kt new file mode 100644 index 00000000000..7aaae03799f --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.kt @@ -0,0 +1,11 @@ +class PropertyTest { + var stringRepresentation: String + get() = this.toString() + set(value) { + setDataFromString(value) + } + + fun setDataFromString(data: String) { + + } +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.log.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.log.fe10.txt new file mode 100644 index 00000000000..bfd75c247c2 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.log.fe10.txt @@ -0,0 +1,23 @@ +UFile (package = ) + UClass (name = PropertyTest) + UMethod (name = getStringRepresentation) + UBlockExpression + UReturnExpression + UQualifiedReferenceExpression + UThisExpression (label = null) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString, resolvesTo = null) + UMethod (name = setStringRepresentation) + UParameter (name = value) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (setDataFromString)) + USimpleNameReferenceExpression (identifier = setDataFromString, resolvesTo = null) + USimpleNameReferenceExpression (identifier = value) + UMethod (name = setDataFromString) + UParameter (name = data) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UMethod (name = PropertyTest) diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.log.fir.txt new file mode 100644 index 00000000000..c0c6c3b4457 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.log.fir.txt @@ -0,0 +1,11 @@ +UFile (package = ) + UClass (name = PropertyTest) + UMethod (name = PropertyTest) + UMethod (name = getStringRepresentation) + [!] FirUnknownKotlinExpression (DOT_QUALIFIED_EXPRESSION) + UMethod (name = setStringRepresentation) + UParameter (name = value) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = setDataFromString) + UParameter (name = data) + [!] FirUnknownKotlinExpression (BLOCK) diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.render.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.render.fe10.txt new file mode 100644 index 00000000000..c599941927e --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.render.fe10.txt @@ -0,0 +1,11 @@ +public final class PropertyTest { + public final fun getStringRepresentation() : java.lang.String { + return this.toString() + } + public final fun setStringRepresentation(@org.jetbrains.annotations.NotNull value: java.lang.String) : void { + setDataFromString(value) + } + public final fun setDataFromString(@org.jetbrains.annotations.NotNull data: java.lang.String) : void { + } + public fun PropertyTest() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.render.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.render.fir.txt new file mode 100644 index 00000000000..ebc5158419e --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.render.fir.txt @@ -0,0 +1,6 @@ +public final class PropertyTest { + public fun PropertyTest() = UastEmptyExpression + public final fun getStringRepresentation() : java.lang.String = [!] FirUnknownKotlinExpression (DOT_QUALIFIED_EXPRESSION) + public final fun setStringRepresentation(value: java.lang.String) : void = [!] FirUnknownKotlinExpression (BLOCK) + public final fun setDataFromString(data: java.lang.String) : void = [!] FirUnknownKotlinExpression (BLOCK) +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.kt b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.kt new file mode 100644 index 00000000000..96e21a830b9 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.kt @@ -0,0 +1,7 @@ +class TestPropertyInitializer { + var withSetter = "/sdcard" + get() = field + set(p) { + field = p + } +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.log.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.log.fe10.txt new file mode 100644 index 00000000000..0445696ef71 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.log.fe10.txt @@ -0,0 +1,17 @@ +UFile (package = ) + UClass (name = TestPropertyInitializer) + UField (name = withSetter) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + ULiteralExpression (value = "/sdcard") + UMethod (name = getWithSetter) + UBlockExpression + UReturnExpression + USimpleNameReferenceExpression (identifier = field) + UMethod (name = setWithSetter) + UParameter (name = p) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = field) + USimpleNameReferenceExpression (identifier = p) + UMethod (name = TestPropertyInitializer) diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.log.fir.txt new file mode 100644 index 00000000000..60734e768ff --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.log.fir.txt @@ -0,0 +1,8 @@ +UFile (package = ) + UClass (name = TestPropertyInitializer) + UMethod (name = TestPropertyInitializer) + UMethod (name = getWithSetter) + [!] FirUnknownKotlinExpression (REFERENCE_EXPRESSION) + UMethod (name = setWithSetter) + UParameter (name = p) + [!] FirUnknownKotlinExpression (BLOCK) diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.render.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.render.fe10.txt new file mode 100644 index 00000000000..89c24e52cd0 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.render.fe10.txt @@ -0,0 +1,10 @@ +public final class TestPropertyInitializer { + @org.jetbrains.annotations.NotNull private var withSetter: java.lang.String = "/sdcard" + public final fun getWithSetter() : java.lang.String { + return field + } + public final fun setWithSetter(@org.jetbrains.annotations.NotNull p: java.lang.String) : void { + field = p + } + public fun TestPropertyInitializer() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.render.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.render.fir.txt new file mode 100644 index 00000000000..37a85d37529 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.render.fir.txt @@ -0,0 +1,5 @@ +public final class TestPropertyInitializer { + public fun TestPropertyInitializer() = UastEmptyExpression + public final fun getWithSetter() : java.lang.String = [!] FirUnknownKotlinExpression (REFERENCE_EXPRESSION) + public final fun setWithSetter(p: java.lang.String) : void = [!] FirUnknownKotlinExpression (BLOCK) +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Simple.kt b/plugins/uast-kotlin-fir/testData/legacy/Simple.kt new file mode 100644 index 00000000000..2b841034329 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Simple.kt @@ -0,0 +1,7 @@ +class Simple { + fun method() { + println("Hello, world!") + } + + val property: String = "Mary" +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Simple.log.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/Simple.log.fe10.txt new file mode 100644 index 00000000000..f352eb5b902 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Simple.log.fe10.txt @@ -0,0 +1,13 @@ +UFile (package = ) + UClass (name = Simple) + UField (name = property) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + ULiteralExpression (value = "Mary") + UMethod (name = method) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println, resolvesTo = null) + ULiteralExpression (value = "Hello, world!") + UMethod (name = getProperty) + UMethod (name = Simple) diff --git a/plugins/uast-kotlin-fir/testData/legacy/Simple.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/Simple.log.fir.txt new file mode 100644 index 00000000000..0cfeafe8699 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Simple.log.fir.txt @@ -0,0 +1,8 @@ +UFile (package = ) + UClass (name = Simple) + UField (name = property) + [!] FirUnknownKotlinExpression (STRING_TEMPLATE) + UMethod (name = Simple) + UMethod (name = method) + [!] FirUnknownKotlinExpression (BLOCK) + UMethod (name = getProperty) diff --git a/plugins/uast-kotlin-fir/testData/legacy/Simple.render.fe10.txt b/plugins/uast-kotlin-fir/testData/legacy/Simple.render.fe10.txt new file mode 100644 index 00000000000..be960f24542 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Simple.render.fe10.txt @@ -0,0 +1,8 @@ +public final class Simple { + @org.jetbrains.annotations.NotNull private final var property: java.lang.String = "Mary" + public final fun method() : void { + println("Hello, world!") + } + public final fun getProperty() : java.lang.String = UastEmptyExpression + public fun Simple() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin-fir/testData/legacy/Simple.render.fir.txt b/plugins/uast-kotlin-fir/testData/legacy/Simple.render.fir.txt new file mode 100644 index 00000000000..8d6ac7cd117 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/legacy/Simple.render.fir.txt @@ -0,0 +1,6 @@ +public final class Simple { + private final var property: java.lang.String = [!] FirUnknownKotlinExpression (STRING_TEMPLATE) + public fun Simple() = UastEmptyExpression + public final fun method() : void = [!] FirUnknownKotlinExpression (BLOCK) + public final fun getProperty() : java.lang.String = UastEmptyExpression +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/common/kotlin/FirUastPluginSelection.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/common/kotlin/FirUastPluginSelection.kt new file mode 100644 index 00000000000..7a421f6211e --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/common/kotlin/FirUastPluginSelection.kt @@ -0,0 +1,14 @@ +/* + * 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.common.kotlin + +interface FirUastPluginSelection { + // Whether this is FIR UAST plugin or FE 1.0 UAST plugin + val isFirUastPlugin: Boolean + + val pluginSuffix: String + get() = if (isFirUastPlugin) ".fir" else ".fe10" +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/common/kotlin/FirUastRenderLogTestBase.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/common/kotlin/FirUastRenderLogTestBase.kt new file mode 100644 index 00000000000..b2265de1760 --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/common/kotlin/FirUastRenderLogTestBase.kt @@ -0,0 +1,28 @@ +/* + * 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.common.kotlin + +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.uast.UFile +import org.jetbrains.uast.asRecursiveLogString +import java.io.File + +interface FirUastRenderLogTestBase : FirUastPluginSelection { + fun getTestFileFromPath(filePath: String, ext: String): File { + return File(filePath.removeSuffix(".kt") + '.' + ext) + } + + private fun getRenderFile(filePath: String) = getTestFileFromPath(filePath, "render$pluginSuffix.txt") + private fun getLogFile(filePath: String) = getTestFileFromPath(filePath, "log$pluginSuffix.txt") + + fun check(filePath: String, file: UFile) { + val renderFile = getRenderFile(filePath) + val logFile = getLogFile(filePath) + + KotlinTestUtils.assertEqualsToFile(renderFile, file.asRenderString()) + KotlinTestUtils.assertEqualsToFile(logFile, file.asRecursiveLogString()) + } +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/env/kotlin/AbstractFirUastTest.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/env/kotlin/AbstractFirUastTest.kt new file mode 100644 index 00000000000..fc788cd1d92 --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/env/kotlin/AbstractFirUastTest.kt @@ -0,0 +1,69 @@ +/* + * 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.test.env.kotlin + +import com.intellij.core.CoreApplicationEnvironment +import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.registerServiceInstance +import com.intellij.util.io.URLUtil +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.uast.UFile +import org.jetbrains.uast.UastFacade +import org.jetbrains.uast.UastLanguagePlugin +import org.jetbrains.uast.common.kotlin.FirUastPluginSelection +import org.jetbrains.uast.kotlin.FirKotlinUastResolveProviderService +import org.jetbrains.uast.kotlin.firKotlinUastPlugin +import org.jetbrains.uast.kotlin.internal.FirCliKotlinUastResolveProviderService +import java.io.File + +abstract class AbstractFirUastTest : KotlinLightCodeInsightFixtureTestCase(), FirUastPluginSelection { + private fun registerExtensionPointAndServiceIfNeeded() { + if (!isFirPlugin) return + + val area = Extensions.getRootArea() + CoreApplicationEnvironment.registerExtensionPoint( + area, + UastLanguagePlugin.extensionPointName, + UastLanguagePlugin::class.java + ) + area.getExtensionPoint(UastLanguagePlugin.extensionPointName) + .registerExtension(firKotlinUastPlugin, testRootDisposable) + project.registerServiceInstance( + FirKotlinUastResolveProviderService::class.java, + FirCliKotlinUastResolveProviderService() + ) + } + + override fun setUp() { + super.setUp() + registerExtensionPointAndServiceIfNeeded() + } + + override fun isFirPlugin(): Boolean = true + + override fun getProjectDescriptor(): LightProjectDescriptor = + KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK + + private fun getVirtualFile(filepath: String): VirtualFile { + val vfs = VirtualFileManager.getInstance().getFileSystem(URLUtil.FILE_PROTOCOL) + return vfs.findFileByPath(filepath)!! + } + + abstract fun check(filePath: String, file: UFile) + + protected fun doCheck(filePath: String, checkCallback: (String, UFile) -> Unit = { _filePath, file -> check(_filePath, file) }) { + val virtualFile = getVirtualFile(filePath) + + val testName = filePath.substring(filePath.lastIndexOf('/') + 1).removeSuffix(".kt") + val psiFile = myFixture.configureByText(virtualFile.name, File(virtualFile.canonicalPath!!).readText()) + val uFile = UastFacade.convertElementWithParent(psiFile, null) ?: error("Can't get UFile for $testName") + checkCallback(filePath, uFile as UFile) + } +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/AbstractFE1UastDeclarationTest.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/AbstractFE1UastDeclarationTest.kt new file mode 100644 index 00000000000..8aab397da1d --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/AbstractFE1UastDeclarationTest.kt @@ -0,0 +1,30 @@ +/* + * 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.test.kotlin + +import org.jetbrains.uast.UFile +import org.jetbrains.uast.common.kotlin.FirUastRenderLogTestBase +import java.io.File + +abstract class AbstractFE1UastDeclarationTest : AbstractKotlinUastTest(), FirUastRenderLogTestBase { + override val isFirUastPlugin: Boolean = false + + override fun check(filePath: String, file: UFile) { + super.check(filePath, file) + } + + override var testDataDir = File("plugins/uast-kotlin-fir/testData") + + fun doTest(filePath: String) { + testDataDir = File(filePath).parentFile + val testName = filePath.substring(filePath.lastIndexOf('/') + 1).removeSuffix(".kt") + val virtualFile = getVirtualFile(testName) + + val psiFile = psiManager.findFile(virtualFile) ?: error("Can't get psi file for $testName") + val uFile = uastContext.convertElementWithParent(psiFile, null) ?: error("Can't get UFile for $testName") + check(filePath, uFile as UFile) + } +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/AbstractFirUastDeclarationTest.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/AbstractFirUastDeclarationTest.kt new file mode 100644 index 00000000000..66f4e84abc8 --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/AbstractFirUastDeclarationTest.kt @@ -0,0 +1,22 @@ +/* + * 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.test.kotlin + +import org.jetbrains.uast.UFile +import org.jetbrains.uast.common.kotlin.FirUastRenderLogTestBase +import org.jetbrains.uast.test.env.kotlin.AbstractFirUastTest + +abstract class AbstractFirUastDeclarationTest : AbstractFirUastTest(), FirUastRenderLogTestBase { + override val isFirUastPlugin: Boolean = true + + override fun check(filePath: String, file: UFile) { + super.check(filePath, file) + } + + fun doTest(filePath: String) { + doCheck(filePath) + } +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastDeclarationTestGenerated.java b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastDeclarationTestGenerated.java new file mode 100644 index 00000000000..1d47c1c94f0 --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastDeclarationTestGenerated.java @@ -0,0 +1,87 @@ +/* + * 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.test.kotlin; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@RunWith(JUnit3RunnerWithInners.class) +public class FE1UastDeclarationTestGenerated extends AbstractFE1UastDeclarationTest { + @TestMetadata("plugins/uast-kotlin-fir/testData/declaration") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Declaration extends AbstractFE1UastDeclarationTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInDeclaration() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/uast-kotlin-fir/testData/declaration"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("facade.kt") + public void testFacade() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/declaration/facade.kt"); + } + + @TestMetadata("importOnDemand.kt") + public void testImportOnDemand() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/declaration/importOnDemand.kt"); + } + + @TestMetadata("objects.kt") + public void testObjects() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/declaration/objects.kt"); + } + } + + @TestMetadata("plugins/uast-kotlin-fir/testData/legacy") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Legacy extends AbstractFE1UastDeclarationTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInLegacy() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/uast-kotlin-fir/testData/legacy"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("Constructors.kt") + public void testConstructors() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/Constructors.kt"); + } + + @TestMetadata("Imports.kt") + public void testImports() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/Imports.kt"); + } + + @TestMetadata("PropertyAccessors.kt") + public void testPropertyAccessors() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.kt"); + } + + @TestMetadata("PropertyInitializer.kt") + public void testPropertyInitializer() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.kt"); + } + + @TestMetadata("Simple.kt") + public void testSimple() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/Simple.kt"); + } + } +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastDeclarationTestGenerated.java b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastDeclarationTestGenerated.java new file mode 100644 index 00000000000..765717d9afe --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastDeclarationTestGenerated.java @@ -0,0 +1,87 @@ +/* + * 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.test.kotlin; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@RunWith(JUnit3RunnerWithInners.class) +public class FirUastDeclarationTestGenerated extends AbstractFirUastDeclarationTest { + @TestMetadata("plugins/uast-kotlin-fir/testData/declaration") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Declaration extends AbstractFirUastDeclarationTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInDeclaration() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/uast-kotlin-fir/testData/declaration"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("facade.kt") + public void testFacade() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/declaration/facade.kt"); + } + + @TestMetadata("importOnDemand.kt") + public void testImportOnDemand() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/declaration/importOnDemand.kt"); + } + + @TestMetadata("objects.kt") + public void testObjects() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/declaration/objects.kt"); + } + } + + @TestMetadata("plugins/uast-kotlin-fir/testData/legacy") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Legacy extends AbstractFirUastDeclarationTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInLegacy() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/uast-kotlin-fir/testData/legacy"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("Constructors.kt") + public void testConstructors() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/Constructors.kt"); + } + + @TestMetadata("Imports.kt") + public void testImports() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/Imports.kt"); + } + + @TestMetadata("PropertyAccessors.kt") + public void testPropertyAccessors() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/PropertyAccessors.kt"); + } + + @TestMetadata("PropertyInitializer.kt") + public void testPropertyInitializer() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/PropertyInitializer.kt"); + } + + @TestMetadata("Simple.kt") + public void testSimple() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/legacy/Simple.kt"); + } + } +} diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt new file mode 100644 index 00000000000..299a25942dc --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt @@ -0,0 +1,67 @@ +/* + * 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.test.kotlin + +import com.intellij.psi.PsiClass +import com.intellij.testFramework.TestDataPath +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtObjectDeclaration +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners +import org.jetbrains.kotlin.test.TestMetadata +import org.jetbrains.uast.UFile +import org.jetbrains.uast.test.env.kotlin.AbstractFirUastTest +import org.junit.Assert +import org.junit.runner.RunWith +import java.lang.IllegalStateException + +@RunWith(JUnit3RunnerWithInners::class) +class FirUastResolveApiTest : AbstractFirUastTest() { + override val isFirUastPlugin: Boolean = true + + override fun check(filePath: String, file: UFile) { + // Bogus + } + + @TestMetadata("plugins/uast-kotlin-fir/testData/legacy") + @TestDataPath("\$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners::class) + class Legacy : AbstractFirUastTest() { + override val isFirUastPlugin: Boolean = true + + override fun check(filePath: String, file: UFile) { + // Bogus + } + + @TestMetadata("Imports.kt") + fun testImports() { + doCheck("plugins/uast-kotlin-fir/testData/legacy/Imports.kt") { _, uFile -> + uFile.imports.forEach { uImport -> + val resolvedImport = uImport.resolve() + ?: throw IllegalStateException("Unresolved import: ${uImport.asRenderString()}") + val expected = when (resolvedImport) { + is PsiClass -> { + // import java.lang.Thread.* + resolvedImport.name == "Thread" + } + is KtNamedFunction -> { + // import kotlin.collections.emptyList + resolvedImport.isTopLevel && resolvedImport.name == "emptyList" + } + is KtObjectDeclaration -> { + // import kotlin.Int.Companion.SIZE_BYTES + val selector = (uImport.importReference?.sourcePsi as? KtExpression)?.getQualifiedElementSelector() + resolvedImport.isCompanion() && selector?.text == "SIZE_BYTES" + } + else -> false + } + Assert.assertTrue("Unexpected import: $resolvedImport", expected) + } + } + } + } +} diff --git a/plugins/uast-kotlin-idea/build.gradle.kts b/plugins/uast-kotlin-idea/build.gradle.kts index 1308b187d42..58a5bf823f6 100644 --- a/plugins/uast-kotlin-idea/build.gradle.kts +++ b/plugins/uast-kotlin-idea/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { compile(project(":idea:ide-common")) compile(project(":idea:idea-core")) compile(project(":plugins:uast-kotlin")) + compile(project(":plugins:uast-kotlin-fir")) compileOnly(intellijDep()) compileOnly(intellijPluginDep("java")) } diff --git a/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/FirIdeaKotlinUastResolveProviderService.kt b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/FirIdeaKotlinUastResolveProviderService.kt new file mode 100644 index 00000000000..8e688d0b913 --- /dev/null +++ b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/FirIdeaKotlinUastResolveProviderService.kt @@ -0,0 +1,13 @@ +/* + * 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.internal + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.kotlin.FirKotlinUastResolveProviderService + +class FirIdeaKotlinUastResolveProviderService : FirKotlinUastResolveProviderService { + override fun isJvmElement(psiElement: PsiElement): Boolean = psiElement.isJvmElement +} diff --git a/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/IdeaKotlinUastResolveProviderService.kt b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/IdeaKotlinUastResolveProviderService.kt index 4e5536524a7..84e9c09ca45 100644 --- a/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/IdeaKotlinUastResolveProviderService.kt +++ b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/IdeaKotlinUastResolveProviderService.kt @@ -5,12 +5,7 @@ package org.jetbrains.uast.kotlin.internal -import com.intellij.openapi.module.ModuleManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.ProjectRootModificationTracker import com.intellij.psi.PsiElement -import com.intellij.psi.util.CachedValueProvider.Result -import com.intellij.psi.util.CachedValuesManager import org.jetbrains.kotlin.codegen.ClassBuilderMode import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -18,13 +13,9 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.resolveCandidates -import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.project.languageVersionSettings -import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil -import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService @@ -40,17 +31,7 @@ class IdeaKotlinUastResolveProviderService : KotlinUastResolveProviderService { ) } - override fun isJvmElement(psiElement: PsiElement): Boolean { - if (allModulesSupportJvm(psiElement.project)) return true - - val containingFile = psiElement.containingFile - if (containingFile is KtFile) { - return TargetPlatformDetector.getPlatform(containingFile).isJvm() - } - - val module = psiElement.module - return module == null || TargetPlatformDetector.getPlatform(module).isJvm() - } + override fun isJvmElement(psiElement: PsiElement): Boolean = psiElement.isJvmElement override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings { return element.languageVersionSettings @@ -62,16 +43,4 @@ class IdeaKotlinUastResolveProviderService : KotlinUastResolveProviderService { val call = ktElement.getCall(bindingContext) ?: return emptySequence() return call.resolveCandidates(bindingContext, resolutionFacade).map { it.candidateDescriptor }.asSequence() } - - private fun allModulesSupportJvm(project: Project): Boolean = - CachedValuesManager.getManager(project) - .getCachedValue(project) { - Result.create( - ModuleManager.getInstance(project).modules.all { module -> - TargetPlatformDetector.getPlatform(module).isJvm() - }, - ProjectRootModificationTracker.getInstance(project) - ) - } - } diff --git a/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/kotlinUastServiceUtils.kt b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/kotlinUastServiceUtils.kt new file mode 100644 index 00000000000..2a357467618 --- /dev/null +++ b/plugins/uast-kotlin-idea/src/org/jetbrains/uast/kotlin/internal/kotlinUastServiceUtils.kt @@ -0,0 +1,40 @@ +/* + * 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.internal + +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ProjectRootModificationTracker +import com.intellij.psi.PsiElement +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.kotlin.idea.project.TargetPlatformDetector +import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.psi.KtFile + +internal val PsiElement.isJvmElement: Boolean + get() { + if (allModulesSupportJvm(project)) return true + + val containingFile = containingFile + if (containingFile is KtFile) { + return TargetPlatformDetector.getPlatform(containingFile).isJvm() + } + + return module == null || TargetPlatformDetector.getPlatform(module!!).isJvm() + } + +private fun allModulesSupportJvm(project: Project): Boolean = + CachedValuesManager.getManager(project) + .getCachedValue(project) { + CachedValueProvider.Result.create( + ModuleManager.getInstance(project).modules.all { module -> + TargetPlatformDetector.getPlatform(module).isJvm() + }, + ProjectRootModificationTracker.getInstance(project) + ) + } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt index 9648cce72df..d806e3428e5 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -739,7 +739,10 @@ private fun convertVariablesDeclaration( return declarationsExpression.apply { declarations = listOf(variable) } } -val kotlinUastPlugin get() = UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin() +val kotlinUastPlugin: UastLanguagePlugin by lz { + UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } + ?: KotlinUastLanguagePlugin() +} private fun expressionTypes(requiredType: Class?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST @@ -758,4 +761,4 @@ private fun Array>.accommodate(vararg mak private inline fun alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make) -private class UElementAlternative(val uType: Class, val make: () -> U?) \ No newline at end of file +private class UElementAlternative(val uType: Class, val make: () -> U?) diff --git a/plugins/uast-kotlin/tests/AbstractKotlinUastTest.kt b/plugins/uast-kotlin/tests/AbstractKotlinUastTest.kt index 06c0523619f..a205b525d48 100644 --- a/plugins/uast-kotlin/tests/AbstractKotlinUastTest.kt +++ b/plugins/uast-kotlin/tests/AbstractKotlinUastTest.kt @@ -41,8 +41,10 @@ abstract class AbstractKotlinUastTest : AbstractUastTest() { private lateinit var compilerConfiguration: CompilerConfiguration private var kotlinCoreEnvironment: KotlinCoreEnvironment? = null + open var testDataDir: File = File("plugins/uast-kotlin/testData") + override fun getVirtualFile(testName: String): VirtualFile { - val testFile = TEST_KOTLIN_MODEL_DIR.listFiles { pathname -> pathname.nameWithoutExtension == testName }.first() + val testFile = testDataDir.listFiles { pathname -> pathname.nameWithoutExtension == testName }.first() super.initializeEnvironment(testFile) @@ -161,4 +163,4 @@ abstract class AbstractKotlinUastTest : AbstractUastTest() { } } -val TEST_KOTLIN_MODEL_DIR = File("plugins/uast-kotlin/testData") \ No newline at end of file +val TEST_KOTLIN_MODEL_DIR = File("plugins/uast-kotlin/testData") diff --git a/settings.gradle b/settings.gradle index 9bf535944a0..bc192f49223 100644 --- a/settings.gradle +++ b/settings.gradle @@ -211,6 +211,7 @@ include ":benchmarks", ":sam-with-receiver-ide-plugin", ":kotlin-imports-dumper-compiler-plugin", ":plugins:uast-kotlin", + ":plugins:uast-kotlin-fir", ":plugins:uast-kotlin-idea", ":plugins:annotation-based-compiler-plugins-ide-support", ":plugins:base-compiler-plugins-ide-support",