aboutsummaryrefslogtreecommitdiff
path: root/org.jacoco.core/src/org/jacoco
diff options
context:
space:
mode:
authorEvgeny Mandrikov <Godin@users.noreply.github.com>2018-08-07 12:23:47 +0200
committerGitHub <noreply@github.com>2018-08-07 12:23:47 +0200
commit82087743dfec23b585e31b8c8c1f9adff5b8288f (patch)
tree49febd2a055959a0e5db4a659886b5e5764c91cb /org.jacoco.core/src/org/jacoco
parenta364dcc69503baa790e84691e4b34fc76a2e47a2 (diff)
downloadjacoco-82087743dfec23b585e31b8c8c1f9adff5b8288f.tar.gz
Add filter for Kotlin when-expressions that list all cases of sealed class (#721)
Diffstat (limited to 'org.jacoco.core/src/org/jacoco')
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java17
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java3
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java62
3 files changed, 81 insertions, 1 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 d4b421ef..9e07153b 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
@@ -18,6 +18,7 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
abstract class AbstractMatcher {
@@ -41,6 +42,22 @@ abstract class AbstractMatcher {
}
/**
+ * Moves {@link #cursor} to next instruction if it is <code>NEW</code> with
+ * given operand, otherwise sets it to <code>null</code>.
+ */
+ final void nextIsNew(final String desc) {
+ nextIs(Opcodes.NEW);
+ if (cursor == null) {
+ return;
+ }
+ final TypeInsnNode i = (TypeInsnNode) cursor;
+ if (desc.equals(i.desc)) {
+ return;
+ }
+ cursor = null;
+ }
+
+ /**
* Moves {@link #cursor} to next instruction if it is
* <code>INVOKESPECIAL &lt;init&gt;</code> with given owner and descriptor,
* otherwise sets it to <code>null</code>.
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java
index 68e9b234..2e719221 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java
@@ -33,7 +33,8 @@ public final class Filters implements IFilter {
new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(),
new StringSwitchJavacFilter(), new LombokGeneratedFilter(),
new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter(),
- new KotlinGeneratedFilter(), new KotlinLateinitFilter());
+ new KotlinGeneratedFilter(), new KotlinLateinitFilter(),
+ new KotlinWhenSealedFilter());
private final IFilter[] filters;
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java
new file mode 100644
index 00000000..ae0d8455
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters bytecode that Kotlin compiler generates for <code>when</code>
+ * expressions which list all cases of <code>sealed class</code>, i.e. which
+ * don't require explicit <code>else</code>.
+ */
+public final class KotlinWhenSealedFilter implements IFilter {
+
+ private static final String EXCEPTION = "kotlin/NoWhenBranchMatchedException";
+
+ private final Matcher matcher = new Matcher();
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ void match(final AbstractInsnNode start, final IFilterOutput output) {
+ if (start.getType() != InsnNode.LABEL) {
+ return;
+ }
+ cursor = start;
+
+ nextIsNew(EXCEPTION);
+ nextIs(Opcodes.DUP);
+ nextIsInvokeSuper(EXCEPTION, "()V");
+ nextIs(Opcodes.ATHROW);
+
+ for (AbstractInsnNode i = cursor; i != null; i = i.getPrevious()) {
+ if (i.getOpcode() == Opcodes.IFEQ
+ && ((JumpInsnNode) i).label == start) {
+ output.ignore(i, i);
+ output.ignore(start, cursor);
+ return;
+ }
+ }
+ }
+ }
+
+}