Repository: bnorm/kotlin-power-assert (kotlin)

Issue:
AbstractMethodError with Kotlin 1.3.70 (released today)
Please see the exception from this build scan:

https://scans.gradle.com/s/zabxwgoutrfrc/failure?openFailures=WzBd&openStackTraces=WzFd#top=0

Relevant configuration code:
```
plugins {
    id("java-gradle-plugin")
    id("com.gradle.plugin-publish") version "0.10.1"
    id("org.jetbrains.kotlin.jvm") version "1.3.70"
    `kotlin-dsl`
    id("com.bnorm.power.kotlin-power-assert") version "0.2.0"
}

tasks.withType<KotlinCompile>().matching {
    // compileTestKotlin, compileFunctionalTestKotlin, ...
    // useIR leads to compilation failures for non-standard test source sets :'(
    //it.name.endsWith("TestKotlin")
    it.name == "compileTestKotlin"
}.configureEach {
    kotlinOptions {
        // For use with the "com.bnorm.power.kotlin-power-assert" plugin, enabling power asserts in tests
        // https://github.com/bnorm/kotlin-power-assert
        useIR = true
    }
}
```

Pull request description:
Fixes #8

Patch:
diff --git a/build.gradle.kts b/build.gradle.kts
index c64bd56..8643d90 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,5 @@
 plugins {
-  kotlin("jvm") version "1.3.60" apply false
+  kotlin("jvm") version "1.3.70" apply false
   id("org.jetbrains.dokka") version "0.10.0" apply false
   id("com.gradle.plugin-publish") version "0.10.1" apply false
 }
diff --git a/kotlin-power-assert/build.gradle.kts b/kotlin-power-assert/build.gradle.kts
index b6b50fc..30deba1 100644
--- a/kotlin-power-assert/build.gradle.kts
+++ b/kotlin-power-assert/build.gradle.kts
@@ -11,14 +11,14 @@ plugins {
 
 dependencies {
   implementation(kotlin("stdlib-jdk8"))
-  compileOnly("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.60")
+  compileOnly("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.70")
 
   kapt("com.google.auto.service:auto-service:1.0-rc6")
   compileOnly("com.google.auto.service:auto-service-annotations:1.0-rc6")
 
   testImplementation(kotlin("test-junit"))
-  testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.60")
-  testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.2.5")
+  testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.70")
+  testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.2.6")
 }
 
 tasks.withType<KotlinCompile> {
diff --git a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/AssertTree.kt b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/AssertTree.kt
index 923706e..679adff 100644
--- a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/AssertTree.kt
+++ b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/AssertTree.kt
@@ -101,7 +101,7 @@ fun buildAssertTree(expression: IrExpression): RootNode {
     }
 
     override fun visitCall(expression: IrCall, data: Node) {
-      if (expression.descriptor.name.asString() == "EQEQ" && expression.origin == IrStatementOrigin.EXCLEQ) {
+      if (expression.symbol.descriptor.name.asString() == "EQEQ" && expression.origin == IrStatementOrigin.EXCLEQ) {
         // Skip the EQEQ part of a EXCLEQ call
         expression.acceptChildren(this, data)
       } else {
diff --git a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/IrStackVariable.kt b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/IrStackVariable.kt
index f02eac5..e9e184c 100644
--- a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/IrStackVariable.kt
+++ b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/IrStackVariable.kt
@@ -16,11 +16,9 @@
 
 package com.bnorm.power
 
-import org.jetbrains.kotlin.backend.common.lower.irThrow
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
 import org.jetbrains.kotlin.ir.IrElement
 import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
-import org.jetbrains.kotlin.ir.builders.irCall
 import org.jetbrains.kotlin.ir.builders.irConcat
 import org.jetbrains.kotlin.ir.builders.irGet
 import org.jetbrains.kotlin.ir.builders.irString
@@ -29,8 +27,6 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable
 import org.jetbrains.kotlin.ir.expressions.IrExpression
 import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
 import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
-import org.jetbrains.kotlin.ir.expressions.IrThrow
-import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
 
 data class IrStackVariable(
   val temporary: IrVariable,
@@ -44,13 +40,6 @@ data class ValueDisplay(
   val source: String
 )
 
-fun IrBuilderWithScope.buildThrow(
-  constructor: IrConstructorSymbol,
-  message: IrExpression
-): IrThrow = irThrow(irCall(constructor).apply {
-  putValueArgument(0, message)
-})
-
 fun IrBuilderWithScope.buildMessage(
   file: IrFile,
   fileSource: String,
@@ -74,7 +63,7 @@ fun IrBuilderWithScope.buildMessage(
 
     val columnOffset: Int = when (original) {
       is IrMemberAccessExpression -> {
-        val descriptor = original.descriptor
+        val descriptor = original.symbol.descriptor
         when {
           descriptor is FunctionDescriptor && descriptor.isInfix -> source.indexOf(descriptor.name.asString())
           else -> when (original.origin) {
diff --git a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertCallTransformer.kt b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertCallTransformer.kt
index 0a592e1..4cad001 100644
--- a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertCallTransformer.kt
+++ b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertCallTransformer.kt
@@ -16,13 +16,16 @@
 
 package com.bnorm.power
 
-import org.jetbrains.kotlin.backend.common.BackendContext
 import org.jetbrains.kotlin.backend.common.FileLoweringPass
+import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
+import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
 import org.jetbrains.kotlin.backend.common.ir.asSimpleLambda
 import org.jetbrains.kotlin.backend.common.ir.inline
+import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
 import org.jetbrains.kotlin.backend.common.lower.at
-import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
+import org.jetbrains.kotlin.backend.common.serialization.findPackage
 import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
 import org.jetbrains.kotlin.descriptors.Visibilities
 import org.jetbrains.kotlin.incremental.components.NoLookupLocation
 import org.jetbrains.kotlin.ir.IrElement
@@ -36,7 +39,6 @@ import org.jetbrains.kotlin.ir.builders.irReturn
 import org.jetbrains.kotlin.ir.builders.irString
 import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
 import org.jetbrains.kotlin.ir.declarations.IrFile
-import org.jetbrains.kotlin.ir.declarations.IrFunction
 import org.jetbrains.kotlin.ir.declarations.path
 import org.jetbrains.kotlin.ir.expressions.IrCall
 import org.jetbrains.kotlin.ir.expressions.IrConst
@@ -46,16 +48,14 @@ import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
 import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
 import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
 import org.jetbrains.kotlin.ir.types.getClass
-import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
 import org.jetbrains.kotlin.ir.util.functions
-import org.jetbrains.kotlin.ir.util.getPackageFragment
 import org.jetbrains.kotlin.ir.util.referenceFunction
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
 import org.jetbrains.kotlin.types.KotlinType
 import org.jetbrains.kotlin.types.typeUtil.isBoolean
 import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
@@ -76,9 +76,9 @@ fun FileLoweringPass.runOnFileInOrder(irFile: IrFile) {
 }
 
 class PowerAssertCallTransformer(
-  private val context: BackendContext,
+  private val context: IrPluginContext,
   private val functions: Set<FqName>
-) : IrElementTransformerVoid(), FileLoweringPass {
+) : IrElementTransformerVoidWithContext(), FileLoweringPass {
   private lateinit var file: IrFile
   private lateinit var fileSource: String
 
@@ -90,8 +90,8 @@ class PowerAssertCallTransformer(
   }
 
   override fun visitCall(expression: IrCall): IrExpression {
-    val function = expression.symbol.owner
-    if (functions.none { function.fqNameWhenAvailable == it })
+    val function = expression.symbol.descriptor
+    if (functions.none { function.fqNameSafe == it })
       return super.visitCall(expression)
 
     val delegate = findDelegate(function) ?: run {
@@ -103,24 +103,26 @@ class PowerAssertCallTransformer(
     val assertionArgument = expression.getValueArgument(0)!!
     val messageArgument = if (function.valueParameters.size == 2) expression.getValueArgument(1) else null
 
-    context.createIrBuilder(expression.symbol).run {
+    val symbol = currentScope!!.scope.scopeOwnerSymbol
+    DeclarationIrBuilder(context, symbol).run {
       at(expression)
 
-      val lambda = messageArgument?.asSimpleLambda()
-      val title = when {
-        messageArgument is IrConst<*> -> messageArgument
-        messageArgument is IrStringConcatenation -> messageArgument
-        lambda != null -> lambda.inline()
-        messageArgument != null -> {
-          val invoke = messageArgument.type.getClass()!!.functions.single { it.name == OperatorNameConventions.INVOKE }
-          irCallOp(invoke.symbol, invoke.returnType, messageArgument)
-        }
-        // TODO what should the default message be?
-        else -> irString("Assertion failed")
-      }
-
       val generator = object : PowerAssertGenerator() {
         override fun IrBuilderWithScope.buildAssertThrow(subStack: List<IrStackVariable>): IrExpression {
+
+          val lambda = messageArgument?.asSimpleLambda()
+          val title = when {
+            messageArgument is IrConst<*> -> messageArgument
+            messageArgument is IrStringConcatenation -> messageArgument
+            lambda != null -> lambda.inline()
+            messageArgument != null -> {
+              val invoke = messageArgument.type.getClass()!!.functions.single { it.name == OperatorNameConventions.INVOKE }
+              irCallOp(invoke.symbol, invoke.returnType, messageArgument)
+            }
+            // TODO what should the default message be?
+            else -> irString("Assertion failed")
+          }
+
           return delegate.buildCall(this, buildMessage(file, fileSource, title, expression, subStack))
         }
       }
@@ -140,7 +142,9 @@ class PowerAssertCallTransformer(
     fun buildCall(builder: IrBuilderWithScope, message: IrExpression): IrExpression
   }
 
-  private fun findDelegate(function: IrFunction): FunctionDelegate? {
+  private fun findDelegate(function: FunctionDescriptor): FunctionDelegate? {
+    fun KotlinType.toIrType() = context.typeTranslator.translateType(this)
+
     return context.findOverloads(function)
       .mapNotNull { overload ->
         // TODO allow other signatures than (Boolean, String) and (Boolean, () -> String))
@@ -152,7 +156,7 @@ class PowerAssertCallTransformer(
           isStringSupertype(parameters[1].type) -> {
             object : FunctionDelegate {
               override fun buildCall(builder: IrBuilderWithScope, message: IrExpression): IrExpression = with(builder) {
-                irCall(overload).apply {
+                irCall(overload, type = overload.descriptor.returnType!!.toIrType()).apply {
                   putValueArgument(0, irFalse())
                   putValueArgument(1, message)
                 }
@@ -168,13 +172,13 @@ class PowerAssertCallTransformer(
                   visibility = Visibilities.LOCAL
                   origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
                 }.apply {
-                  val bodyBuilder = this@PowerAssertCallTransformer.context.createIrBuilder(symbol)
+                  val bodyBuilder = DeclarationIrBuilder(this@PowerAssertCallTransformer.context, symbol)
                   body = bodyBuilder.irBlockBody {
                     +irReturn(message)
                   }
                 }
                 val expression = IrFunctionExpressionImpl(-1, -1, context.irBuiltIns.stringType, lambda, IrStatementOrigin.LAMBDA)
-                irCall(overload).apply {
+                irCall(overload, type = overload.descriptor.returnType!!.toIrType()).apply {
                   putValueArgument(0, irFalse())
                   putValueArgument(1, expression)
                 }
@@ -195,7 +199,7 @@ class PowerAssertCallTransformer(
 }
 
 // TODO is this the best way to find overload functions?
-private fun BackendContext.findOverloads(function: IrFunction): List<IrFunctionSymbol> =
-  function.getPackageFragment()!!.symbol.descriptor.getMemberScope()
+private fun IrPluginContext.findOverloads(function: FunctionDescriptor): List<IrFunctionSymbol> =
+  function.findPackage().getMemberScope()
     .getContributedFunctions(function.name, NoLookupLocation.FROM_BACKEND)
-    .map { ir.symbols.externalSymbolTable.referenceFunction(it) }
+    .map { symbolTable.referenceFunction(it) }
diff --git a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertIrGenerationExtension.kt b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertIrGenerationExtension.kt
index b525984..85d4c48 100644
--- a/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertIrGenerationExtension.kt
+++ b/kotlin-power-assert/src/main/kotlin/com/bnorm/power/PowerAssertIrGenerationExtension.kt
@@ -16,16 +16,17 @@
 
 package com.bnorm.power
 
-import org.jetbrains.kotlin.backend.common.BackendContext
 import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
-import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
+import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
 import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.BindingContext
 
 class PowerAssertIrGenerationExtension(
   private val functions: Set<FqName>
 ) : IrGenerationExtension {
-  override fun generate(file: IrFile, backendContext: BackendContext, bindingContext: BindingContext) {
-    PowerAssertCallTransformer(backendContext, functions).runOnFileInOrder(file)
+  override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
+    for (file in moduleFragment.files) {
+      PowerAssertCallTransformer(pluginContext, functions).runOnFileInOrder(file)
+    }
   }
 }
diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts
index 4ab8dc3..c43489b 100644
--- a/sample/build.gradle.kts
+++ b/sample/build.gradle.kts
@@ -1,11 +1,11 @@
 buildscript {
   dependencies {
-    classpath("gradle.plugin.com.bnorm.power:kotlin-power-assert-gradle:0.1.0")
+    classpath("gradle.plugin.com.bnorm.power:kotlin-power-assert-gradle:0.2.0")
   }
 }
 
 plugins {
-  kotlin("jvm") version "1.3.60"
+  kotlin("jvm") version "1.3.70"
 }
 apply(plugin = "com.bnorm.power.kotlin-power-assert")
 
@@ -16,7 +16,6 @@ repositories {
 dependencies {
   implementation(kotlin("stdlib-jdk8"))
   testImplementation(kotlin("test-junit"))
-  testImplementation("org.assertj:assertj-core:3.15.0")
 }
 
 tasks.compileTestKotlin {
@@ -25,5 +24,5 @@ tasks.compileTestKotlin {
 }
 
 configure<com.bnorm.power.PowerAssertGradleExtension> {
-  functions = listOf("kotlin.test.AssertionsKt.assertTrue", "kotlin.PreconditionsKt.require")
+  functions = listOf("kotlin.test.assertTrue", "kotlin.require")
 }


Test patch:
diff --git a/kotlin-power-assert/src/test/kotlin/com/bnorm/power/test.kt b/kotlin-power-assert/src/test/kotlin/com/bnorm/power/test.kt
index 059b8a8..7223d11 100644
--- a/kotlin-power-assert/src/test/kotlin/com/bnorm/power/test.kt
+++ b/kotlin-power-assert/src/test/kotlin/com/bnorm/power/test.kt
@@ -345,7 +345,7 @@ assertTrue(1 == 2, message = "${"$"}text, the world is broken")
              |
              false
 """.trimIndent(),
-      PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.AssertionsKt.assertTrue")))
+      PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertTrue")))
     )
   }
 
@@ -362,7 +362,7 @@ require(1 == 2) { "the world is broken" }
           |
           false
 """.trimIndent(),
-      PowerAssertComponentRegistrar(setOf(FqName("kotlin.PreconditionsKt.require")))
+      PowerAssertComponentRegistrar(setOf(FqName("kotlin.require")))
     )
   }
 
@@ -379,7 +379,7 @@ check(1 == 2) { "the world is broken" }
         |
         false
 """.trimIndent(),
-      PowerAssertComponentRegistrar(setOf(FqName("kotlin.PreconditionsKt.check")))
+      PowerAssertComponentRegistrar(setOf(FqName("kotlin.check")))
     )
   }
 }
@@ -387,7 +387,7 @@ check(1 == 2) { "the world is broken" }
 fun assertMessage(
   @Language("kotlin") source: String,
   message: String,
-  vararg plugins: ComponentRegistrar = arrayOf(PowerAssertComponentRegistrar(setOf(FqName("kotlin.PreconditionsKt.assert"))))
+  vararg plugins: ComponentRegistrar = arrayOf(PowerAssertComponentRegistrar(setOf(FqName("kotlin.assert"))))
 ) {
   val result = KotlinCompilation().apply {
     sources = listOf(SourceFile.kotlin("main.kt", source))
@@ -400,7 +400,7 @@ fun assertMessage(
   assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode)
 
   val kClazz = result.classLoader.loadClass("MainKt")
-  val main = kClazz.declaredMethods.single { it.name == "main" }
+  val main = kClazz.declaredMethods.single { it.name == "main" && it.parameterCount == 0 }
   try {
     try {
       main.invoke(null)
diff --git a/sample/src/test/kotlin/com/bnorm/power/PowerAssertTest.kt b/sample/src/test/kotlin/com/bnorm/power/PowerAssertTest.kt
index 49b2a45..2c3a576 100644
--- a/sample/src/test/kotlin/com/bnorm/power/PowerAssertTest.kt
+++ b/sample/src/test/kotlin/com/bnorm/power/PowerAssertTest.kt
@@ -25,7 +25,7 @@ data class Person(
 )
 
 class PowerAssertTest {
-  private val people = listOf(Person("Brian", "Norman"), Person("Melinda", "Norman"))
+  private val people = listOf(Person("John", "Doe"), Person("Jane", "Doe"))
 
   @Test
   fun assertTrue() {