[Test] Add Fir Identical checkers for signature dump handler

This commit is contained in:
Dmitriy Novozhilov
2024-02-16 10:21:52 +02:00
committed by Space Team
parent e3dc0f0fa3
commit d1e7b9b4cf
7 changed files with 143 additions and 77 deletions
@@ -1,23 +0,0 @@
// CHECK:
// Mangled name: A
// Public signature: /A|null[0]
class A : Java1 {
// CHECK:
// Mangled name: A#<init>(){}
// Public signature: /A.<init>|-5645683436151566731[0]
// Public signature debug description: <init>(){}
constructor() /* primary */
// CHECK JVM_IR:
// Mangled name: A#bar(){}List?
// Public signature: /A.bar|-6805136188302315839[0]
// Public signature debug description: bar(){}List?
/* fake */ override fun bar(): List?
// CHECK:
// Mangled name: A#foo(List?){}
// Public signature: /A.foo|-6260703452578085119[0]
// Public signature debug description: foo(List?){}
/* fake */ override fun foo(a: List?): Unit
}
@@ -1,7 +1,6 @@
// FIR_IDENTICAL
// ISSUE: KT-65298
// TARGET_BACKEND: JVM
// SEPARATE_SIGNATURE_DUMP_FOR_K2
// FILE: Java1.java
public class Java1 {
@@ -11,4 +10,4 @@ public class Java1 {
// FILE: 1.kt
class A : Java1() {
}
}
@@ -1,44 +0,0 @@
/*
* 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 org.jetbrains.kotlin.test.WrappedException
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.utils.FirIdenticalCheckerHelper
import org.jetbrains.kotlin.test.utils.withExtension
import java.io.File
class FirIrSourceRangesIdenticalChecker(testServices: TestServices) : AfterAnalysisChecker(testServices) {
override val directiveContainers: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives)
private val simpleChecker = object : FirIdenticalCheckerHelper(testServices) {
override fun getClassicFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension(IrSourceRangesDumpHandler.DUMP_EXTENSION).takeIf { it.exists() }
}
override fun getFirFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension("fir.${IrSourceRangesDumpHandler.DUMP_EXTENSION}").takeIf { it.exists() }
}
}
override fun check(failedAssertions: List<WrappedException>) {
if (failedAssertions.isNotEmpty()) return
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
if (FirDiagnosticsDirectives.FIR_IDENTICAL in testServices.moduleStructure.allDirectives) {
simpleChecker.deleteFirFile(testDataFile)
return
}
if (simpleChecker.firAndClassicContentsAreEquals(testDataFile)) {
simpleChecker.deleteFirFile(testDataFile)
simpleChecker.addDirectiveToClassicFileAndAssert(testDataFile)
}
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.codegenSuppressionChecker
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_SIGNATURE
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.MUTE_SIGNATURE_COMPARISON_K2
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.SEPARATE_SIGNATURE_DUMP_FOR_K2
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.FIR_IDENTICAL
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.model.BackendKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule
@@ -103,11 +105,32 @@ class IrMangledNameAndSignatureDumpHandler(
companion object {
const val DUMP_EXTENSION = "sig.kt.txt"
private fun separateSignatureDirectiveNotPresent(testServices: TestServices): Boolean {
return SEPARATE_SIGNATURE_DUMP_FOR_K2 !in testServices.moduleStructure.allDirectives
}
}
override val additionalAfterAnalysisCheckers: List<Constructor<AfterAnalysisChecker>>
get() = listOf(::IdenticalChecker)
class IdenticalChecker(testServices: TestServices) : SimpleFirIrIdenticalChecker(testServices) {
override val dumpExtension: String
get() = DUMP_EXTENSION
override fun markedAsIdentical(): Boolean {
return separateSignatureDirectiveNotPresent(testServices)
}
override fun processClassicFileIfContentIsIdentical(testDataFile: File) {
simpleChecker.removeDirectiveFromClassicFileAndAssert(testDataFile, SEPARATE_SIGNATURE_DUMP_FOR_K2)
}
}
private fun computeDumpExtension(): String {
return if (testServices.defaultsProvider.defaultFrontend == FrontendKinds.ClassicFrontend ||
SEPARATE_SIGNATURE_DUMP_FOR_K2 !in testServices.moduleStructure.allDirectives
return if (
testServices.defaultsProvider.defaultFrontend == FrontendKinds.ClassicFrontend ||
separateSignatureDirectiveNotPresent(testServices)
) {
DUMP_EXTENSION
} else {
@@ -40,7 +40,16 @@ class IrSourceRangesDumpHandler(
get() = listOf(CodegenTestDirectives, FirDiagnosticsDirectives)
override val additionalAfterAnalysisCheckers: List<Constructor<AfterAnalysisChecker>>
get() = listOf(::FirIrSourceRangesIdenticalChecker)
get() = listOf(::IdenticalChecker)
class IdenticalChecker(testServices: TestServices) : SimpleFirIrIdenticalChecker(testServices) {
override val dumpExtension: String
get() = DUMP_EXTENSION
override fun shouldRun(): Boolean {
return CodegenTestDirectives.DUMP_SOURCE_RANGES_IR in testServices.moduleStructure.allDirectives
}
}
private val baseDumper = MultiModuleInfoDumper()
private val buildersForSeparateFileDumps: MutableMap<File, StringBuilder> = mutableMapOf()
@@ -0,0 +1,73 @@
/*
* 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 org.jetbrains.kotlin.test.WrappedException
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.utils.FirIdenticalCheckerHelper
import org.jetbrains.kotlin.test.utils.withExtension
import java.io.File
/**
* Use this checker as a base class if you need to check if K1 and K2 dumps are the same
* and add/remove some directive to the testdata file if they actually are
*
* Format of dump filename:
* - K1: `testName.dumpExtension`
* - K2: `testName.fir.dumpExtension`
*
* By default, this checker uses existence of `FIR_IDENTICAL` directive as a marker that dumps are identical
* This behavior can be tweaked by overriding [markedAsIdentical] and [processClassicFileIfContentIsIdentical] functions
*
* For example, [IrMangledNameAndSignatureDumpHandler.IdenticalChecker] uses lack of `SEPARATE_SIGNATURE_DUMP_FOR_K2` directive
* for this purpose
*/
abstract class SimpleFirIrIdenticalChecker(testServices: TestServices) : AfterAnalysisChecker(testServices) {
protected abstract val dumpExtension: String
override val directiveContainers: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives)
protected val simpleChecker = object : FirIdenticalCheckerHelper(testServices) {
override fun getClassicFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension(dumpExtension).takeIf { it.exists() }
}
override fun getFirFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension("fir.${dumpExtension}").takeIf { it.exists() }
}
}
protected open fun shouldRun(): Boolean {
return true
}
override fun check(failedAssertions: List<WrappedException>) {
if (!shouldRun()) return
if (failedAssertions.isNotEmpty()) return
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
if (markedAsIdentical()) {
simpleChecker.deleteFirFile(testDataFile)
return
}
if (simpleChecker.firAndClassicContentsAreEquals(testDataFile)) {
simpleChecker.deleteFirFile(testDataFile)
processClassicFileIfContentIsIdentical(testDataFile)
}
}
protected open fun markedAsIdentical(): Boolean {
return FirDiagnosticsDirectives.FIR_IDENTICAL in testServices.moduleStructure.allDirectives
}
protected open fun processClassicFileIfContentIsIdentical(testDataFile: File) {
simpleChecker.addDirectiveToClassicFileAndAssert(testDataFile)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.utils
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.Directive
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
@@ -13,7 +14,7 @@ import java.io.File
abstract class FirIdenticalCheckerHelper(private val testServices: TestServices) {
companion object {
private val isTeamCityBuild: Boolean = System.getenv("TEAMCITY_VERSION") != null
val isTeamCityBuild: Boolean = System.getenv("TEAMCITY_VERSION") != null
}
abstract fun getClassicFileToCompare(testDataFile: File): File?
@@ -39,19 +40,47 @@ abstract class FirIdenticalCheckerHelper(private val testServices: TestServices)
}
}
fun addDirectiveToClassicFileAndAssert(testDataFile: File) {
fun addDirectiveToClassicFileAndAssert(testDataFile: File, directiveToAdd: Directive = FirDiagnosticsDirectives.FIR_IDENTICAL) {
if (!isTeamCityBuild) {
val classicFileContent = testDataFile.readText()
testDataFile.writer().use {
it.appendLine("// ${FirDiagnosticsDirectives.FIR_IDENTICAL.name}")
it.appendLine("// ${directiveToAdd.name}")
it.append(classicFileContent)
}
}
val directiveName = directiveToAdd.name
val message = if (isTeamCityBuild) {
"Please remove .fir.txt dump and add // FIR_IDENTICAL to test source"
"Please remove .fir.txt dump and add // $directiveName to test source"
} else {
"Deleted .fir.txt dump, added // FIR_IDENTICAL to test source"
"Deleted .fir.txt dump, added // $directiveName to test source"
}
testServices.assertions.fail {
"""
Dumps via FIR & via old FE are the same.
$message
Please re-run the test now
""".trimIndent()
}
}
fun removeDirectiveFromClassicFileAndAssert(testDataFile: File, directiveToRemove: Directive) {
val directiveName = directiveToRemove.name
if (!isTeamCityBuild) {
val classicFileContent = testDataFile.readLines()
testDataFile.writer().use {
classicFileContent.forEachIndexed { index, line ->
if (line.startsWith("// $directiveName")) return@forEachIndexed
// Don't add empty line at the end, if last line is empty already
if (index == classicFileContent.size - 1 && line.isBlank()) return@forEachIndexed
it.appendLine(line)
}
}
}
val message = if (isTeamCityBuild) {
"Please remove .fir.txt dump and remove // $directiveName from test source"
} else {
"Deleted .fir.txt dump, removed // $directiveName from test source"
}
testServices.assertions.fail {
"""