-
Notifications
You must be signed in to change notification settings - Fork 624
/
Transformer.kt
115 lines (99 loc) · 4.63 KB
/
Transformer.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package io.kotest.framework.multiplatform.embeddablecompiler
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.addChild
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.toLogger
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irVararg
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.getSimpleFunction
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.name.FqName
import java.util.concurrent.CopyOnWriteArrayList
abstract class Transformer(protected val messageCollector: MessageCollector, protected val pluginContext: IrPluginContext) : IrElementTransformerVoidWithContext() {
private val specs = CopyOnWriteArrayList<IrClass>()
private var configs = CopyOnWriteArrayList<IrClass>()
override fun visitClassNew(declaration: IrClass): IrStatement {
super.visitClassNew(declaration)
if (declaration.isProjectConfig()) configs.add(declaration)
return declaration
}
override fun visitFileNew(declaration: IrFile): IrFile {
super.visitFileNew(declaration)
val specs = declaration.specs()
messageCollector.toLogger().log("${declaration.name} contains ${specs.size} spec(s): ${specs.joinToString(", ") { it.kotlinFqName.asString() }}")
this.specs.addAll(specs)
return declaration
}
override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment {
val fragment = super.visitModuleFragment(declaration)
messageCollector.toLogger().log("Detected ${configs.size} configs:")
configs.forEach {
messageCollector.toLogger().log(it.kotlinFqName.asString())
}
messageCollector.toLogger().log("Detected ${specs.size} JS specs:")
specs.forEach {
messageCollector.toLogger().log(it.kotlinFqName.asString())
}
if (specs.isEmpty()) {
return fragment
}
val file = declaration.files.first()
val launcher = generateLauncher(specs, configs, file)
file.addChild(launcher)
return fragment
}
abstract fun generateLauncher(specs: Iterable<IrClass>, configs: Iterable<IrClass>, declarationParent: IrDeclarationParent): IrDeclaration
protected fun IrBuilderWithScope.callLauncher(
launchFunction: IrSimpleFunctionSymbol,
specs: Iterable<IrClass>,
configs: Iterable<IrClass>,
constructorGenerator: IrBuilderWithScope.() -> IrExpression
): IrCall {
return irCall(launchFunction).also { promise: IrCall ->
promise.dispatchReceiver = irCall(withSpecsFn).also { withSpecs ->
withSpecs.putValueArgument(
0,
irVararg(
pluginContext.irBuiltIns.stringType,
specs.map { irCall(it.constructors.first()) }
)
)
withSpecs.dispatchReceiver = irCall(withConfigFn).also { withConfig ->
withConfig.putValueArgument(
0,
irVararg(
pluginContext.irBuiltIns.stringType,
configs.map { irCall(it.constructors.first()) }
)
)
withConfig.dispatchReceiver = constructorGenerator()
}
}
}
}
protected val launcherClass by lazy {
pluginContext.referenceClass(FqName(EntryPoint.TestEngineClassName))
?: error("Cannot find ${EntryPoint.TestEngineClassName} class reference")
}
protected val launcherConstructor by lazy { launcherClass.constructors.first { it.owner.valueParameters.isEmpty() } }
protected val withSpecsFn by lazy {
launcherClass.getSimpleFunction(EntryPoint.WithSpecsMethodName)
?: error("Cannot find function ${EntryPoint.WithSpecsMethodName}")
}
protected val withConfigFn by lazy {
launcherClass.getSimpleFunction(EntryPoint.WithConfigMethodName)
?: error("Cannot find function ${EntryPoint.WithConfigMethodName}")
}
}