[FIR-PLUGIN] Add tests for generating declarations from plugin

This commit is contained in:
Dmitriy Novozhilov
2020-06-01 18:52:16 +03:00
parent eceeacdf61
commit 0c18cb054d
11 changed files with 259 additions and 15 deletions
@@ -8,4 +8,12 @@ package org.jetbrains.kotlin.fir.plugin
annotation class AllOpen
annotation class WithGenerated
annotation class WithHello
annotation class WithNestedFoo
annotation class WithNestedFoo
annotation class A
annotation class B
annotation class C
annotation class D
annotation class E
annotation class F
annotation class G
@@ -6,6 +6,10 @@
package org.jetbrains.kotlin.fir.plugin
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.plugin.generators.AllOpenMemberGenerator
import org.jetbrains.kotlin.fir.plugin.generators.AllOpenNestedClassGenerator
import org.jetbrains.kotlin.fir.plugin.generators.AllOpenRecursiveNestedClassGenerator
import org.jetbrains.kotlin.fir.plugin.generators.AllOpenTopLevelDeclarationsGenerator
class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
override fun ExtensionRegistrarContext.configurePlugin() {
@@ -13,5 +17,7 @@ class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
+::AllOpenMemberGenerator
+::AllOpenNestedClassGenerator
+::AllOpenAdditionalCheckers
+::AllOpenTopLevelDeclarationsGenerator
+::AllOpenRecursiveNestedClassGenerator
}
}
@@ -3,31 +3,32 @@
* 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.kotlin.fir.plugin
package org.jetbrains.kotlin.fir.plugin.generators
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.extensions.FirExistingClassModificationExtension
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.and
import org.jetbrains.kotlin.fir.extensions.predicate.has
import org.jetbrains.kotlin.fir.extensions.predicate.under
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedNestedClass
import org.jetbrains.kotlin.fir.plugin.AllOpenPluginKey
import org.jetbrains.kotlin.fir.plugin.fqn
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClass
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class AllOpenMemberGenerator(session: FirSession) : FirExistingClassModificationExtension(session) {
override fun generateNestedClasses(
class AllOpenMemberGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
override fun generateClasses(
annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<FirRegularClass>> {
return emptyList()
}
override fun generateMembersForNestedClasses(generatedNestedClass: GeneratedNestedClass): List<FirDeclaration> {
override fun generateMembersForGeneratedClass(generatedClass: GeneratedClass): List<FirDeclaration> {
return emptyList()
}
@@ -3,7 +3,7 @@
* 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.kotlin.fir.plugin
package org.jetbrains.kotlin.fir.plugin.generators
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildConstructor
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.extensions.FirExistingClassModificationExtension
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.has
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedNestedClass
import org.jetbrains.kotlin.fir.plugin.AllOpenPluginKey
import org.jetbrains.kotlin.fir.plugin.fqn
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClass
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
@@ -28,8 +30,8 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.Name
class AllOpenNestedClassGenerator(session: FirSession) : FirExistingClassModificationExtension(session) {
override fun generateNestedClasses(
class AllOpenNestedClassGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
override fun generateClasses(
annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<FirRegularClass>> {
@@ -53,8 +55,8 @@ class AllOpenNestedClassGenerator(session: FirSession) : FirExistingClassModific
return listOf(GeneratedDeclaration(newClass, owner))
}
override fun generateMembersForNestedClasses(generatedNestedClass: GeneratedNestedClass): List<FirDeclaration> {
val klass = generatedNestedClass.nestedClass
override fun generateMembersForGeneratedClass(generatedClass: GeneratedClass): List<FirDeclaration> {
val klass = generatedClass.klass
val classId = klass.symbol.classId
val constructor = buildConstructor {
@@ -0,0 +1,84 @@
/*
* Copyright 2010-2020 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.kotlin.fir.plugin.generators
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirEffectiveVisibilityImpl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.has
import org.jetbrains.kotlin.fir.plugin.fqn
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClass
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
class AllOpenRecursiveNestedClassGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
override fun generateClasses(
annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<FirRegularClass>> {
if (owners.size > 2) return emptyList()
val owner = annotatedDeclaration as? FirRegularClass ?: return emptyList()
val newClass = buildRegularClass {
session = this@AllOpenRecursiveNestedClassGenerator.session
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.Plugin(key)
status = FirResolvedDeclarationStatusImpl(
Visibilities.PUBLIC,
FirEffectiveVisibilityImpl.Public,
Modality.FINAL
)
classKind = ClassKind.CLASS
name = Name.identifier("Nested")
symbol = FirRegularClassSymbol(owner.symbol.classId.createNestedClassId(name))
scopeProvider = owner.scopeProvider
annotations += buildAnnotationCall {
annotationTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(annotationClassId),
emptyArray(),
isNullable = false
)
}
}
}
return listOf(GeneratedDeclaration(newClass, owner))
}
override fun generateMembersForGeneratedClass(generatedClass: GeneratedClass): List<FirDeclaration> {
return emptyList()
}
override fun generateMembers(
annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<*>> {
return emptyList()
}
override val key: FirPluginKey
get() = Key
override val predicate: DeclarationPredicate
get() = has("B".fqn())
private val annotationClassId = "B".fqn().let {
ClassId(it.parent(), it.shortName())
}
private object Key : FirPluginKey()
}
@@ -0,0 +1,84 @@
/*
* Copyright 2010-2020 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.kotlin.fir.plugin.generators
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirEffectiveVisibilityImpl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.has
import org.jetbrains.kotlin.fir.plugin.fqn
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClass
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
class AllOpenTopLevelDeclarationsGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
override fun generateClasses(
annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<FirRegularClass>> {
val file = owners.first() as FirFile
val klass = annotatedDeclaration as? FirRegularClass ?: return emptyList()
val newClass = buildRegularClass {
session = this@AllOpenTopLevelDeclarationsGenerator.session
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.Plugin(key)
status = FirResolvedDeclarationStatusImpl(
Visibilities.PUBLIC,
FirEffectiveVisibilityImpl.Public,
Modality.FINAL
)
classKind = ClassKind.OBJECT
name = Name.identifier("TopLevel${klass.name}")
symbol = FirRegularClassSymbol(ClassId(file.packageFqName, name))
scopeProvider = klass.scopeProvider
}
return listOf(GeneratedDeclaration(newClass, file))
}
override fun generateMembersForGeneratedClass(generatedClass: GeneratedClass): List<FirDeclaration> {
val klass = generatedClass.klass
val function = buildSimpleFunction {
session = klass.session
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.Plugin(key)
returnTypeRef = session.builtinTypes.intType
status = FirResolvedDeclarationStatusImpl(
Visibilities.PUBLIC,
FirEffectiveVisibilityImpl.Public,
Modality.FINAL
)
name = Name.identifier("hello")
symbol = FirNamedFunctionSymbol(CallableId(klass.symbol.classId, name), isFakeOverride = false)
}
return listOf(function)
}
override fun generateMembers(
annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<*>> {
return emptyList()
}
override val key: FirPluginKey
get() = Key
override val predicate: DeclarationPredicate
get() = has("A".fqn())
private object Key : FirPluginKey()
}
@@ -0,0 +1,8 @@
import org.jetbrains.kotlin.fir.plugin.B
@B
class SomeClass
fun test_1(x: SomeClass.Nested) {}
fun test_2(x: SomeClass.Nested.Nested) {}
fun test_3(x: SomeClass.Nested.Nested.Nested) {}
@@ -0,0 +1,19 @@
FILE: recursiveNestedClasses.kt
@R|org/jetbrains/kotlin/fir/plugin/B|() public final class SomeClass : R|kotlin/Any| {
public constructor(): R|SomeClass| {
super<R|kotlin/Any|>()
}
@R|org/jetbrains/kotlin/fir/plugin/B|() public final class Nested {
@R|org/jetbrains/kotlin/fir/plugin/B|() public final class Nested {
}
}
}
public final fun test_1(x: R|SomeClass.Nested|): R|kotlin/Unit| {
}
public final fun test_2(x: R|SomeClass.Nested.Nested|): R|kotlin/Unit| {
}
public final fun test_3(x: R|ERROR CLASS: Symbol not found, for `SomeClass.Nested.Nested.Nested`|): R|kotlin/Unit| {
}
@@ -0,0 +1,8 @@
import org.jetbrains.kotlin.fir.plugin.A
@A
class SomeClass
fun test() {
TopLevelSomeClass.hello()
}
@@ -0,0 +1,14 @@
FILE: topLevelClass.kt
@R|org/jetbrains/kotlin/fir/plugin/A|() public final class SomeClass : R|kotlin/Any| {
public constructor(): R|SomeClass| {
super<R|kotlin/Any|>()
}
}
public final fun test(): R|kotlin/Unit| {
Q|TopLevelSomeClass|.R|/TopLevelSomeClass.hello|()
}
public final object TopLevelSomeClass {
public final fun hello(): R|kotlin/Int|
}
@@ -67,6 +67,16 @@ public class FirAllOpenDiagnosticTestGenerated extends AbstractFirAllOpenDiagnos
public void testNestedClass() throws Exception {
runTest("plugins/fir/fir-plugin-prototype/testData/memberGen/nestedClass.kt");
}
@TestMetadata("recursiveNestedClasses.kt")
public void testRecursiveNestedClasses() throws Exception {
runTest("plugins/fir/fir-plugin-prototype/testData/memberGen/recursiveNestedClasses.kt");
}
@TestMetadata("topLevelClass.kt")
public void testTopLevelClass() throws Exception {
runTest("plugins/fir/fir-plugin-prototype/testData/memberGen/topLevelClass.kt");
}
}
@TestMetadata("plugins/fir/fir-plugin-prototype/testData/status")