diff options
author | Evgeny Mandrikov <138671+Godin@users.noreply.github.com> | 2019-03-04 23:01:39 +0100 |
---|---|---|
committer | Marc R. Hoffmann <hoffmann@mountainminds.com> | 2019-03-04 23:01:39 +0100 |
commit | c30eb290f7958dce50c072527fbe6234e8388dd2 (patch) | |
tree | dade3590649d0462bf9ace8b86628fcdbfd72c4f | |
parent | 5f46dcf8c7ed2c7646daa76389201b404250b1fc (diff) | |
download | platform_external_jacoco-c30eb290f7958dce50c072527fbe6234e8388dd2.tar.gz platform_external_jacoco-c30eb290f7958dce50c072527fbe6234e8388dd2.tar.bz2 platform_external_jacoco-c30eb290f7958dce50c072527fbe6234e8388dd2.zip |
Update KotlinCoroutineFilter for Kotlin 1.3.30 (#849)
3 files changed, 114 insertions, 14 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java index 40b04c3f..b5b06743 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java @@ -24,6 +24,92 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { private final IFilter filter = new KotlinCoroutineFilter(); + @Test + public void should_filter_suspending_lambdas_generated_by_Kotlin_1_3_30() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "invokeSuspend", "(Ljava/lang/Object;)Ljava/lang/Object;", null, + null); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + m.visitLabel(new Label()); + final Range range1 = new Range(); + range1.fromInclusive = m.instructions.getLast(); + m.visitMethodInsn(Opcodes.INVOKESTATIC, + "kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false); + m.visitVarInsn(Opcodes.ASTORE, 4); + + m.visitVarInsn(Opcodes.ALOAD, 0); + // line of "runBlocking" + m.visitFieldInsn(Opcodes.GETFIELD, "Target", "label", "I"); + final Label dflt = new Label(); + final Label state0 = new Label(); + final Label state1 = new Label(); + m.visitTableSwitchInsn(0, 1, dflt, state0, state1); + + m.visitLabel(state0); + + { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt", + "throwOnFailure", "", false); + range1.toInclusive = m.instructions.getLast(); + } + + // line before "suspendingFunction" + m.visitInsn(Opcodes.NOP); + + // line of "suspendingFunction" + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false); + + m.visitInsn(Opcodes.DUP); + final Range range2 = new Range(); + range2.fromInclusive = m.instructions.getLast(); + m.visitVarInsn(Opcodes.ALOAD, 4); + final Label continuationLabelAfterLoadedResult = new Label(); + m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult); + // line of "runBlocking" + m.visitVarInsn(Opcodes.ALOAD, 4); + m.visitInsn(Opcodes.ARETURN); + + m.visitLabel(state1); + + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitFieldInsn(Opcodes.GETFIELD, "Target", "I$0", "I"); + m.visitVarInsn(Opcodes.ISTORE, 3); + + { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt", + "throwOnFailure", "", false); + } + m.visitVarInsn(Opcodes.ALOAD, 1); + range2.toInclusive = m.instructions.getLast(); + m.visitLabel(continuationLabelAfterLoadedResult); + + // line after "suspendingFunction" + m.visitInsn(Opcodes.NOP); + m.visitInsn(Opcodes.ARETURN); + + m.visitLabel(dflt); + final Range range0 = new Range(); + range0.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException"); + m.visitInsn(Opcodes.DUP); + m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine"); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "java/lang/IllegalStateException", "<init>", + "(Ljava/lang/String;)V", false); + m.visitInsn(Opcodes.ATHROW); + range0.toInclusive = m.instructions.getLast(); + + filter.filter(m, context, output); + + assertIgnored(range0, range1, range2); + } + /** * <pre> * runBlocking { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index b1d448af..e2bed498 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -73,13 +73,7 @@ public final class KotlinCoroutineFilter implements IFilter { s.labels.size() * 2); nextIs(Opcodes.ALOAD); - nextIs(Opcodes.DUP); - nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); - nextIs(Opcodes.IFEQ); - nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); - nextIs(Opcodes.GETFIELD); - nextIs(Opcodes.ATHROW); - nextIs(Opcodes.POP); + nextIsThrowOnFailure(); if (cursor == null) { return; @@ -109,13 +103,7 @@ public final class KotlinCoroutineFilter implements IFilter { for (AbstractInsnNode j = i; j != null; j = j.getNext()) { cursor = j; nextIs(Opcodes.ALOAD); - nextIs(Opcodes.DUP); - nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); - nextIs(Opcodes.IFEQ); - nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); - nextIs(Opcodes.GETFIELD); - nextIs(Opcodes.ATHROW); - nextIs(Opcodes.POP); + nextIsThrowOnFailure(); nextIs(Opcodes.ALOAD); if (cursor != null && skipNonOpcodes(cursor @@ -149,6 +137,24 @@ public final class KotlinCoroutineFilter implements IFilter { } } + private void nextIsThrowOnFailure() { + final AbstractInsnNode c = cursor; + nextIsInvokeStatic("kotlin/ResultKt", "throwOnFailure"); + if (cursor == null) { + cursor = c; + // Before resolution of + // https://youtrack.jetbrains.com/issue/KT-28015 in + // Kotlin 1.3.30 + nextIs(Opcodes.DUP); + nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + nextIs(Opcodes.IFEQ); + nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + nextIs(Opcodes.GETFIELD); + nextIs(Opcodes.ATHROW); + nextIs(Opcodes.POP); + } + } + private void nextIsCreateStateInstance() { nextIs(Opcodes.INSTANCEOF); diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index b1c9f715..c9109e96 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,14 @@ <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2> +<h3>New Features</h3> + +<ul> + <li>Branches added by the Kotlin compiler version 1.3.30 for suspending lambdas + and functions are filtered out during generation of report + (GitHub <a href="https://github.com/jacoco/jacoco/issues/849">#849</a>).</li> +</ul> + <h2>Release 0.8.3 (2019/01/23)</h2> <h3>New Features</h3> |