[stub builder] introduce a separate testsuite where classfiles generated by the K2 compiler

The result of k1/k2 should be similar here, the differences should be fixed by KT-60764
This commit is contained in:
Ilya Kirillov
2023-07-27 14:13:08 +02:00
committed by Space Team
parent 2ab73f286a
commit 419c0c83e3
7 changed files with 123 additions and 8 deletions
@@ -0,0 +1,10 @@
/*
* 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.analysis.decompiler.stub.files
abstract class AbstractAdditionalStubInfoK2CompilerTest : AbstractAdditionalStubInfoTest() {
override val useK2ToCompileCode = true
}
@@ -22,7 +22,8 @@ abstract class AbstractAdditionalStubInfoTest : AbstractDecompiledClassTest() {
val stub = KotlinClsStubBuilder().buildFileStub(FileContentImpl.createByFile(getClassFileToDecompile(testData, false)))!! val stub = KotlinClsStubBuilder().buildFileStub(FileContentImpl.createByFile(getClassFileToDecompile(testData, false)))!!
val builder = StringBuilder() val builder = StringBuilder()
extractAdditionInfo(stub, builder, 0) extractAdditionInfo(stub, builder, 0)
KotlinTestUtils.assertEqualsToFile(testData.expectedFile, builder.toString()) KotlinTestUtils.assertEqualsToFile(testData.getExpectedFile(useK2ToCompileCode), builder.toString())
testData.checkIfIdentical(useK2ToCompileCode)
} }
private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, level: Int) { private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, level: Int) {
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2022 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.analysis.decompiler.stub.files
abstract class AbstractClsStubBuilderK2CompilerTest : AbstractClsStubBuilderTest() {
override val useK2ToCompileCode: Boolean = true
}
@@ -9,23 +9,29 @@ import com.intellij.core.CoreApplicationEnvironment
import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import org.jetbrains.kotlin.analysis.decompiler.stub.file.CachedAttributeData
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
import org.jetbrains.kotlin.analysis.decompiler.stub.file.DummyFileAttributeService import org.jetbrains.kotlin.analysis.decompiler.stub.file.DummyFileAttributeService
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.test.* import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.utils.FirIdenticalCheckerHelper
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.DataInput
import java.io.DataOutput
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.util.stream.Collectors import java.util.stream.Collectors
import kotlin.io.path.absolutePathString import kotlin.io.path.absolutePathString
import kotlin.io.path.name import kotlin.io.path.name
import kotlin.io.path.readText import kotlin.io.path.readText
import org.jetbrains.kotlin.test.services.JUnit5Assertions
import java.io.File
import org.jetbrains.kotlin.test.services.AssertionsService
abstract class AbstractDecompiledClassTest : KotlinTestWithEnvironment() { abstract class AbstractDecompiledClassTest : KotlinTestWithEnvironment() {
protected open val useK2ToCompileCode: Boolean = false
override fun createEnvironment(): KotlinCoreEnvironment { override fun createEnvironment(): KotlinCoreEnvironment {
return KotlinTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations( return KotlinTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(
ApplicationEnvironmentDisposer.ROOT_DISPOSABLE, ApplicationEnvironmentDisposer.ROOT_DISPOSABLE,
@@ -55,6 +61,7 @@ abstract class AbstractDecompiledClassTest : KotlinTestWithEnvironment() {
this.add("-Xuse-type-table") this.add("-Xuse-type-table")
} }
this.addAll(testData.additionalCompilerOptions) this.addAll(testData.additionalCompilerOptions)
addAll(listOf("-language-version", getLanguageVersionToCompile().versionString))
} }
val library = CompilerTestUtil.compileJvmLibrary( val library = CompilerTestUtil.compileJvmLibrary(
src = testData.directory.toFile(), src = testData.directory.toFile(),
@@ -65,6 +72,16 @@ abstract class AbstractDecompiledClassTest : KotlinTestWithEnvironment() {
) )
} }
private fun getLanguageVersionToCompile(): LanguageVersion {
return if (useK2ToCompileCode) {
val k2Version = maxOf(LanguageVersion.LATEST_STABLE, LanguageVersion.KOTLIN_2_0)
check(k2Version.usesK2)
k2Version
} else {
LanguageVersion.KOTLIN_1_9
}
}
private fun findClassFileByName(library: Path, className: String): VirtualFile { private fun findClassFileByName(library: Path, className: String): VirtualFile {
val jarFileSystem = environment.projectEnvironment.environment.jarFileSystem as CoreJarFileSystem val jarFileSystem = environment.projectEnvironment.environment.jarFileSystem as CoreJarFileSystem
val root = jarFileSystem.refreshAndFindFileByPath(library.absolutePathString() + "!/")!! val root = jarFileSystem.refreshAndFindFileByPath(library.absolutePathString() + "!/")!!
@@ -93,6 +110,37 @@ internal data class TestData(
val jvmFileName: String, val jvmFileName: String,
val additionalCompilerOptions: List<String>, val additionalCompilerOptions: List<String>,
) { ) {
fun containsDirective(directive: String): Boolean {
return InTextDirectivesUtils.isDirectiveDefined(mainKotlinFile.readText(), "// $directive")
}
fun <R : Any> withFirIgnoreDirective(action: () -> R): R? {
val directive = "FIR_IGNORE"
if (containsDirective(directive)) return null
return action()
}
fun getExpectedFile(useK2: Boolean): Path {
if (useK2) {
IdenticalCheckerHelper.getFirFileToCompare(expectedFile.toFile()).takeIf { it.exists() }?.let { return it.toPath() }
}
return expectedFile
}
fun checkIfIdentical(useK2: Boolean) {
if (containsDirective(FirDiagnosticsDirectives.FIR_IDENTICAL.name)) {
return
}
if (useK2) {
if (IdenticalCheckerHelper.firAndClassicContentsAreEquals(expectedFile.toFile())) {
IdenticalCheckerHelper.deleteFirFile(expectedFile.toFile())
IdenticalCheckerHelper.addDirectiveToClassicFileAndAssert(mainKotlinFile.toFile())
}
}
}
companion object { companion object {
fun createFromDirectory(directory: Path): TestData { fun createFromDirectory(directory: Path): TestData {
val allFiles = Files.list(directory).collect(Collectors.toList()) val allFiles = Files.list(directory).collect(Collectors.toList())
@@ -111,5 +159,23 @@ internal data class TestData(
) )
} }
} }
private object IdenticalCheckerHelper : FirIdenticalCheckerHelper(
TestServices().apply {
register(AssertionsService::class, JUnit5Assertions)
}
) {
override fun getClassicFileToCompare(testDataFile: File): File {
val path = testDataFile.toPath()
val fileNameWithoutExtension = path.fileName.toString().removeSuffix(".k2.txt").removeSuffix(".txt")
return path.parent.resolve("$fileNameWithoutExtension.txt").toFile()
}
override fun getFirFileToCompare(testDataFile: File): File {
val path = testDataFile.toPath()
val fileNameWithoutExtension = path.fileName.toString().removeSuffix(".k2.txt").removeSuffix(".txt")
return path.parent.resolve("$fileNameWithoutExtension.k2.txt").toFile()
}
}
} }
@@ -19,9 +19,10 @@ abstract class AbstractStubBuilderTest : AbstractDecompiledClassTest() {
fun runTest(testDirectory: String) { fun runTest(testDirectory: String) {
val testDirectoryPath = Paths.get(testDirectory) val testDirectoryPath = Paths.get(testDirectory)
val testData = TestData.createFromDirectory(testDirectoryPath) val testData = TestData.createFromDirectory(testDirectoryPath)
testData.withFirIgnoreDirective {
doTest(testData, useStringTable = true) doTest(testData, useStringTable = true)
doTest(testData, useStringTable = false) doTest(testData, useStringTable = false)
}
} }
@@ -31,7 +32,9 @@ abstract class AbstractStubBuilderTest : AbstractDecompiledClassTest() {
} }
private fun testClsStubsForFile(classFile: VirtualFile, testData: TestData) { private fun testClsStubsForFile(classFile: VirtualFile, testData: TestData) {
KotlinTestUtils.assertEqualsToFile(testData.expectedFile, getStubToTest(classFile).serializeToString()) val stub = getStubToTest(classFile)
KotlinTestUtils.assertEqualsToFile(testData.getExpectedFile(useK2ToCompileCode), stub.serializeToString())
testData.checkIfIdentical(useK2ToCompileCode)
} }
protected abstract fun getStubToTest(classFile: VirtualFile): PsiFileStub<*> protected abstract fun getStubToTest(classFile: VirtualFile): PsiFileStub<*>
@@ -0,0 +1,10 @@
/*
* 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.analysis.decompiler.psi
abstract class AbstractByDecompiledPsiStubBuilderK2CompilerTest : AbstractByDecompiledPsiStubBuilderTest() {
override val useK2ToCompileCode: Boolean = true
}
@@ -5,8 +5,11 @@
package org.jetbrains.kotlin.generators.tests.analysis.api package org.jetbrains.kotlin.generators.tests.analysis.api
import org.jetbrains.kotlin.analysis.decompiler.psi.AbstractByDecompiledPsiStubBuilderK2CompilerTest
import org.jetbrains.kotlin.analysis.decompiler.psi.AbstractByDecompiledPsiStubBuilderTest import org.jetbrains.kotlin.analysis.decompiler.psi.AbstractByDecompiledPsiStubBuilderTest
import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractAdditionalStubInfoK2CompilerTest
import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractAdditionalStubInfoTest import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractAdditionalStubInfoTest
import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractClsStubBuilderK2CompilerTest
import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractClsStubBuilderTest import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractClsStubBuilderTest
import org.jetbrains.kotlin.generators.TestGroupSuite import org.jetbrains.kotlin.generators.TestGroupSuite
@@ -18,6 +21,10 @@ internal fun TestGroupSuite.generateDecompiledTests() {
testClass<AbstractClsStubBuilderTest> { testClass<AbstractClsStubBuilderTest> {
model("clsFileStubBuilder", extension = null, recursive = false) model("clsFileStubBuilder", extension = null, recursive = false)
} }
testClass<AbstractClsStubBuilderK2CompilerTest> {
model("clsFileStubBuilder", extension = null, recursive = false)
}
} }
testGroup( testGroup(
@@ -27,6 +34,10 @@ internal fun TestGroupSuite.generateDecompiledTests() {
testClass<AbstractAdditionalStubInfoTest> { testClass<AbstractAdditionalStubInfoTest> {
model("additionalClsStubInfo", extension = null, recursive = false) model("additionalClsStubInfo", extension = null, recursive = false)
} }
testClass<AbstractAdditionalStubInfoK2CompilerTest> {
model("additionalClsStubInfo", extension = null, recursive = false)
}
} }
testGroup( testGroup(
@@ -36,5 +47,9 @@ internal fun TestGroupSuite.generateDecompiledTests() {
testClass<AbstractByDecompiledPsiStubBuilderTest> { testClass<AbstractByDecompiledPsiStubBuilderTest> {
model("clsFileStubBuilder", extension = null, recursive = false) model("clsFileStubBuilder", extension = null, recursive = false)
} }
testClass<AbstractByDecompiledPsiStubBuilderK2CompilerTest> {
model("clsFileStubBuilder", extension = null, recursive = false)
}
} }
} }