diff --git a/compiler/ir/ir.tests/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt b/compiler/ir/ir.tests/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt index 9b1f3c34b1a..3ace91cfedf 100644 --- a/compiler/ir/ir.tests/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt +++ b/compiler/ir/ir.tests/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt @@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil import junit.framework.TestCase import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.util.dumpTreesFromLineNumber import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.utils.rethrow import java.io.File @@ -52,6 +53,11 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { actual.append(actualCount).append(" ").append(expectation.needle).append("\n") } + for (irTreeFileLabel in expectations.irTreeFileLabels) { + val actualTrees = irFile.dumpTreesFromLineNumber(irTreeFileLabel.lineNumber) + KotlinTestUtils.assertEqualsToFile(irTreeFileLabel.expectedTextFile, actualTrees) + } + try { TestCase.assertEquals(irFileDump, expected.toString(), actual.toString()) } @@ -61,40 +67,52 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { } } - protected class Expectations(val irExpectedTextFile: File?, val regexps: List) + internal class Expectations(val irExpectedTextFile: File?, val regexps: List, val irTreeFileLabels: List) - protected class RegexpInText(val numberOfOccurrences: Int, val needle: String) { + internal class RegexpInText(val numberOfOccurrences: Int, val needle: String) { constructor(countStr: String, needle: String) : this(Integer.valueOf(countStr), needle) } + internal class IrTreeFileLabel(val expectedTextFile: File, val lineNumber: Int) + companion object { private val EXPECTED_OCCURRENCES_PATTERN = Regex("""^\s*//\s*(\d+)\s*(.*)$""") - private val EXPECT_TXT_PATTERN = Regex("""^\s*//\s*IR_FILE_TXT\s+(.*)$""") + private val IR_FILE_TXT_PATTERN = Regex("""^\s*//\s*IR_FILE_TXT\s+(.*)$""") + private val IR_TREES_TXT_PATTERN = Regex("""// \s*<<<\s+(.*)$""") - private fun parseExpectations(dir: File, testFile: TestFile): Expectations { + internal fun parseExpectations(dir: File, testFile: TestFile): Expectations { var expectedTextFileName: String? = null val regexps = ArrayList() - for (line in testFile.content.split("\n")) { + val treeFiles = ArrayList() + + for ((lineNumber, line) in testFile.content.split("\n").withIndex()) { EXPECTED_OCCURRENCES_PATTERN.matchEntire(line)?.let { matchResult -> - regexps.add(RegexpInText(matchResult.groupValues[1], matchResult.groupValues[2])) + regexps.add(RegexpInText(matchResult.groupValues[1], matchResult.groupValues[2].trim())) } - EXPECT_TXT_PATTERN.matchEntire(line)?.let { matchResult -> - expectedTextFileName = matchResult.groupValues[1] + ?: IR_FILE_TXT_PATTERN.matchEntire(line)?.let { matchResult -> + expectedTextFileName = matchResult.groupValues[1].trim() + } + ?: IR_TREES_TXT_PATTERN.find(line)?.let { matchResult -> + val fileName = matchResult.groupValues[1].trim() + val file = createExpectedTextFile(testFile, dir, fileName) + treeFiles.add(IrTreeFileLabel(file, lineNumber)) } } - val expectedTextFile: File? = expectedTextFileName?.let { - val textFile = File(dir, expectedTextFileName) - if (!textFile.exists()) { - TestCase.assertTrue("Can't create an IR expected text containingFile: ${textFile.absolutePath}", textFile.createNewFile()) - PrintWriter(FileWriter(textFile)).use { - it.println("$expectedTextFileName: new IR expected text containingFile for ${testFile.name}") - } - } - textFile - } + val expectedTextFile: File? = expectedTextFileName?.let { createExpectedTextFile(testFile, dir, it) } - return Expectations(expectedTextFile, regexps) + return Expectations(expectedTextFile, regexps, treeFiles) + } + + internal fun createExpectedTextFile(testFile: TestFile, dir: File, fileName: String): File { + val textFile = File(dir, fileName) + if (!textFile.exists()) { + TestCase.assertTrue("Can't create an IR expected text containingFile: ${textFile.absolutePath}", textFile.createNewFile()) + PrintWriter(FileWriter(textFile)).use { + it.println("$fileName: new IR expected text containingFile for ${testFile.name}") + } + } + return textFile } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFile.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFile.kt index 7913dcb2c3c..d05640faa8c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFile.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFile.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor interface IrFile : IrCompoundDeclaration { val name: String + val fileEntry: SourceLocationManager.FileEntry val module: IrModule override val descriptor: PackageFragmentDescriptor @@ -32,7 +33,7 @@ interface IrFile : IrCompoundDeclaration { } class IrFileImpl( - val fileEntry: SourceLocationManager.FileEntry, + override val fileEntry: SourceLocationManager.FileEntry, override val name: String, override val descriptor: PackageFragmentDescriptor ) : IrCompoundDeclarationBase(0, fileEntry.maxOffset, IrDeclarationOriginKind.DEFINED), IrFile { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt index 5eb5e0e54cf..36415bae8c4 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt @@ -17,17 +17,25 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.SourceLocationManager import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrCallExpression import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.utils.Printer -fun IrDeclaration.dump(): String { +fun IrElement.dump(): String { val sb = StringBuilder() accept(DumpIrTreeVisitor(sb), "") return sb.toString() } +fun IrFile.dumpTreesFromLineNumber(lineNumber: Int): String { + val sb = StringBuilder() + accept(DumpTreeFromSourceLineVisitor(fileEntry, lineNumber, sb), null) + return sb.toString() +} + class DumpIrTreeVisitor(out: Appendable): IrElementVisitor { val printer = Printer(out, " ") val elementRenderer = RenderIrElementVisitor() @@ -67,3 +75,20 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor { private fun String.withLabel(label: String) = if (label.isEmpty()) this else "$label: $this" } + +class DumpTreeFromSourceLineVisitor( + val fileEntry: SourceLocationManager.FileEntry, + val lineNumber: Int, + out: Appendable +): IrElementVisitor { + val dumper = DumpIrTreeVisitor(out) + + override fun visitElement(element: IrElement, data: Nothing?) { + if (fileEntry.getLineNumber(element.startOffset) == lineNumber) { + element.accept(dumper, "") + return + } + + element.acceptChildren(this, data) + } +} diff --git a/compiler/testData/ir/irText/calls.txt b/compiler/testData/ir/irText/calls.txt index a4c054d6b02..42b9403a02b 100644 --- a/compiler/testData/ir/irText/calls.txt +++ b/compiler/testData/ir/irText/calls.txt @@ -20,10 +20,10 @@ IrFile /calls.kt IrFunction public fun kotlin.Int.ext1(): kotlin.Int IrExpressionBody RETURN type=kotlin.Int - DUMMY KtThisExpression + $RECEIVER of: IrFunction public fun kotlin.Int.ext2(/*0*/ x: kotlin.Int): kotlin.Int IrExpressionBody RETURN type=kotlin.Int CALL foo - x: DUMMY KtThisExpression + x: $RECEIVER of: y: VAR x diff --git a/compiler/testData/ir/irText/smoke.kt b/compiler/testData/ir/irText/smoke.kt index da6b7411cba..814098a54f1 100644 --- a/compiler/testData/ir/irText/smoke.kt +++ b/compiler/testData/ir/irText/smoke.kt @@ -1,5 +1,5 @@ fun testFun(): String { return "OK" } -val testSimpleVal = 1 +val testSimpleVal = 1 // <<< smoke.testSimpleVal.txt val testValWithGetter: Int get() = 42 var testSimpleVar = 2 var testVarWithAccessors: Int diff --git a/compiler/testData/ir/irText/smoke.testSimpleVal.txt b/compiler/testData/ir/irText/smoke.testSimpleVal.txt new file mode 100644 index 00000000000..b6e0f87da0a --- /dev/null +++ b/compiler/testData/ir/irText/smoke.testSimpleVal.txt @@ -0,0 +1,4 @@ +IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null + IrExpressionBody + RETURN type=kotlin.Int + LITERAL Int type=kotlin.Int value='1'