Add JVM ABI K1/K2 consistency tests
This commit is contained in:
committed by
Space Team
parent
5a1fb78fcd
commit
34bac48541
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.test
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys.USE_FIR
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.isCommon
|
||||
@@ -16,6 +17,9 @@ import org.jetbrains.kotlin.platform.konan.isNative
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
|
||||
import org.jetbrains.kotlin.wasm.resolve.WasmJsPlatformAnalyzerServices
|
||||
import java.io.File
|
||||
|
||||
@@ -44,4 +48,12 @@ fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices {
|
||||
isWasm() -> WasmJsPlatformAnalyzerServices
|
||||
else -> error("Unknown target platform: $this")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> runWithEnablingFirUseOption(testServices: TestServices, module: TestModule, lambda: () -> T): T {
|
||||
val compilerConfiguration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
compilerConfiguration.put(USE_FIR, true)
|
||||
val result = lambda()
|
||||
compilerConfiguration.put(USE_FIR, false)
|
||||
return result
|
||||
}
|
||||
+4
-9
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
|
||||
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
|
||||
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
|
||||
import org.jetbrains.kotlin.test.directives.model.ValueDirective
|
||||
import org.jetbrains.kotlin.test.directives.tryRetrieveIgnoredInliner
|
||||
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
@@ -43,17 +44,11 @@ class BlackBoxInlinerCodegenSuppressor(testServices: TestServices) : AfterAnalys
|
||||
|
||||
private fun suppressForTargetFrontend(
|
||||
failedAssertions: List<WrappedException>,
|
||||
directive: ValueDirective<TargetInliner>
|
||||
directive: ValueDirective<TargetInliner>,
|
||||
): List<WrappedException>? {
|
||||
val directiveName = directive.name
|
||||
val ignoreDirectives = testServices.moduleStructure.allDirectives[directive]
|
||||
if (ignoreDirectives.size > 1) {
|
||||
throw IllegalArgumentException("Directive $directiveName should contains only one value")
|
||||
}
|
||||
|
||||
val ignoreDirective = ignoreDirectives.singleOrNull()
|
||||
val ignoreDirective = testServices.tryRetrieveIgnoredInliner(directive)
|
||||
val enabledIrInliner = LanguageSettingsDirectives.ENABLE_JVM_IR_INLINER in testServices.moduleStructure.allDirectives
|
||||
val unmuteError = listOf(AssertionError("Looks like this test can be unmuted. Please remove $directiveName directive.").wrap())
|
||||
val unmuteError = listOf(AssertionError("Looks like this test can be unmuted. Please remove ${directive.name} directive.").wrap())
|
||||
|
||||
if (ignoreDirective == TargetInliner.IR && enabledIrInliner || ignoreDirective == TargetInliner.BYTECODE && !enabledIrInliner) {
|
||||
return if (failedAssertions.isNotEmpty()) emptyList() else unmuteError
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.backend.handlers
|
||||
|
||||
import com.google.common.collect.Sets
|
||||
import org.jetbrains.kotlin.abicmp.defects.Location
|
||||
import org.jetbrains.kotlin.abicmp.reports.*
|
||||
import org.jetbrains.kotlin.abicmp.tag
|
||||
import org.jetbrains.kotlin.abicmp.tasks.ClassTask
|
||||
import org.jetbrains.kotlin.abicmp.tasks.checkerConfiguration
|
||||
import org.jetbrains.kotlin.codegen.getClassFiles
|
||||
import org.jetbrains.kotlin.test.backend.ir.AbiCheckerSuppressor
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
import org.jetbrains.kotlin.test.utils.withExtension
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
|
||||
class JvmAbiConsistencyHandler(testServices: TestServices) : AnalysisHandler<BinaryArtifacts.JvmFromK1AndK2>(testServices, true, true) {
|
||||
override val artifactKind: TestArtifactKind<BinaryArtifacts.JvmFromK1AndK2>
|
||||
get() = ArtifactKinds.JvmFromK1AndK2
|
||||
|
||||
|
||||
private class ModuleReport(
|
||||
val missingInK1: Set<String>,
|
||||
val missingInK2: Set<String>,
|
||||
val nonEmptyClassReports: MutableList<ClassReport>,
|
||||
)
|
||||
|
||||
private class TestReport {
|
||||
private val modulesWithNonEmptyReports = mutableMapOf<String, ModuleReport>()
|
||||
|
||||
fun addModuleReport(moduleName: String, report: ModuleReport) {
|
||||
modulesWithNonEmptyReports[moduleName] = report
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean = modulesWithNonEmptyReports.isEmpty()
|
||||
|
||||
fun dumpAsPlainText(): String {
|
||||
|
||||
fun TextTreeBuilderContext.reportMissing(frontendName: String, missing: Set<String>) {
|
||||
if (missing.isEmpty()) return
|
||||
node("Missing in $frontendName") {
|
||||
node(missing.joinToString("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
val out = PrintWriter(outputStream)
|
||||
|
||||
dumpTree(out) {
|
||||
modulesWithNonEmptyReports.forEach { (module, report) ->
|
||||
node("MODULE $module") {
|
||||
reportMissing("K1", report.missingInK1)
|
||||
reportMissing("K2", report.missingInK2)
|
||||
report.nonEmptyClassReports.forEach { classReport ->
|
||||
with(classReport) { appendClassReport() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outputStream.toString()
|
||||
}
|
||||
|
||||
// Might be used while debugging
|
||||
@Suppress("unused")
|
||||
fun dumpAsHtml(): String {
|
||||
fun PrintWriter.reportMissing(frontendName: String, missing: Set<String>) {
|
||||
if (missing.isEmpty()) return
|
||||
println("Missing in $frontendName:")
|
||||
tag("br")
|
||||
println(missing.joinToString())
|
||||
tag("br")
|
||||
tag("br")
|
||||
}
|
||||
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
PrintWriter(outputStream, true).use { out ->
|
||||
out.tag("html") {
|
||||
out.tag("head") {
|
||||
out.tag("style", REPORT_CSS)
|
||||
}
|
||||
out.tag("body") {
|
||||
modulesWithNonEmptyReports.forEach { (module, report) ->
|
||||
out.tag("h2", "Module: $module")
|
||||
out.reportMissing("K1", report.missingInK1)
|
||||
out.reportMissing("K2", report.missingInK2)
|
||||
report.nonEmptyClassReports.forEach { it.writeAsHtml(out) }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputStream.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private val testReport = TestReport()
|
||||
|
||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||
val txtDiffPath = testServices.moduleStructure.originalTestDataFiles.first().withExtension(".jvm_abi.txt")
|
||||
val isDifferenceExplained = testServices.moduleStructure.allDirectives.contains(CodegenTestDirectives.JVM_ABI_K1_K2_DIFF)
|
||||
|
||||
if (!testReport.isEmpty()) {
|
||||
JUnit5Assertions.assertEqualsToFile(
|
||||
txtDiffPath,
|
||||
testReport.dumpAsPlainText(),
|
||||
sanitizer = { it },
|
||||
differenceObtainedMessage = { "Actual K1/K2 JVM ABI difference differs from expected" },
|
||||
fileNotFoundMessageTeamCity = fileNotFoundMessageBuilder(isTeamCityVersion = true, isDifferenceExplained),
|
||||
fileNotFoundMessageLocal = fileNotFoundMessageBuilder(isTeamCityVersion = false, isDifferenceExplained)
|
||||
)
|
||||
|
||||
if (!isDifferenceExplained) {
|
||||
fail(
|
||||
"K1/K2 JVM ABI difference obtained. Add ${CodegenTestDirectives.JVM_ABI_K1_K2_DIFF.name} directive with an explanation"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (isDifferenceExplained && txtDiffPath.exists()) {
|
||||
fail(
|
||||
"No K1/K2 JVM ABI difference found. Remove ${CodegenTestDirectives.JVM_ABI_K1_K2_DIFF.name} directive and $txtDiffPath"
|
||||
)
|
||||
}
|
||||
if (isDifferenceExplained) {
|
||||
fail("No K1/K2 JVM ABI difference found. Remove ${CodegenTestDirectives.JVM_ABI_K1_K2_DIFF.name} directive")
|
||||
}
|
||||
if (txtDiffPath.exists()) {
|
||||
fail("No K1/K2 JVM ABI difference found. Remove $txtDiffPath")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fileNotFoundMessageBuilder(isTeamCityVersion: Boolean, isDiffExplained: Boolean): ((File) -> String) = {
|
||||
buildString {
|
||||
if (isTeamCityVersion) {
|
||||
append("Expected data file did not exist `$it`")
|
||||
} else {
|
||||
append("Expected data file did not exist. Generating: $it")
|
||||
}
|
||||
if (!isDiffExplained) {
|
||||
append("\n")
|
||||
append("Also add ${CodegenTestDirectives.JVM_ABI_K1_K2_DIFF.name} directive with an explanation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fail(message: String) {
|
||||
JUnit5Assertions.fail { message }
|
||||
}
|
||||
|
||||
override fun processModule(module: TestModule, info: BinaryArtifacts.JvmFromK1AndK2) {
|
||||
if (AbiCheckerSuppressor.ignoredByBackendOrInliner(testServices)) return
|
||||
val classesFromK1 = info.fromK1.classFileFactory.getClassFiles().associate { it.relativePath to it.asByteArray() }
|
||||
val classesFromK2 = info.fromK2.classFileFactory.getClassFiles().associate { it.relativePath to it.asByteArray() }
|
||||
val missingInK2 = Sets.difference(classesFromK1.keys, classesFromK2.keys)
|
||||
val missingInK1 = Sets.difference(classesFromK2.keys, classesFromK1.keys)
|
||||
val commonClasses = Sets.intersection(classesFromK1.keys, classesFromK2.keys)
|
||||
|
||||
val nonEmptyClassReports = mutableListOf<ClassReport>()
|
||||
commonClasses.forEach { classInternalName ->
|
||||
val k1ClassNode = parseClassNode(classesFromK1[classInternalName]!!)
|
||||
val k2ClassNode = parseClassNode(classesFromK2[classInternalName]!!)
|
||||
val classReport = ClassReport(Location.Class("", classInternalName), classInternalName, "K1", "K2", DefectReport())
|
||||
ClassTask(checkerConfiguration {
|
||||
// Indication of constants is different in K2 as expected
|
||||
// We simply turn the checker off to avoid producing an enormous number of difference reports
|
||||
disable("class.metadata.property.hasConstant")
|
||||
}, k1ClassNode, k2ClassNode, classReport).run()
|
||||
if (classReport.isNotEmpty()) {
|
||||
nonEmptyClassReports.add(classReport)
|
||||
}
|
||||
}
|
||||
|
||||
if (nonEmptyClassReports.isNotEmpty() || missingInK1.isNotEmpty() || missingInK2.isNotEmpty()) {
|
||||
testReport.addModuleReport(module.name, ModuleReport(missingInK1, missingInK2, nonEmptyClassReports))
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseClassNode(byteArray: ByteArray) =
|
||||
ClassNode().also { ClassReader(ByteArrayInputStream(byteArray)).accept(it, ClassReader.SKIP_CODE) }
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.test.WrappedException
|
||||
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
|
||||
import org.jetbrains.kotlin.test.backend.TargetInliner
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_K1
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_K2
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_INLINER
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_INLINER_K1
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_INLINER_K2
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.JVM_ABI_K1_K2_DIFF
|
||||
import org.jetbrains.kotlin.test.directives.tryRetrieveIgnoredInliner
|
||||
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
|
||||
import org.jetbrains.kotlin.test.services.ServiceRegistrationData
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
import org.jetbrains.kotlin.test.services.service
|
||||
import org.jetbrains.kotlin.utils.bind
|
||||
|
||||
class AbiCheckerSuppressor(testServices: TestServices) : AfterAnalysisChecker(testServices) {
|
||||
|
||||
companion object {
|
||||
fun ignoredByBackendOrInliner(testServices: TestServices) = testServices.ignoredByBackend || testServices.ignoredByInliner
|
||||
}
|
||||
|
||||
override val additionalServices: List<ServiceRegistrationData>
|
||||
get() = listOf(service(BlackBoxCodegenSuppressor::SuppressionChecker.bind(null)))
|
||||
|
||||
|
||||
override fun suppressIfNeeded(failedAssertions: List<WrappedException>): List<WrappedException> {
|
||||
val isDifferenceExplained = testServices.moduleStructure.allDirectives.contains(JVM_ABI_K1_K2_DIFF)
|
||||
if (ignoredByBackendOrInliner(testServices)) {
|
||||
if (isDifferenceExplained) {
|
||||
return listOf(
|
||||
AssertionError(
|
||||
"No K1/K2 JVM ABI comparison done for this test. Please remove ${JVM_ABI_K1_K2_DIFF.name} directive."
|
||||
).wrap()
|
||||
)
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
return failedAssertions
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val TestServices.suppressionChecker: BlackBoxCodegenSuppressor.SuppressionChecker by TestServices.testServiceAccessor()
|
||||
|
||||
private val TestServices.ignoredByBackend: Boolean
|
||||
get() = listOf(IGNORE_BACKEND, IGNORE_BACKEND_K1, IGNORE_BACKEND_K2)
|
||||
.any { suppressionChecker.failuresInModuleAreIgnored(moduleStructure.modules.first(), it).testMuted }
|
||||
|
||||
private val TestServices.ignoredByInliner: Boolean
|
||||
get() = listOf(IGNORE_INLINER, IGNORE_INLINER_K1, IGNORE_INLINER_K2).any { tryRetrieveIgnoredInliner(it) == TargetInliner.BYTECODE }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.test.model.BackendKind
|
||||
import org.jetbrains.kotlin.test.model.BackendKinds
|
||||
import org.jetbrains.kotlin.test.model.ResultingArtifact
|
||||
|
||||
class IrBackendInputsFromK1AndK2(
|
||||
val fromK1: IrBackendInput,
|
||||
val fromK2: IrBackendInput,
|
||||
) : ResultingArtifact.BackendInput<IrBackendInputsFromK1AndK2>() {
|
||||
override val kind: BackendKind<IrBackendInputsFromK1AndK2>
|
||||
get() = BackendKinds.IrBackendForK1AndK2
|
||||
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
import org.jetbrains.kotlin.test.runWithEnablingFirUseOption
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
|
||||
class K1AndK2JvmIrBackendFacade(testServices: TestServices) :
|
||||
BackendFacade<IrBackendInputsFromK1AndK2, BinaryArtifacts.JvmFromK1AndK2>(
|
||||
testServices,
|
||||
BackendKinds.IrBackendForK1AndK2,
|
||||
ArtifactKinds.JvmFromK1AndK2
|
||||
) {
|
||||
|
||||
private val backendForClassicFrontend = JvmIrBackendFacade(testServices)
|
||||
private val backendForFir = JvmIrBackendFacade(testServices)
|
||||
|
||||
override fun transform(module: TestModule, inputArtifact: IrBackendInputsFromK1AndK2): BinaryArtifacts.JvmFromK1AndK2? {
|
||||
val fromClassicFrontend = backendForClassicFrontend.transform(module, inputArtifact.fromK1) ?: return null
|
||||
val fromFir =
|
||||
runWithEnablingFirUseOption(testServices, module) { backendForFir.transform(module, inputArtifact.fromK2) } ?: return null
|
||||
return BinaryArtifacts.JvmFromK1AndK2(fromClassicFrontend, fromFir)
|
||||
}
|
||||
|
||||
override fun shouldRunAnalysis(module: TestModule): Boolean {
|
||||
return module.backendKind == BackendKinds.IrBackend && module.binaryKind == ArtifactKinds.JvmFromK1AndK2
|
||||
}
|
||||
}
|
||||
+14
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.test.builders.CompilerStepsNames.DESERIALIZED_IR_HAN
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.FIR_HANDLERS_STEP_NAME
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.JS_ARTIFACTS_HANDLERS_STEP_NAME
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.JVM_ARTIFACTS_HANDLERS_STEP_NAME
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.JVM_FROM_K1_AND_K2_ARTIFACTS_HANDLERS_STEP_NAME
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.KLIB_ARTIFACTS_HANDLERS_STEP_NAME
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.RAW_IR_HANDLERS_STEP_NAME
|
||||
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.WASM_ARTIFACTS_HANDLERS_STEP_NAME
|
||||
@@ -43,6 +44,7 @@ object CompilerStepsNames {
|
||||
const val JS_ARTIFACTS_HANDLERS_STEP_NAME = "js artifacts handlers"
|
||||
const val WASM_ARTIFACTS_HANDLERS_STEP_NAME = "wasm artifacts handlers"
|
||||
const val KLIB_ARTIFACTS_HANDLERS_STEP_NAME = "klib artifacts handlers"
|
||||
const val JVM_FROM_K1_AND_K2_ARTIFACTS_HANDLERS_STEP_NAME = "jvm from K1 and K2 artifacts handlers"
|
||||
|
||||
}
|
||||
|
||||
@@ -109,6 +111,12 @@ inline fun TestConfigurationBuilder.jvmArtifactsHandlersStep(
|
||||
namedHandlersStep(JVM_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.Jvm, init)
|
||||
}
|
||||
|
||||
inline fun TestConfigurationBuilder.jvmFromK1AndK2ArtifactsHandlersStep(
|
||||
init: HandlersStepBuilder<BinaryArtifacts.JvmFromK1AndK2, ArtifactKinds.JvmFromK1AndK2>.() -> Unit = {},
|
||||
) {
|
||||
namedHandlersStep(JVM_FROM_K1_AND_K2_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.JvmFromK1AndK2, init)
|
||||
}
|
||||
|
||||
inline fun TestConfigurationBuilder.jsArtifactsHandlersStep(
|
||||
init: HandlersStepBuilder<BinaryArtifacts.Js, ArtifactKinds.Js>.() -> Unit = {}
|
||||
) {
|
||||
@@ -175,3 +183,9 @@ inline fun TestConfigurationBuilder.configureKlibArtifactsHandlersStep(
|
||||
) {
|
||||
configureNamedHandlersStep(KLIB_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.KLib, init)
|
||||
}
|
||||
|
||||
inline fun TestConfigurationBuilder.configureJvmFromK1AndK2ArtifactHandlerStep(
|
||||
init: HandlersStepBuilder<BinaryArtifacts.JvmFromK1AndK2, ArtifactKinds.JvmFromK1AndK2>.() -> Unit,
|
||||
) {
|
||||
configureNamedHandlersStep(JVM_FROM_K1_AND_K2_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.JvmFromK1AndK2, init)
|
||||
}
|
||||
+17
-1
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
|
||||
import org.jetbrains.kotlin.test.directives.model.ValueDirective
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
|
||||
object CodegenTestDirectives : SimpleDirectivesContainer() {
|
||||
val IGNORE_BACKEND by enumDirective<TargetBackend>(
|
||||
@@ -255,12 +257,17 @@ object CodegenTestDirectives : SimpleDirectivesContainer() {
|
||||
Suppresses test if $ENABLE_IR_FAKE_OVERRIDE_GENERATION directive enabled
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val JVM_ABI_K1_K2_DIFF by stringDirective(
|
||||
description = "Expect difference in JVM ABI between K1 and K2",
|
||||
applicability = Global
|
||||
)
|
||||
}
|
||||
|
||||
fun extractIgnoredDirectiveForTargetBackend(
|
||||
module: TestModule,
|
||||
targetBackend: TargetBackend,
|
||||
customIgnoreDirective: ValueDirective<TargetBackend>? = null
|
||||
customIgnoreDirective: ValueDirective<TargetBackend>? = null,
|
||||
): ValueDirective<TargetBackend>? =
|
||||
when (module.frontendKind) {
|
||||
FrontendKinds.ClassicFrontend -> CodegenTestDirectives.IGNORE_BACKEND_K1
|
||||
@@ -280,3 +287,12 @@ fun extractIgnoredDirectiveForTargetBackend(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun TestServices.tryRetrieveIgnoredInliner(directive: ValueDirective<TargetInliner>): TargetInliner? {
|
||||
val directiveName = directive.name
|
||||
val ignoreDirectives = moduleStructure.allDirectives[directive]
|
||||
if (ignoreDirectives.size > 1) {
|
||||
throw IllegalArgumentException("Directive $directiveName should contains only one value")
|
||||
}
|
||||
return ignoreDirectives.singleOrNull()
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.frontend
|
||||
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
|
||||
import org.jetbrains.kotlin.test.model.FrontendFacade
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.runWithEnablingFirUseOption
|
||||
import org.jetbrains.kotlin.test.services.ServiceRegistrationData
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager
|
||||
|
||||
class K1AndK2FrontendFacade(
|
||||
testServices: TestServices,
|
||||
) : FrontendFacade<K1AndK2OutputArtifact>(testServices, FrontendKinds.ClassicAndFIR) {
|
||||
|
||||
override val additionalServices: List<ServiceRegistrationData>
|
||||
get() = classicFrontendFacade.additionalServices + firFrontendFacade.additionalServices
|
||||
|
||||
private val classicFrontendFacade: ClassicFrontendFacade = ClassicFrontendFacade(testServices)
|
||||
private val firFrontendFacade: FirFrontendFacade = FirFrontendFacade(testServices)
|
||||
|
||||
override fun analyze(module: TestModule): K1AndK2OutputArtifact {
|
||||
testServices.compiledClassesManager.specifiedFrontendKind = FrontendKinds.ClassicFrontend
|
||||
val k1Artifact = classicFrontendFacade.analyze(module)
|
||||
testServices.compiledClassesManager.specifiedFrontendKind = FrontendKinds.FIR
|
||||
val k2Artifact = runWithEnablingFirUseOption(testServices, module) { firFrontendFacade.analyze(module) }
|
||||
return K1AndK2OutputArtifact(k1Artifact, k2Artifact)
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.frontend
|
||||
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
||||
import org.jetbrains.kotlin.test.model.FrontendKind
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.ResultingArtifact
|
||||
|
||||
class K1AndK2OutputArtifact(val k1Artifact: ClassicFrontendOutputArtifact, val k2Artifact: FirOutputArtifact) :
|
||||
ResultingArtifact.FrontendOutput<K1AndK2OutputArtifact>() {
|
||||
override val kind: FrontendKind<K1AndK2OutputArtifact>
|
||||
get() = FrontendKinds.ClassicAndFIR
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.frontend
|
||||
|
||||
import org.jetbrains.kotlin.test.backend.ir.IrBackendInputsFromK1AndK2
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2IrConverter
|
||||
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrJvmResultsConverter
|
||||
import org.jetbrains.kotlin.test.model.BackendKinds
|
||||
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.runWithEnablingFirUseOption
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
|
||||
class K1AndK2ToIrConverter(testServices: TestServices) :
|
||||
Frontend2BackendConverter<K1AndK2OutputArtifact, IrBackendInputsFromK1AndK2>(
|
||||
testServices,
|
||||
FrontendKinds.ClassicAndFIR,
|
||||
BackendKinds.IrBackendForK1AndK2
|
||||
) {
|
||||
|
||||
private val classicFrontend2IrConverter = ClassicFrontend2IrConverter(testServices)
|
||||
private val fir2IrConverter = Fir2IrJvmResultsConverter(testServices)
|
||||
override fun transform(module: TestModule, inputArtifact: K1AndK2OutputArtifact): IrBackendInputsFromK1AndK2? {
|
||||
val irFromClassic = classicFrontend2IrConverter.transform(module, inputArtifact.k1Artifact)
|
||||
val irFromFir =
|
||||
runWithEnablingFirUseOption(testServices, module) { fir2IrConverter.transform(module, inputArtifact.k2Artifact) } ?: return null
|
||||
return IrBackendInputsFromK1AndK2(irFromClassic, irFromFir)
|
||||
}
|
||||
|
||||
override fun shouldRunAnalysis(module: TestModule): Boolean {
|
||||
return module.backendKind == BackendKinds.IrBackend
|
||||
}
|
||||
|
||||
}
|
||||
+5
-2
@@ -11,7 +11,6 @@ import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.ModulePath
|
||||
@@ -86,7 +85,11 @@ internal class MultiplatformSeparateAnalysisConfiguration(
|
||||
if (dependencies.isEmpty()) return
|
||||
for (dependency in dependencies) {
|
||||
val dependencyModule = dependencyProvider.getTestModule(dependency.moduleName)
|
||||
val artifact = dependencyProvider.getArtifact(dependencyModule, FrontendKinds.ClassicFrontend)
|
||||
val artifact = if (module.frontendKind == FrontendKinds.ClassicAndFIR) {
|
||||
dependencyProvider.getArtifact(dependencyModule, FrontendKinds.ClassicAndFIR).k1Artifact
|
||||
} else {
|
||||
dependencyProvider.getArtifact(dependencyModule, FrontendKinds.ClassicFrontend)
|
||||
}
|
||||
/*
|
||||
We need create KtFiles again with new project because otherwise we can access to some caches using
|
||||
old project as key which may leads to missing services in core environment
|
||||
|
||||
@@ -25,6 +25,11 @@ object BinaryArtifacts {
|
||||
get() = ArtifactKinds.Jvm
|
||||
}
|
||||
|
||||
class JvmFromK1AndK2(val fromK1: Jvm, val fromK2: Jvm) : ResultingArtifact.Binary<JvmFromK1AndK2>() {
|
||||
override val kind: BinaryKind<JvmFromK1AndK2>
|
||||
get() = ArtifactKinds.JvmFromK1AndK2
|
||||
}
|
||||
|
||||
sealed class Js : ResultingArtifact.Binary<Js>() {
|
||||
abstract val outputFile: File
|
||||
override val kind: BinaryKind<Js>
|
||||
|
||||
@@ -8,17 +8,21 @@ package org.jetbrains.kotlin.test.model
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendInput
|
||||
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
|
||||
import org.jetbrains.kotlin.test.backend.ir.IrBackendInputsFromK1AndK2
|
||||
import org.jetbrains.kotlin.test.frontend.K1AndK2OutputArtifact
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
|
||||
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
||||
|
||||
object FrontendKinds {
|
||||
object ClassicFrontend : FrontendKind<ClassicFrontendOutputArtifact>("ClassicFrontend")
|
||||
object FIR : FrontendKind<FirOutputArtifact>("FIR")
|
||||
object ClassicAndFIR : FrontendKind<K1AndK2OutputArtifact>("ClassicAndFIR")
|
||||
|
||||
fun fromString(string: String): FrontendKind<*>? {
|
||||
return when (string) {
|
||||
"ClassicFrontend" -> ClassicFrontend
|
||||
"FIR" -> FIR
|
||||
"ClassicAndFIR" -> ClassicAndFIR
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -35,6 +39,11 @@ object BackendKinds {
|
||||
*/
|
||||
object IrBackend : BackendKind<IrBackendInput>("IrBackend")
|
||||
|
||||
/**
|
||||
* The artifact kind representing two IRs, generated by K1 and K2 frontends respectively
|
||||
*/
|
||||
object IrBackendForK1AndK2 : BackendKind<IrBackendInputsFromK1AndK2>("TwoIrBackends")
|
||||
|
||||
/**
|
||||
* The artifact kind representing IR deserialized from a klib.
|
||||
*/
|
||||
@@ -58,6 +67,7 @@ object BackendKinds {
|
||||
|
||||
object ArtifactKinds {
|
||||
object Jvm : BinaryKind<BinaryArtifacts.Jvm>("JVM")
|
||||
object JvmFromK1AndK2 : BinaryKind<BinaryArtifacts.JvmFromK1AndK2>("JvmFromK1AndK2")
|
||||
object Js : BinaryKind<BinaryArtifacts.Js>("JS")
|
||||
object Native : BinaryKind<BinaryArtifacts.Native>("Native")
|
||||
object Wasm : BinaryKind<BinaryArtifacts.Wasm>("Wasm")
|
||||
@@ -70,6 +80,7 @@ object ArtifactKinds {
|
||||
"Native" -> Native
|
||||
"Wasm" -> Wasm
|
||||
"KLib" -> KLib
|
||||
"JvmFromK1AndK2" -> JvmFromK1AndK2
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.test.runners
|
||||
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.test.FirParser
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.backend.handlers.JvmAbiConsistencyHandler
|
||||
import org.jetbrains.kotlin.test.backend.ir.AbiCheckerSuppressor
|
||||
import org.jetbrains.kotlin.test.backend.ir.K1AndK2JvmIrBackendFacade
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
import org.jetbrains.kotlin.test.builders.configureJvmFromK1AndK2ArtifactHandlerStep
|
||||
import org.jetbrains.kotlin.test.builders.jvmFromK1AndK2ArtifactsHandlersStep
|
||||
import org.jetbrains.kotlin.test.directives.*
|
||||
import org.jetbrains.kotlin.test.frontend.K1AndK2ToIrConverter
|
||||
import org.jetbrains.kotlin.test.frontend.K1AndK2FrontendFacade
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.runners.codegen.commonServicesConfigurationForCodegenAndDebugTest
|
||||
import org.jetbrains.kotlin.test.services.configuration.JavaForeignAnnotationType
|
||||
import org.jetbrains.kotlin.test.services.configuration.JvmForeignAnnotationsConfigurator
|
||||
|
||||
open class AbstractJvmAbiConsistencyTest :
|
||||
AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR),
|
||||
RunnerWithTargetBackendForTestGeneratorMarker {
|
||||
|
||||
override fun TestConfigurationBuilder.configuration() {
|
||||
|
||||
commonServicesConfigurationForCodegenAndDebugTest(FrontendKinds.ClassicAndFIR)
|
||||
|
||||
defaultDirectives {
|
||||
FirDiagnosticsDirectives.FIR_PARSER with FirParser.Psi
|
||||
}
|
||||
|
||||
forTestsMatching("compiler/testData/codegen/bytecodeText/*") {
|
||||
defaultDirectives {
|
||||
+ConfigurationDirectives.WITH_STDLIB
|
||||
+JvmEnvironmentConfigurationDirectives.WITH_REFLECT
|
||||
}
|
||||
}
|
||||
|
||||
forTestsMatching("compiler/testData/codegen/boxModernJdk/*") {
|
||||
defaultDirectives {
|
||||
+ConfigurationDirectives.WITH_STDLIB
|
||||
+CodegenTestDirectives.USE_JAVAC_BASED_ON_JVM_TARGET
|
||||
+CodegenTestDirectives.IGNORE_DEXING
|
||||
}
|
||||
}
|
||||
|
||||
forTestsMatching("compiler/testData/codegen/boxModernJdk/testsWithJava11/*") {
|
||||
defaultDirectives {
|
||||
JvmEnvironmentConfigurationDirectives.JDK_KIND with TestJdkKind.FULL_JDK_11
|
||||
JvmEnvironmentConfigurationDirectives.JVM_TARGET with JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
|
||||
forTestsMatching("compiler/testData/codegen/boxModernJdk/testsWithJava17/*") {
|
||||
defaultDirectives {
|
||||
JvmEnvironmentConfigurationDirectives.JDK_KIND with TestJdkKind.FULL_JDK_17
|
||||
JvmEnvironmentConfigurationDirectives.JVM_TARGET with JvmTarget.JVM_17
|
||||
}
|
||||
}
|
||||
|
||||
forTestsMatching("compiler/testData/codegen/box/javaInterop/foreignAnnotationsTests/tests/*") {
|
||||
defaultDirectives {
|
||||
ForeignAnnotationsDirectives.ANNOTATIONS_PATH with JavaForeignAnnotationType.Annotations
|
||||
}
|
||||
useConfigurators(::JvmForeignAnnotationsConfigurator)
|
||||
}
|
||||
|
||||
useAfterAnalysisCheckers(
|
||||
::AbiCheckerSuppressor
|
||||
)
|
||||
|
||||
facadeStep(::K1AndK2FrontendFacade)
|
||||
facadeStep(::K1AndK2ToIrConverter)
|
||||
facadeStep(::K1AndK2JvmIrBackendFacade)
|
||||
|
||||
jvmFromK1AndK2ArtifactsHandlersStep {}
|
||||
|
||||
configureJvmFromK1AndK2ArtifactHandlerStep {
|
||||
useHandlers(::JvmAbiConsistencyHandler)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -44,7 +44,7 @@ fun <F : ResultingArtifact.FrontendOutput<F>, B : ResultingArtifact.BackendInput
|
||||
jvmArtifactsHandlersStep(init = {})
|
||||
}
|
||||
|
||||
private fun TestConfigurationBuilder.commonServicesConfigurationForCodegenAndDebugTest(targetFrontend: FrontendKind<*>) {
|
||||
fun TestConfigurationBuilder.commonServicesConfigurationForCodegenAndDebugTest(targetFrontend: FrontendKind<*>) {
|
||||
globalDefaults {
|
||||
frontend = targetFrontend
|
||||
targetPlatform = JvmPlatforms.defaultJvmPlatform
|
||||
|
||||
+20
-3
@@ -18,22 +18,39 @@ object JUnit5Assertions : AssertionsService() {
|
||||
val isTeamCityBuild: Boolean = System.getenv("TEAMCITY_VERSION") != null
|
||||
|
||||
override fun assertEqualsToFile(expectedFile: File, actual: String, sanitizer: (String) -> String, message: () -> String) {
|
||||
assertEqualsToFile(
|
||||
expectedFile,
|
||||
actual,
|
||||
sanitizer,
|
||||
differenceObtainedMessage = message,
|
||||
fileNotFoundMessageTeamCity = { "Expected data file did not exist `$expectedFile`" },
|
||||
fileNotFoundMessageLocal = { "Expected data file did not exist. Generating: $expectedFile" })
|
||||
}
|
||||
|
||||
fun assertEqualsToFile(
|
||||
expectedFile: File,
|
||||
actual: String,
|
||||
sanitizer: (String) -> String,
|
||||
differenceObtainedMessage: () -> String,
|
||||
fileNotFoundMessageTeamCity: (File) -> String,
|
||||
fileNotFoundMessageLocal: (File) -> String,
|
||||
) {
|
||||
try {
|
||||
val actualText = actual.trim { it <= ' ' }.convertLineSeparators().trimTrailingWhitespacesAndAddNewlineAtEOF()
|
||||
if (!expectedFile.exists()) {
|
||||
if (isTeamCityBuild) {
|
||||
org.junit.jupiter.api.fail("Expected data file did not exist `$expectedFile`")
|
||||
org.junit.jupiter.api.fail(fileNotFoundMessageTeamCity(expectedFile))
|
||||
} else {
|
||||
expectedFile.parentFile.mkdirs()
|
||||
expectedFile.writeText(actualText)
|
||||
org.junit.jupiter.api.fail("Expected data file did not exist. Generating: $expectedFile")
|
||||
org.junit.jupiter.api.fail(fileNotFoundMessageLocal(expectedFile))
|
||||
}
|
||||
}
|
||||
val expected = expectedFile.readText().convertLineSeparators()
|
||||
val expectedText = expected.trim { it <= ' ' }.trimTrailingWhitespacesAndAddNewlineAtEOF()
|
||||
if (sanitizer.invoke(expectedText) != sanitizer.invoke(actualText)) {
|
||||
throw FileComparisonFailure(
|
||||
"${message()}: ${expectedFile.name}",
|
||||
"${differenceObtainedMessage()}: ${expectedFile.name}",
|
||||
expected, actual, expectedFile.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -349,7 +349,7 @@ class ModuleStructureExtractorImpl(
|
||||
targetBackend = targetBackend,
|
||||
frontendKind = currentModuleFrontendKind ?: defaultsProvider.defaultFrontend,
|
||||
backendKind = BackendKinds.fromTargetBackend(targetBackend),
|
||||
binaryKind = defaultsProvider.defaultArtifactKind ?: targetPlatform.toArtifactKind(),
|
||||
binaryKind = defaultsProvider.defaultArtifactKind ?: targetPlatform.toArtifactKind(frontendKind),
|
||||
files = filesOfCurrentModule,
|
||||
allDependencies = dependenciesOfCurrentModule,
|
||||
directives = moduleDirectives,
|
||||
|
||||
+9
-9
@@ -11,10 +11,7 @@ import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.platform.konan.NativePlatforms
|
||||
import org.jetbrains.kotlin.test.directives.model.ComposedRegisteredDirectives
|
||||
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
|
||||
import org.jetbrains.kotlin.test.model.BinaryKind
|
||||
import org.jetbrains.kotlin.test.model.ArtifactKinds
|
||||
import org.jetbrains.kotlin.test.model.DependencyKind
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
import org.jetbrains.kotlin.test.services.TestModuleStructure
|
||||
import java.io.File
|
||||
|
||||
@@ -52,11 +49,14 @@ class TestModuleStructureImpl(
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun TargetPlatform.toArtifactKind(): BinaryKind<*> = when (this) {
|
||||
in JvmPlatforms.allJvmPlatforms -> ArtifactKinds.Jvm
|
||||
in JsPlatforms.allJsPlatforms -> ArtifactKinds.Js
|
||||
in NativePlatforms.allNativePlatforms -> ArtifactKinds.Native
|
||||
else -> BinaryKind.NoArtifact
|
||||
fun TargetPlatform.toArtifactKind(frontendKind: FrontendKind<out ResultingArtifact.FrontendOutput<*>>): BinaryKind<*> {
|
||||
if (frontendKind == FrontendKinds.ClassicAndFIR && this in JvmPlatforms.allJvmPlatforms) return ArtifactKinds.JvmFromK1AndK2
|
||||
return when (this) {
|
||||
in JvmPlatforms.allJvmPlatforms -> ArtifactKinds.Jvm
|
||||
in JsPlatforms.allJsPlatforms -> ArtifactKinds.Js
|
||||
in NativePlatforms.allNativePlatforms -> ArtifactKinds.Native
|
||||
else -> BinaryKind.NoArtifact
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-3
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.output.writeAll
|
||||
import org.jetbrains.kotlin.codegen.ClassFileFactory
|
||||
import org.jetbrains.kotlin.test.model.ArtifactKinds
|
||||
import org.jetbrains.kotlin.test.model.FrontendKind
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
import java.io.File
|
||||
@@ -17,14 +19,24 @@ import java.io.File
|
||||
class CompiledClassesManager(val testServices: TestServices) : TestService {
|
||||
private val compiledKotlinCache = mutableMapOf<TestModule, File>()
|
||||
private val compiledJavaCache = mutableMapOf<TestModule, File>()
|
||||
var specifiedFrontendKind: FrontendKind<*> = FrontendKind.NoFrontend
|
||||
|
||||
fun getCompiledKotlinDirForModule(module: TestModule, classFileFactory: ClassFileFactory? = null): File {
|
||||
return compiledKotlinCache.getOrPut(module) {
|
||||
val outputDir = testServices.getOrCreateTempDirectory("module_${module.name}_kotlin-classes")
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val classFileFactory = classFileFactory
|
||||
?: testServices.dependencyProvider.getArtifact(module, ArtifactKinds.Jvm).classFileFactory
|
||||
val classFileFactory = classFileFactory ?: if (module.binaryKind == ArtifactKinds.JvmFromK1AndK2) {
|
||||
require(specifiedFrontendKind == FrontendKinds.FIR || specifiedFrontendKind == FrontendKinds.ClassicFrontend)
|
||||
val k1AndK2Artifact = testServices.dependencyProvider.getArtifact(module, ArtifactKinds.JvmFromK1AndK2)
|
||||
if (specifiedFrontendKind == FrontendKinds.FIR) {
|
||||
k1AndK2Artifact.fromK2.classFileFactory
|
||||
} else {
|
||||
k1AndK2Artifact.fromK1.classFileFactory
|
||||
}
|
||||
} else {
|
||||
testServices.dependencyProvider.getArtifact(module, ArtifactKinds.Jvm).classFileFactory
|
||||
}
|
||||
val outputFileCollection = SimpleOutputFileCollection(classFileFactory.currentOutput)
|
||||
val messageCollector = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
@@ -44,4 +56,4 @@ class CompiledClassesManager(val testServices: TestServices) : TestService {
|
||||
}
|
||||
}
|
||||
|
||||
val TestServices.compiledClassesManager: CompiledClassesManager by TestServices.testServiceAccessor()
|
||||
val TestServices.compiledClassesManager: CompiledClassesManager by TestServices.testServiceAccessor()
|
||||
Reference in New Issue
Block a user