File tree Expand file tree Collapse file tree 4 files changed +98
-5
lines changed
burst-kotlin-plugin-tests/src/test/kotlin/app/cash/burst/kotlin
burst-kotlin-plugin/src/main/kotlin/app/cash/burst/kotlin Expand file tree Collapse file tree 4 files changed +98
-5
lines changed Original file line number Diff line number Diff line change
1
+ Burst Troubleshooting
2
+ =====================
3
+
4
+ NoSuchMethodError
5
+ -----------------
6
+
7
+ ```
8
+ java.lang.NoSuchMethodError: 'void com.example.AbstractFooTest.intercept(app.cash.burst.TestFunction)'
9
+ at com.example.StandardFooTest.intercept(StandardFooTest.kt:100)
10
+ ```
11
+
12
+ You’ll get this if the Burst Gradle Plugin wasn’t applied to a class that needs it. Update the
13
+ corresponding ` build.gradle.kts ` to apply it:
14
+
15
+ ``` kotlin
16
+ plugins {
17
+ id(" app.cash.burst" )
18
+ .. .
19
+ }
20
+ ```
Original file line number Diff line number Diff line change @@ -1480,4 +1480,59 @@ class TestInterceptorKotlinPluginTest {
1480
1480
" running BaseTest.happyPath" ,
1481
1481
)
1482
1482
}
1483
+
1484
+ /* *
1485
+ * Our initial implementation failed bytecode validation when a function returned 'void' when the
1486
+ * interceptor required it to return 'Unit'.
1487
+ */
1488
+ @Test
1489
+ fun earlyReturn () {
1490
+ val log = BurstTester (
1491
+ packageName = " com.example" ,
1492
+ ).compileAndRun(
1493
+ SourceFile .kotlin(
1494
+ " Main.kt" ,
1495
+ """
1496
+ package com.example
1497
+
1498
+ import app.cash.burst.InterceptTest
1499
+ import app.cash.burst.TestFunction
1500
+ import app.cash.burst.TestInterceptor
1501
+ import kotlin.test.AfterTest
1502
+ import kotlin.test.BeforeTest
1503
+ import kotlin.test.Test
1504
+
1505
+ class SampleTest {
1506
+ @InterceptTest
1507
+ val interceptor = object : TestInterceptor {
1508
+ override fun intercept(testFunction: TestFunction) {
1509
+ log("intercepting")
1510
+ testFunction()
1511
+ log("intercepted")
1512
+ }
1513
+ }
1514
+
1515
+ @Test
1516
+ fun happyPath() {
1517
+ if (true) {
1518
+ log("early return")
1519
+ return
1520
+ }
1521
+ log("no early return")
1522
+ }
1523
+ }
1524
+
1525
+ fun main(vararg args: String) {
1526
+ SampleTest().happyPath()
1527
+ }
1528
+ """ ,
1529
+ ),
1530
+ )
1531
+
1532
+ assertThat(log).containsExactly(
1533
+ " intercepting" ,
1534
+ " early return" ,
1535
+ " intercepted" ,
1536
+ )
1537
+ }
1483
1538
}
Original file line number Diff line number Diff line change @@ -50,7 +50,6 @@ import org.jetbrains.kotlin.ir.util.defaultType
50
50
import org.jetbrains.kotlin.ir.util.packageFqName
51
51
import org.jetbrains.kotlin.ir.util.parentClassOrNull
52
52
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
53
- import org.jetbrains.kotlin.ir.util.statements
54
53
import org.jetbrains.kotlin.ir.util.superClass
55
54
import org.jetbrains.kotlin.name.Name
56
55
@@ -364,7 +363,7 @@ internal class InterceptorInjector(
364
363
// If there's no function body to rewrite, we're probably looking at a superclass from another
365
364
// module. The rewrite won't be emitted anywhere, but we still need to generate its symbols for
366
365
// subclasses to call.
367
- val originalBody = original.body ? : return
366
+ if ( original.body == null ) return
368
367
369
368
if (original.modality != Modality .FINAL && originalParent.modality != Modality .FINAL ) {
370
369
unexpectedOpenFunction(original)
@@ -380,9 +379,7 @@ internal class InterceptorInjector(
380
379
arguments[0 ] = irString(packageName)
381
380
arguments[1 ] = irString(className)
382
381
arguments[2 ] = irString(original.name.asString())
383
- arguments[3 ] = localLambda(original.symbol) {
384
- + originalBody.statements
385
- }
382
+ arguments[3 ] = moveBodyToLocalLambda(original)
386
383
}
387
384
388
385
+ irCall(
Original file line number Diff line number Diff line change 15
15
*/
16
16
package app.cash.burst.kotlin
17
17
18
+ import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
18
19
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
19
20
import org.jetbrains.kotlin.backend.common.lower.irCatch
20
21
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocationWithRange
@@ -227,6 +228,26 @@ fun IrBlockBodyBuilder.localLambda(
227
228
)
228
229
}
229
230
231
+ /* * Moves the body of [original] to a newly-created local lambda. */
232
+ fun IrBlockBodyBuilder.moveBodyToLocalLambda (
233
+ original : IrSimpleFunction ,
234
+ ): IrFunctionExpressionImpl {
235
+ return IrFunctionExpressionImpl (
236
+ startOffset = startOffset,
237
+ endOffset = endOffset,
238
+ type = context.irBuiltIns.functionN(0 ).typeWith(context.irBuiltIns.unitType),
239
+ function = context.irFactory.buildFun {
240
+ this .name = Name .special(" <anonymous>" )
241
+ this .returnType = context.irBuiltIns.unitType
242
+ this .origin = IrDeclarationOrigin .Companion .LOCAL_FUNCTION_FOR_LAMBDA
243
+ this .visibility = DescriptorVisibilities .LOCAL
244
+ }.apply {
245
+ body = original.moveBodyTo(this , mapOf ())
246
+ },
247
+ origin = IrStatementOrigin .Companion .LAMBDA ,
248
+ )
249
+ }
250
+
230
251
internal fun IrBlockBuilder.irAccumulateFailure (
231
252
burstApis : BurstApis ,
232
253
failure : IrVariable ,
You can’t perform that action at this time.
0 commit comments