aboutsummaryrefslogtreecommitdiff
path: root/org.jacoco.core/src/org/jacoco/core/internal
diff options
context:
space:
mode:
authorEvgeny Mandrikov <Godin@users.noreply.github.com>2018-12-26 07:43:03 +0100
committerMarc R. Hoffmann <hoffmann@mountainminds.com>2018-12-26 07:43:03 +0100
commit3b8df21b64ec1e581c620b7a12483d7a6ee1655b (patch)
tree60b3f999c4891d3d1c8228aa6940618e38d954d1 /org.jacoco.core/src/org/jacoco/core/internal
parentccad8eb36a13e9500a20da82cd5535a96c56e369 (diff)
downloadjacoco-3b8df21b64ec1e581c620b7a12483d7a6ee1655b.tar.gz
Update filter for Kotlin coroutines that restore state (#803)
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core/internal')
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java10
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java52
2 files changed, 43 insertions, 19 deletions
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
index 2ae1499b..ca7fb9ac 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
@@ -158,11 +158,21 @@ abstract class AbstractMatcher {
* {@link AbstractInsnNode#LABEL}, {@link AbstractInsnNode#LINE}.
*/
final void skipNonOpcodes() {
+ cursor = skipNonOpcodes(cursor);
+ }
+
+ /**
+ * Returns first instruction from given and following it that is not
+ * {@link AbstractInsnNode#FRAME}, {@link AbstractInsnNode#LABEL},
+ * {@link AbstractInsnNode#LINE}.
+ */
+ static AbstractInsnNode skipNonOpcodes(AbstractInsnNode cursor) {
while (cursor != null && (cursor.getType() == AbstractInsnNode.FRAME
|| cursor.getType() == AbstractInsnNode.LABEL
|| cursor.getType() == AbstractInsnNode.LINE)) {
cursor = cursor.getNext();
}
+ return cursor;
}
}
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 f2ecd340..f1261b22 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
@@ -16,6 +16,7 @@ import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
@@ -72,32 +73,45 @@ public final class KotlinCoroutineFilter implements IFilter {
ignore.add(s);
ignore.add(cursor);
- for (AbstractInsnNode i = methodNode.instructions
- .getFirst(); i != null; i = i.getNext()) {
+ int suspensionPoint = 1;
+ for (AbstractInsnNode i = cursor; i != null
+ && suspensionPoint < s.labels.size(); i = i.getNext()) {
cursor = i;
nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED");
nextIs(Opcodes.IF_ACMPNE);
+ if (cursor == null) {
+ continue;
+ }
+ final AbstractInsnNode continuationAfterLoadedResult = skipNonOpcodes(
+ (((JumpInsnNode) cursor)).label);
nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED");
nextIs(Opcodes.ARETURN);
-
- 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);
-
- nextIs(Opcodes.ALOAD);
- if (cursor != null) {
- ignore.add(i);
- ignore.add(cursor);
+ if (cursor == null
+ || skipNonOpcodes(cursor.getNext()) != skipNonOpcodes(
+ s.labels.get(suspensionPoint))) {
+ continue;
}
- }
- if (ignore.size() != s.labels.size() * 2) {
- return;
+ 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);
+
+ nextIs(Opcodes.ALOAD);
+ if (cursor != null && skipNonOpcodes(cursor
+ .getNext()) == continuationAfterLoadedResult) {
+ ignore.add(i);
+ ignore.add(cursor);
+ suspensionPoint++;
+ break;
+ }
+ }
}
cursor = s.dflt;