diff --git a/compiler/testData/checkLocalVariablesTable/localFun.kt b/compiler/testData/checkLocalVariablesTable/localFun.kt index f893c74d7cd..b69677cfe1e 100644 --- a/compiler/testData/checkLocalVariablesTable/localFun.kt +++ b/compiler/testData/checkLocalVariablesTable/localFun.kt @@ -1,8 +1,18 @@ -// IGNORE_BACKEND: JVM_IR fun foo() { + val x = 1 fun bar() { + val y = x } } +// Local function bodies are in a separate class (implementing FunctionN) for non-IR, and are static methods in the enclosing class for IR. + +// JVM_TEMPLATES // METHOD : LocalFunKt$foo$1.invoke()V +// VARIABLE : NAME=y TYPE=I INDEX=1 // VARIABLE : NAME=this TYPE=LLocalFunKt$foo$1; INDEX=0 + +// JVM_IR_TEMPLATES +// METHOD : LocalFunKt.foo$bar(I)V +// VARIABLE : NAME=y TYPE=I INDEX=1 +// VARIABLE : NAME=$x TYPE=I INDEX=0 diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.kt index fedfc4d6140..162585c2afb 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractCheckLocalVariablesTableTest.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.codegen +import com.intellij.openapi.util.Comparing import com.intellij.openapi.util.text.StringUtil import junit.framework.TestCase import org.jetbrains.kotlin.backend.common.output.OutputFileCollection -import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.org.objectweb.asm.* +import org.junit.ComparisonFailure import java.io.File import java.util.* import java.util.regex.Pattern @@ -33,43 +35,85 @@ abstract class AbstractCheckLocalVariablesTableTest : CodegenTestCase() { compile(files) try { - val classAndMethod = parseClassAndMethodSignature(wholeFile) + val filteredLines = filterTestFileForTargetBackend(wholeFile) + val classAndMethod = parseClassAndMethodSignature(filteredLines) val split = classAndMethod.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() assert(split.size == 2) { "Exactly one dot is expected: $classAndMethod" } val classFileRegex = StringUtil.escapeToRegexp(split[0] + ".class").replace("\\*", ".+") val methodName = split[1] val outputFiles = (classFileFactory as OutputFileCollection).asList() - val outputFile = outputFiles.first { file -> file.relativePath.matches(classFileRegex.toRegex()) } - - val pathsString = outputFiles.joinToString { it.relativePath } - assertNotNull("Couldn't find class file for pattern $classFileRegex in: $pathsString", outputFile) + val outputFile = outputFiles.firstOrNull { file -> file.relativePath.matches(classFileRegex.toRegex()) } + checkNotNull(outputFile) { + val pathsString = outputFiles.joinToString { it.relativePath } + "Couldn't find class file for pattern $classFileRegex in: $pathsString" + } val classReader = ClassReader(outputFile.asByteArray()) val actualLocalVariables = readLocalVariable(classReader, methodName) checkLocalVariableTypes(classReader, methodName, actualLocalVariables) - doCompare(wholeFile, files.single().content, actualLocalVariables) + doCompare(filteredLines, actualLocalVariables) } catch (e: Throwable) { printReport(wholeFile) throw e } } - protected open fun doCompare( - testFile: File, - text: String, - actualLocalVariables: List - ) { - KotlinTestUtils.assertEqualsToFile( - testFile, - text.substringBefore("// VARIABLE : ") + getActualVariablesAsString( - actualLocalVariables - ) - ) + // TODO: Refactor test infrastructure to share filtering with AbstractBytecodeTextTest + private fun filterTestFileForTargetBackend(testFile: File): List { + val filteredLines = mutableListOf() + var currentBackend = TargetBackend.ANY + for (line in testFile.readLines()) { + if (line.contains(JVM_TEMPLATES)) { + currentBackend = TargetBackend.JVM + } else if (line.contains(JVM_IR_TEMPLATES)) { + currentBackend = TargetBackend.JVM_IR + } else if (currentBackend == TargetBackend.ANY || currentBackend == backend) { + filteredLines.add(line) + } + } + return filteredLines } - protected class LocalVariable internal constructor( + private fun doCompare( + testFileLines: List, + actualLocalVariables: List + ) { + val actual = getActualVariablesAsString(actualLocalVariables) + val expected = getExpectedVariablesAsString(testFileLines) + if (!Comparing.equal(expected, actual)) { + throw ComparisonFailure( + "Variables differ from expected", + expected, + actual + ) + } + } + + private fun getActualVariablesAsString(list: List) = if (backend.isIR) { + // Ignore local index. + list.map { it.toString().replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } + .sorted() + .joinToString("\n") + } else { + list.joinToString("\n") + } + + private fun getExpectedVariablesAsString(testFileLines: List): String { + val variableLines = testFileLines.asSequence().filter { line -> line.startsWith("// VARIABLE ") } + return if (backend.isIR) { + // Ignore local index. + variableLines + .map { it.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } + .sorted() + .joinToString("\n") + } else { + variableLines.joinToString("\n") + } + } + + private class LocalVariable internal constructor( val name: String, val type: String, val index: Int, @@ -82,8 +126,8 @@ abstract class AbstractCheckLocalVariablesTableTest : CodegenTestCase() { } } - private fun parseClassAndMethodSignature(testFile: File): String { - for (line in testFile.readLines()) { + private fun parseClassAndMethodSignature(testFileLines: List): String { + for (line in testFileLines) { val methodMatcher = methodPattern.matcher(line) if (methodMatcher.matches()) { return methodMatcher.group(1) @@ -95,7 +139,9 @@ abstract class AbstractCheckLocalVariablesTableTest : CodegenTestCase() { companion object { - private fun getActualVariablesAsString(list: List) = list.joinToString("\n") + private const val JVM_TEMPLATES = "// JVM_TEMPLATES" + + private const val JVM_IR_TEMPLATES = "// JVM_IR_TEMPLATES" private val methodPattern = Pattern.compile("^// METHOD : *(.*)") @@ -104,6 +150,7 @@ abstract class AbstractCheckLocalVariablesTableTest : CodegenTestCase() { class Visitor : ClassVisitor(Opcodes.API_VERSION) { var readVariables: MutableList = ArrayList() var methodFound = false + var methodsFound = mutableListOf() override fun visitMethod( access: Int, name: String, desc: String, signature: String?, exceptions: Array? @@ -128,6 +175,7 @@ abstract class AbstractCheckLocalVariablesTableTest : CodegenTestCase() { } } } else { + methodsFound.add(name + desc) super.visitMethod(access, name, desc, signature, exceptions) } } @@ -135,7 +183,10 @@ abstract class AbstractCheckLocalVariablesTableTest : CodegenTestCase() { val visitor = Visitor() cr.accept(visitor, ClassReader.SKIP_FRAMES) - TestCase.assertTrue("method not found: $methodName", visitor.methodFound) + TestCase.assertTrue( + "Method not found: $methodName. Methods found were: ${visitor.methodsFound.joinToString()}", + visitor.methodFound + ) return visitor.readVariables } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt index d3729eecd1b..449be98bb57 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrCheckLocalVariablesTableTest.kt @@ -5,43 +5,9 @@ package org.jetbrains.kotlin.codegen.ir -import com.intellij.openapi.util.Comparing import org.jetbrains.kotlin.codegen.AbstractCheckLocalVariablesTableTest import org.jetbrains.kotlin.test.TargetBackend -import org.junit.ComparisonFailure -import java.io.File abstract class AbstractIrCheckLocalVariablesTableTest : AbstractCheckLocalVariablesTableTest() { - override fun doCompare( - testFile: File, - text: String, - actualLocalVariables: List - ) { - val actual = getActualVariablesAsList(actualLocalVariables) - val expected = getExpectedVariablesAsList(testFile) - if (!Comparing.equal(expected, actual)) { - throw ComparisonFailure( - "Variables differ from expected", - expected.joinToString("\n"), - actual.joinToString("\n") - ) - } - } - - private fun getActualVariablesAsList(list: List): List { - return list.map { it.toString() } - // Ignore local index. - .map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } - .sorted() - } - - private fun getExpectedVariablesAsList(testFile: File): List { - return testFile.readLines() - .filter { line -> line.startsWith("// VARIABLE ") } - // Ignore local index. - .map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } - .sorted() - } - override fun getBackend() = TargetBackend.JVM_IR }