[FIR] Add simple IR body generator to FIR plugin prototype

This commit is contained in:
Dmitriy Novozhilov
2021-10-04 14:23:44 +03:00
committed by TeamCityServer
parent fc1f2e9c72
commit 20e35167c8
10 changed files with 341 additions and 1 deletions
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBoxTest
import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBytecodeShapeTest
import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidIrBoxTest
import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidSyntheticPropertyDescriptorTest
import org.jetbrains.kotlin.fir.plugin.runners.AbstractAllOpenBlackBoxCodegenTest
import org.jetbrains.kotlin.fir.plugin.runners.AbstractFir2IrAllOpenTest
import org.jetbrains.kotlin.fir.plugin.runners.AbstractFirAllOpenDiagnosticTest
import org.jetbrains.kotlin.generators.TestGroup
@@ -378,6 +379,10 @@ fun main(args: Array<String>) {
testClass<AbstractFir2IrAllOpenTest> {
model("fir2ir")
}
testClass<AbstractAllOpenBlackBoxCodegenTest> {
model("box")
}
}
}
}
@@ -10,6 +10,9 @@ dependencies {
api(project(":compiler:fir:tree"))
api(project(":compiler:fir:resolve"))
api(project(":compiler:fir:checkers"))
api(project(":compiler:fir:fir2ir"))
api(project(":compiler:ir.backend.common"))
api(project(":compiler:ir.tree.impl"))
api(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(project(":kotlin-reflect-api"))
@@ -25,6 +28,7 @@ dependencies {
testCompileOnly(project(":kotlin-reflect-api"))
testRuntimeOnly(project(":kotlin-reflect"))
testRuntimeOnly(project(":core:descriptors.runtime"))
testRuntimeOnly(project(":compiler:fir:fir-serialization"))
testRuntimeOnly(intellijDep()) {
includeJars("jna", rootProject = rootProject)
@@ -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.kotlin.ir.plugin
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.fir.backend.IrPluginDeclarationOrigin
import org.jetbrains.kotlin.fir.plugin.generators.AllOpenClassGenerator
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
class GeneratedDeclarationsIrBodyFiller : IrGenerationExtension {
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
moduleFragment.acceptChildrenVoid(Transformer(pluginContext))
}
}
private class Transformer(val context: IrPluginContext) : IrElementVisitorVoid {
private val irFactory = context.irFactory
private val irBuiltIns = context.irBuiltIns
override fun visitElement(element: IrElement) {
when (element) {
is IrDeclaration,
is IrFile,
is IrModuleFragment -> element.acceptChildrenVoid(this)
else -> {}
}
}
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
val origin = declaration.origin
if (origin !is IrPluginDeclarationOrigin || origin.pluginKey != AllOpenClassGenerator.Key) return
require(declaration.body == null)
val constructedType = declaration.returnType as? IrSimpleType ?: return
val constructedClassSymbol = constructedType.classifier
val constructedClass = constructedClassSymbol.owner as? IrClass ?: return
val constructor = constructedClass.primaryConstructor ?: return
val constructorCall = IrConstructorCallImpl(
-1,
-1,
constructedType,
constructor.symbol,
typeArgumentsCount = 0,
constructorTypeArgumentsCount = 0,
valueArgumentsCount = 0
)
val returnStatement = IrReturnImpl(-1, -1, irBuiltIns.nothingType, declaration.symbol, constructorCall)
declaration.body = irFactory.createBlockBody(-1, -1, listOf(returnStatement))
}
override fun visitConstructor(declaration: IrConstructor) {
val origin = declaration.origin
if (origin !is IrPluginDeclarationOrigin || origin.pluginKey != AllOpenClassGenerator.Key) return
require(declaration.body == null)
val type = declaration.returnType as? IrSimpleType ?: return
val delegatingAnyCall = IrDelegatingConstructorCallImpl(
-1,
-1,
irBuiltIns.anyType,
irBuiltIns.anyClass.owner.primaryConstructor?.symbol ?: return,
typeArgumentsCount = 0,
valueArgumentsCount = 0
)
val initializerCall = IrInstanceInitializerCallImpl(
-1,
-1,
(declaration.parent as? IrClass)?.symbol ?: return,
type
)
declaration.body = irFactory.createBlockBody(-1, -1, listOf(delegatingAnyCall, initializerCall))
}
}
@@ -0,0 +1,88 @@
FILE fqName:bar fileName:/generatedClassWithMembersAndNestedClasses.kt
CLASS CLASS name:Foo modality:FINAL visibility:public superTypes:[kotlin.Any]
annotations:
B
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:bar.Foo
CONSTRUCTOR visibility:public <> () returnType:bar.Foo [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Foo modality:FINAL visibility:public superTypes:[kotlin.Any]'
FUN name:box visibility:public modality:FINAL <> ($this:bar.Foo) returnType:kotlin.String
$this: VALUE_PARAMETER name:<this> type:bar.Foo
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in bar.Foo'
CONST String type=kotlin.String value="OK"
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:testConstructor visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:generatedClass type:foo.AllOpenGenerated [val]
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in foo.AllOpenGenerated' type=foo.AllOpenGenerated origin=null
FUN name:testNestedClasses visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
VAR name:nestedFoo type:foo.AllOpenGenerated.NestedFoo [val]
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in foo.AllOpenGenerated.NestedFoo' type=foo.AllOpenGenerated.NestedFoo origin=null
RETURN type=kotlin.Nothing from='public final fun testNestedClasses (): kotlin.String declared in bar'
CALL 'public final fun box (): kotlin.String declared in bar.Foo' type=kotlin.String origin=null
$this: CALL 'public final fun materialize (): bar.Foo declared in foo.AllOpenGenerated.NestedFoo' type=bar.Foo origin=null
$this: GET_VAR 'val nestedFoo: foo.AllOpenGenerated.NestedFoo [val] declared in bar.testNestedClasses' type=foo.AllOpenGenerated.NestedFoo origin=null
FUN name:box visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
CALL 'public final fun testConstructor (): kotlin.Unit declared in bar' type=kotlin.Unit origin=null
RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in bar'
CALL 'public final fun testNestedClasses (): kotlin.String declared in bar' type=kotlin.String origin=null
FILE fqName:foo fileName:__GENERATED DECLARATIONS__.kt
CLASS GENERATED[AllOpenClassGeneratorKey] CLASS name:AllOpenGenerated modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:foo.AllOpenGenerated
CONSTRUCTOR GENERATED[AllOpenClassGeneratorKey] visibility:public <> () returnType:foo.AllOpenGenerated [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS GENERATED[AllOpenClassGeneratorKey] CLASS name:AllOpenGenerated modality:FINAL visibility:public superTypes:[kotlin.Any]'
CLASS GENERATED[AllOpenClassGeneratorKey] CLASS name:NestedFoo modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:foo.AllOpenGenerated.NestedFoo
CONSTRUCTOR GENERATED[AllOpenClassGeneratorKey] visibility:public <> () returnType:foo.AllOpenGenerated.NestedFoo [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS GENERATED[AllOpenClassGeneratorKey] CLASS name:NestedFoo modality:FINAL visibility:public superTypes:[kotlin.Any]'
FUN GENERATED[AllOpenClassGeneratorKey] name:materialize visibility:public modality:FINAL <> ($this:foo.AllOpenGenerated.NestedFoo) returnType:bar.Foo
$this: VALUE_PARAMETER name:<this> type:foo.AllOpenGenerated.NestedFoo
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun materialize (): bar.Foo declared in foo.AllOpenGenerated.NestedFoo'
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in bar.Foo' type=bar.Foo origin=null
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
@@ -0,0 +1,38 @@
FILE: generatedClassWithMembersAndNestedClasses.kt
package bar
@R|org/jetbrains/kotlin/fir/plugin/B|() public final class Foo : R|kotlin/Any| {
public constructor(): R|bar/Foo| {
super<R|kotlin/Any|>()
}
public final fun box(): R|kotlin/String| {
^box String(OK)
}
}
public final fun testConstructor(): R|kotlin/Unit| {
lval generatedClass: R|foo/AllOpenGenerated| = R|foo/AllOpenGenerated|()
}
public final fun testNestedClasses(): R|kotlin/String| {
lval nestedFoo: R|foo/AllOpenGenerated.NestedFoo| = Q|foo/AllOpenGenerated|.R|foo/AllOpenGenerated.NestedFoo|()
^testNestedClasses R|<local>/nestedFoo|.R|foo/AllOpenGenerated.NestedFoo.materialize|().R|bar/Foo.box|()
}
public final fun box(): R|kotlin/String| {
R|bar/testConstructor|()
^box R|bar/testNestedClasses|()
}
FILE: __GENERATED DECLARATIONS__.kt
package foo
public final class AllOpenGenerated : R|kotlin/Any| {
public constructor(): R|foo/AllOpenGenerated|
public final class NestedFoo : R|kotlin/Any| {
public final fun materialize(): R|bar/Foo|
public constructor(): R|foo/AllOpenGenerated.NestedFoo|
}
}
@@ -0,0 +1,26 @@
// DUMP_IR
package bar
import foo.AllOpenGenerated
import org.jetbrains.kotlin.fir.plugin.B
@B
class Foo {
fun box(): String {
return "OK"
}
}
fun testConstructor() {
val generatedClass: AllOpenGenerated = AllOpenGenerated()
}
fun testNestedClasses(): String {
val nestedFoo = AllOpenGenerated.NestedFoo()
return nestedFoo.materialize().box()
}
fun box(): String {
testConstructor()
return testNestedClasses()
}
@@ -0,0 +1,33 @@
/*
* 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.kotlin.fir.plugin.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/fir/fir-plugin-prototype/testData/box")
@TestDataPath("$PROJECT_ROOT")
public class AllOpenBlackBoxCodegenTestGenerated extends AbstractAllOpenBlackBoxCodegenTest {
@Test
public void testAllFilesPresentInBox() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir/fir-plugin-prototype/testData/box"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("generatedClassWithMembersAndNestedClasses.kt")
public void testGeneratedClassWithMembersAndNestedClasses() throws Exception {
runTest("plugins/fir/fir-plugin-prototype/testData/box/generatedClassWithMembersAndNestedClasses.kt");
}
}
@@ -0,0 +1,37 @@
/*
* 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.kotlin.fir.plugin.runners
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler
import org.jetbrains.kotlin.test.backend.handlers.IrTreeVerifierHandler
import org.jetbrains.kotlin.test.backend.handlers.JvmBoxRunner
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.fir2IrStep
import org.jetbrains.kotlin.test.builders.irHandlersStep
import org.jetbrains.kotlin.test.builders.jvmArtifactsHandlersStep
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
open class AbstractAllOpenBlackBoxCodegenTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
override fun TestConfigurationBuilder.configuration() {
commonFirWithPluginFrontendConfiguration()
fir2IrStep()
irHandlersStep {
useHandlers(
::IrTextDumpHandler,
::IrTreeVerifierHandler,
)
}
facadeStep(::JvmIrBackendFacade)
jvmArtifactsHandlersStep {
useHandlers(::JvmBoxRunner)
}
useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.plugin.runners
import org.jetbrains.kotlin.fir.plugin.FirAllOpenComponentRegistrar
import org.jetbrains.kotlin.fir.plugin.services.IrExtensionRegistrar
import org.jetbrains.kotlin.fir.plugin.services.PluginAnnotationsProvider
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
@@ -22,7 +23,10 @@ fun TestConfigurationBuilder.commonFirWithPluginFrontendConfiguration() {
+FIR_DUMP
}
useConfigurators(::PluginAnnotationsProvider)
useConfigurators(
::PluginAnnotationsProvider,
::IrExtensionRegistrar
)
}
val FirFrontendFacadeWithPlugin: Constructor<FirFrontendFacade>
@@ -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.kotlin.fir.plugin.services
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.ir.plugin.GeneratedDeclarationsIrBodyFiller
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
class IrExtensionRegistrar(testServices: TestServices) : EnvironmentConfigurator(testServices) {
override fun registerCompilerExtensions(project: Project) {
IrGenerationExtension.registerExtension(project, GeneratedDeclarationsIrBodyFiller())
}
}