[Test] Use IrPluginContext for searching declarations for DUMP_EXTERNAL_CLASS check

This commit is contained in:
Dmitriy Novozhilov
2022-12-05 12:55:24 +02:00
committed by Space Team
parent e7f6482857
commit 5d6cb2b691
44 changed files with 1128 additions and 501 deletions
@@ -5,22 +5,13 @@
package org.jetbrains.kotlin.test.backend.handlers
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.dumpTreesFromLineNumber
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_EXTERNAL_CLASS
@@ -43,9 +34,15 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ
companion object {
const val DUMP_EXTENSION = "ir.txt"
fun computeDumpExtension(module: TestModule, defaultExtension: String): String {
return if (module.frontendKind == FrontendKinds.ClassicFrontend || FIR_IDENTICAL in module.directives)
defaultExtension else "fir.$defaultExtension"
fun computeDumpExtension(module: TestModule, defaultExtension: String, ignoreFirIdentical: Boolean = false): String {
return if (
module.frontendKind == FrontendKinds.ClassicFrontend ||
(!ignoreFirIdentical && FIR_IDENTICAL in module.directives)
) {
defaultExtension
} else {
"fir.$defaultExtension"
}
}
fun List<IrFile>.groupWithTestFiles(module: TestModule): List<Pair<TestFile?, IrFile>> = mapNotNull { irFile ->
@@ -61,7 +58,6 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ
private val baseDumper = MultiModuleInfoDumper()
private val buildersForSeparateFileDumps: MutableMap<File, StringBuilder> = mutableMapOf()
@OptIn(ExperimentalStdlibApi::class)
override fun processModule(module: TestModule, info: IrBackendInput) {
if (DUMP_IR !in module.directives) return
val irFiles = info.irModuleFragment.files
@@ -79,42 +75,27 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ
}
private fun compareDumpsOfExternalClasses(module: TestModule, info: IrBackendInput) {
// FIR doesn't support searching descriptors
if (module.frontendKind == FrontendKinds.FIR) return
val externalClassFqns = module.directives[DUMP_EXTERNAL_CLASS]
if (externalClassFqns.isEmpty()) return
// TODO: why JS one is used here in original AbstractIrTextTestCase?
val mangler = JsManglerDesc
val signaturer = IdSignatureDescriptor(mangler)
val irModule = info.irModuleFragment
val stubGenerator = DeclarationStubGeneratorImpl(
irModule.descriptor,
SymbolTable(signaturer, IrFactoryImpl), // TODO
irModule.irBuiltins,
DescriptorByIdSignatureFinderImpl(irModule.descriptor, mangler)
)
val externalClassIds = module.directives[DUMP_EXTERNAL_CLASS]
if (externalClassIds.isEmpty()) return
val baseFile = testServices.moduleStructure.originalTestDataFiles.first()
for (externalClassFqn in externalClassFqns) {
val classDump = stubGenerator.generateExternalClass(irModule.descriptor, externalClassFqn).dump()
val expectedFile = baseFile.withSuffixAndExtension(".__$externalClassFqn", module.dumpExtension)
for (externalClassId in externalClassIds) {
val classDump = info.irPluginContext.findExternalClass(externalClassId).dump()
val suffix = ".__${externalClassId.replace("/", ".")}"
val expectedFile = baseFile.withSuffixAndExtension(suffix, module.getDumpExtension(ignoreFirIdentical = true))
assertions.assertEqualsToFile(expectedFile, classDump)
}
}
private fun DeclarationStubGenerator.generateExternalClass(descriptor: ModuleDescriptor, externalClassFqn: String): IrClass {
val classDescriptor =
descriptor.findClassAcrossModuleDependencies(ClassId.topLevel(FqName(externalClassFqn)))
?: throw AssertionError("Can't find a class in external dependencies: $externalClassFqn")
return generateMemberStub(classDescriptor) as IrClass
private fun IrPluginContext.findExternalClass(externalClassId: String): IrClass {
val classId = ClassId.fromString(externalClassId)
return referenceClass(classId)?.owner ?: assertions.fail { "Can't find a class in external dependencies: $externalClassId" }
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
val moduleStructure = testServices.moduleStructure
val defaultExpectedFile = moduleStructure.originalTestDataFiles.first().withExtension(moduleStructure.modules.first().dumpExtension)
val defaultExpectedFile = moduleStructure.originalTestDataFiles.first()
.withExtension(moduleStructure.modules.first().getDumpExtension())
checkOneExpectedFile(defaultExpectedFile, baseDumper.generateResultingDump())
buildersForSeparateFileDumps.entries.forEach { (expectedFile, dump) -> checkOneExpectedFile(expectedFile, dump.toString()) }
}
@@ -125,6 +106,7 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ
}
}
private val TestModule.dumpExtension: String
get() = computeDumpExtension(this, DUMP_EXTENSION)
private fun TestModule.getDumpExtension(ignoreFirIdentical: Boolean = false): String {
return computeDumpExtension(this, DUMP_EXTENSION, ignoreFirIdentical)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.backend.ir
import org.jetbrains.kotlin.KtSourceFile
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -24,8 +25,14 @@ sealed class IrBackendInput : ResultingArtifact.BackendInput<IrBackendInput>() {
abstract val irModuleFragment: IrModuleFragment
/*
* Here plugin context can be used as a service for inspecting resulting IR module
*/
abstract val irPluginContext: IrPluginContext
data class JsIrBackendInput(
override val irModuleFragment: IrModuleFragment,
override val irPluginContext: IrPluginContext,
val sourceFiles: List<KtSourceFile>,
val icData: List<KotlinFileSerializedData>,
val expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>, // TODO: abstract from descriptors
@@ -41,5 +48,8 @@ sealed class IrBackendInput : ResultingArtifact.BackendInput<IrBackendInput>() {
) : IrBackendInput() {
override val irModuleFragment: IrModuleFragment
get() = backendInput.irModuleFragment
override val irPluginContext: IrPluginContext
get() = backendInput.pluginContext
}
}
@@ -64,10 +64,12 @@ class ClassicFrontend2IrConverter(
.diagnosticReporter(DiagnosticReporterFactory.createReporter())
.build()
val convertionResult =
codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationStateAndFiles(state, psiFiles.values))
return IrBackendInput.JvmIrBackendInput(
state,
codegenFactory,
codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationStateAndFiles(state, psiFiles.values)),
convertionResult,
emptyList()
)
}
@@ -81,7 +83,7 @@ class ClassicFrontend2IrConverter(
val sourceFiles = psiFiles.values.toList()
val icData = configuration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList()
val expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val moduleFragment = generateIrForKlibSerialization(
val (moduleFragment, pluginContext) = generateIrForKlibSerialization(
project,
sourceFiles,
configuration,
@@ -101,6 +103,7 @@ class ClassicFrontend2IrConverter(
return IrBackendInput.JsIrBackendInput(
moduleFragment,
pluginContext,
sourceFiles.map(::KtPsiSourceFile),
icData,
expectDescriptorToSymbol = expectDescriptorToSymbol,
@@ -68,7 +68,7 @@ class Fir2IrJsResultsConverter(
val fir2IrExtensions = Fir2IrExtensions.Default
val firFiles = inputArtifact.allFirFiles.values
val (irModuleFragment, components) =
val (irModuleFragment, components, pluginContext) =
inputArtifact.firAnalyzerFacade.convertToJsIr(firFiles, fir2IrExtensions, module, configuration, testServices)
val sourceFiles = firFiles.mapNotNull { it.sourceFile }
@@ -86,6 +86,7 @@ class Fir2IrJsResultsConverter(
return IrBackendInput.JsIrBackendInput(
irModuleFragment,
pluginContext,
sourceFiles,
icData,
expectDescriptorToSymbol,
@@ -44,7 +44,7 @@ class Fir2IrResultsConverter(
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
val fir2IrExtensions = JvmFir2IrExtensions(configuration, JvmIrDeserializerImpl(), JvmIrMangler)
val (irModuleFragment, components) = inputArtifact.firAnalyzerFacade.convertToIr(fir2IrExtensions)
val (irModuleFragment, components, pluginContext) = inputArtifact.firAnalyzerFacade.convertToIr(fir2IrExtensions)
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)
@@ -82,6 +82,7 @@ class Fir2IrResultsConverter(
components.irProviders,
fir2IrExtensions,
FirJvmBackendExtension(inputArtifact.session, components),
pluginContext,
notifyCodegenStart = {},
),
sourceFiles