JVM IR: Enable evaluate expression tests for the JVM IR backend

This commit is contained in:
Steven Schäfer
2020-09-22 11:53:24 +02:00
committed by max-kammerer
parent 33969c5f9a
commit 48b736e551
33 changed files with 1476 additions and 23 deletions
@@ -253,6 +253,11 @@ fun main(args: Array<String>) {
model("evaluation/multipleBreakpoints", testMethod = "doMultipleBreakpointsTest")
}
testClass<AbstractIrKotlinEvaluateExpressionTest> {
model("evaluation/singleBreakpoint", testMethod = "doSingleBreakpointTest", targetBackend = TargetBackend.JVM_IR)
model("evaluation/multipleBreakpoints", testMethod = "doMultipleBreakpointsTest", targetBackend = TargetBackend.JVM_IR)
}
testClass<AbstractSelectExpressionForDebuggerTest> {
model("selectExpression", recursive = false)
model("selectExpression/disallowMethodCalls", testMethod = "doTestWoMethodCalls")
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2020 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.idea.debugger.test
abstract class AbstractIrKotlinEvaluateExpressionTest : AbstractKotlinEvaluateExpressionTest() {
override fun useIrBackend(): Boolean = true
}
@@ -11,7 +11,6 @@ import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.debugger.engine.evaluation.EvaluateException
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.DebuggerContextImpl.createDebuggerContext
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl
@@ -27,12 +26,16 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.idea.debugger.test.util.FramePrinter
import org.jetbrains.kotlin.idea.debugger.test.util.FramePrinterDelegate
import org.jetbrains.kotlin.idea.debugger.test.util.KotlinOutputChecker
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
import org.jetbrains.kotlin.test.KotlinBaseTest
import org.jetbrains.kotlin.test.TargetBackend
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import javax.swing.tree.TreeNode
private data class CodeFragment(val text: String, val result: String, val kind: CodeFragmentKind)
@@ -57,6 +60,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
private var framePrinter: FramePrinter? = null
private val exceptions = ConcurrentHashMap<String, Throwable>()
fun doSingleBreakpointTest(path: String) {
isMultipleBreakpointsTest = false
doTest(path)
@@ -89,6 +94,7 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
override fun tearDown() {
framePrinter?.close()
framePrinter = null
exceptions.clear()
super.tearDown()
}
@@ -102,26 +108,22 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
val exceptions = linkedMapOf<String, Throwable>()
for ((expression, expected, kind) in data.fragments) {
mayThrow(exceptions, expression) {
mayThrow(expression) {
evaluate(this, expression, kind, expected)
}
}
val completion = { resume(this) }
framePrinter?.printFrame(completion) ?: completion()
checkExceptions(exceptions)
}
finish()
}
private fun performMultipleBreakpointTest(data: EvaluationTestData) {
val exceptions = linkedMapOf<String, Throwable>()
for ((expression, expected) in data.fragments) {
mayThrow(exceptions, expression) {
doOnBreakpoint {
doOnBreakpoint {
mayThrow(expression) {
try {
evaluate(this, expression, CodeFragmentKind.EXPRESSION, expected)
} finally {
@@ -131,8 +133,6 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
}
}
}
checkExceptions(exceptions)
finish()
}
@@ -211,24 +211,30 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
super.expandAll(tree, runnable, HashSet(), filter, suspendContext)
}
private fun mayThrow(collector: MutableMap<String, Throwable>, expression: String, f: () -> Unit) {
private fun mayThrow(expression: String, f: () -> Unit) {
try {
f()
} catch (e: Throwable) {
collector[expression] = e
exceptions[expression] = e
}
}
private fun checkExceptions(exceptions: MutableMap<String, Throwable>) {
override fun throwExceptionsIfAny() {
if (exceptions.isNotEmpty()) {
for (exc in exceptions.values) {
exc.printStackTrace()
val isIgnored = InTextDirectivesUtils.isIgnoredTarget(
if (useIrBackend()) TargetBackend.JVM_IR else TargetBackend.JVM,
getExpectedOutputFile()
)
if (!isIgnored) {
for (exc in exceptions.values) {
exc.printStackTrace()
}
val expressionsText = exceptions.entries.joinToString("\n") { (k, v) -> "expression: $k, exception: ${v.message}" }
throw AssertionError("Test failed:\n$expressionsText")
} else {
(checker as KotlinOutputChecker).threwException = true
}
val expressionsText = exceptions.entries.joinToString("\n") { (k, v) -> "expression: $k, exception: ${v.message}" }
@Suppress("ConvertToStringTemplate")
throw AssertionError("Test failed:\n" + expressionsText)
}
}
@@ -220,7 +220,7 @@ abstract class KotlinDescriptorTestCase : DescriptorTestCase() {
}
}
private fun getExpectedOutputFile(): File {
protected fun getExpectedOutputFile(): File {
if (useIrBackend()) {
val irOut = File(getTestDirectoryPath(), getTestName(true) + ".ir.out")
if (irOut.exists()) return irOut
@@ -45,6 +45,9 @@ internal class KotlinOutputChecker(
private lateinit var myTestName: String
// True if the underlying test has already failed, but the failure was ignored.
var threwException = false
override fun init(testName: String) {
super.init(testName)
this.myTestName = Character.toLowerCase(testName[0]) + testName.substring(1)
@@ -60,6 +63,7 @@ internal class KotlinOutputChecker(
val outDir = File(testDir)
var outFile = expectedOutputFile
val isIgnored = InTextDirectivesUtils.isIgnoredTarget(if (useIrBackend) TargetBackend.JVM_IR else TargetBackend.JVM, outFile)
if (!outFile.exists()) {
if (SystemInfo.isWindows) {
@@ -80,7 +84,6 @@ internal class KotlinOutputChecker(
LOG.error("Test file created ${outFile.path}\n**************** Don't forget to put it into VCS! *******************")
} else {
val originalText = FileUtilRt.loadFile(outFile, CharsetToolkit.UTF8)
val isIgnored = InTextDirectivesUtils.isIgnoredTarget(if (useIrBackend) TargetBackend.JVM_IR else TargetBackend.JVM, outFile)
val expected = StringUtilRt.convertLineSeparators(originalText).split("\n").filter {
!it.trim().startsWith(InTextDirectivesUtils.IGNORE_BACKEND_DIRECTIVE_PREFIX)
}.joinToString("\n")
@@ -104,7 +107,7 @@ internal class KotlinOutputChecker(
if (isIgnored) return
Assert.assertEquals(expected, actual)
} else if (isIgnored) {
} else if (isIgnored && !threwException) {
// Fail if tests are marked as failing, but actually pass.
throw AssertionError("Test passes and could be unmuted, remove IGNORE_BACKEND directive from ${outFile.path}")
}
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
FunctionBreakpoint created at constructors.kt:9
LineBreakpoint created at constructors.kt:13
FunctionBreakpoint created at constructors.kt:20
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:7 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:12 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:18 lambdaOrdinal = 1
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at localFunCustomLib.kt:7
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at localFun.kt:9
LineBreakpoint created at localFun.kt:15
LineBreakpoint created at localFun.kt:21
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at smartcasts.kt:19
LineBreakpoint created at smartcasts.kt:29
Run Java
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at thisLabels.kt:6
LineBreakpoint created at thisLabels.kt:8
LineBreakpoint created at thisLabels.kt:10
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at dataClassCopy.kt:6
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at delegatedPropertyInOtherFile.kt:10
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at delegatedVariables.kt:6
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at extractThisInTrait.kt:10
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at capturedValues1.kt:17
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at defaultImplsMangling.kt:8
Run Java
Connected to the target VM
@@ -0,0 +1,14 @@
LineBreakpoint created at frameAnonymousObject.kt:11
Run Java
Connected to the target VM
frameAnonymousObject.kt:11
frame = invoke:11, FrameAnonymousObjectKt$main$o$1$run$1 {frameAnonymousObject}
this = this = {frameAnonymousObject.FrameAnonymousObjectKt$main$o$1$run$1@uniqueID}Function0<kotlin.Unit>
field = $val1: int = 1 (sp = null)
field = this$0: frameAnonymousObject.FrameAnonymousObjectKt$main$o$1 = {frameAnonymousObject.FrameAnonymousObjectKt$main$o$1@uniqueID} (sp = null)
field = obProp: int = 1 (sp = frameAnonymousObject.kt, 6)
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,33 @@
LineBreakpoint created at frameExtFunExtFun.kt:24
Run Java
Connected to the target VM
frameExtFunExtFun.kt:24
Compile bytecode for valFoo
Compile bytecode for valTest
Compile bytecode for aProp
Compile bytecode for outerProp
Compile bytecode for bProp
Compile bytecode for aMyFun()
Compile bytecode for outerMyFun()
Compile bytecode for bMyFun()
frame = invoke:24, Outer$foo$LocalClass$test$1 {frameExtFunExtFun}
this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}Function0<kotlin.Unit>
field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} (sp = null)
field = outerProp: int = 1 (sp = frameExtFunExtFun.kt, 13)
field = $this_foo: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} (sp = null)
field = aProp: int = 1 (sp = frameExtFunExtFun.kt, 8)
field = this$1: frameExtFunExtFun.Outer$foo$LocalClass = {frameExtFunExtFun.Outer$foo$LocalClass@uniqueID} (sp = null)
field = lcProp: int = 1 (sp = frameExtFunExtFun.kt, 19)
field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} (sp = null)
field = outerProp: int = 1 (sp = frameExtFunExtFun.kt, 13)
field = $this_foo: frameExtFunExtFun.A = {frameExtFunExtFun.A@uniqueID} (sp = null)
field = aProp: int = 1 (sp = frameExtFunExtFun.kt, 8)
field = $valFoo: int = 1 (sp = null)
field = $this_test: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} (sp = null)
field = bProp: int = 1 (sp = frameExtFunExtFun.kt, 41)
field = $valFoo: int = 1 (sp = null)
field = $valTest: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,15 @@
LineBreakpoint created at frameInnerLambda.kt:9
Run Java
Connected to the target VM
frameInnerLambda.kt:9
Compile bytecode for val1
Compile bytecode for val2
Compile bytecode for val1 + val2
frame = invoke:9, FrameInnerLambdaKt$main$1$1 {frameInnerLambda}
this = this = {frameInnerLambda.FrameInnerLambdaKt$main$1$1@uniqueID}Function0<kotlin.Unit>
field = $val1: int = 1 (sp = null)
field = $val2: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,19 @@
LineBreakpoint created at frameThis0This0.kt:17
Run Java
Connected to the target VM
frameThis0This0.kt:17
Compile bytecode for val1
Compile bytecode for val2
Compile bytecode for prop1
Compile bytecode for prop1 + val1 + val2
Compile bytecode for myFun()
frame = invoke:17, A$test$1$1 {frameThis0This0}
this = this = {frameThis0This0.A$test$1$1@uniqueID}Function0<kotlin.Unit>
field = this$0: frameThis0This0.A = {frameThis0This0.A@uniqueID} (sp = null)
field = prop1: int = 1 (sp = frameThis0This0.kt, 8)
field = $val1: int = 1 (sp = null)
field = $val2: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM
Process finished with exit code 0
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at hideSyntheticThis.kt:6
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at lambdaAsValueArgument.kt:19
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at lambdaFun3.kt:7
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at kt15259.kt:7
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at kt29179.kt:9
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at test.kt:8
Run Java
Connected to the target VM
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at destructuringParam.kt:12 lambdaOrdinal = 1
Run Java
Connected to the target VM
@@ -0,0 +1,7 @@
LineBreakpoint created at inlineFunctionalExpression.kt:9
Run Java
Connected to the target VM
inlineFunctionalExpression.kt:9
Disconnected from the target VM
Process finished with exit code 0
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at localFunctionsWithReceivers.kt:10
Run Java
Connected to the target VM
@@ -0,0 +1,13 @@
LineBreakpoint created at onObjectHeader.kt:5
Run Java
Connected to the target VM
onObjectHeader.kt:5
onObjectHeader.kt:10
onObjectHeader.kt:16
onObjectHeader.kt:10
onObjectHeader.kt:11
onObjectHeader.kt:8
Compile bytecode for 1 + 1
Disconnected from the target VM
Process finished with exit code 0
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
KotlinFieldBreakpoint created at fwBackingField.kt:5
KotlinFieldBreakpoint created at fwBackingField.kt:8
KotlinFieldBreakpoint created at fwBackingField.kt:18