diff options
author | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2018-10-05 02:09:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-05 02:09:18 +0200 |
commit | 9c6bb3371efdad77175d6bbf3ee139d3b7c9356f (patch) | |
tree | 1dba90cb5eacc4ee711ae9d8a2fb694d917f0601 | |
parent | 37ed339d89dac0cfb528a7e694b9ab3596afac54 (diff) | |
download | jacoco-9c6bb3371efdad77175d6bbf3ee139d3b7c9356f.tar.gz |
Add filter for Kotlin "unsafe" cast operator (#761)
6 files changed, 186 insertions, 1 deletions
diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java new file mode 100644 index 00000000..475d902b --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinUnsafeCastOperatorTarget; + +/** + * Test of "unsafe" cast operator. + */ +public class KotlinUnsafeCastOperatorTest extends ValidationTestBase { + + public KotlinUnsafeCastOperatorTest() { + super(KotlinUnsafeCastOperatorTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt new file mode 100644 index 00000000..a4f5ccda --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.test.validation.kotlin.targets + +/** + * This test target is "unsafe" cast operator. + */ +object KotlinUnsafeCastOperatorTarget { + + private fun nullable(): String? { + return "" + } + + @JvmStatic + fun main(args: Array<String>) { + nullable() as String // assertFullyCovered() + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java new file mode 100644 index 00000000..eb942519 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link KotlinUnsafeCastOperatorFilter}. + */ +public class KotlinUnsafeCastOperatorFilterTest extends FilterTestBase { + + private final KotlinUnsafeCastOperatorFilter filter = new KotlinUnsafeCastOperatorFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + @Test + public void should_filter() { + final Label label = new Label(); + + m.visitInsn(Opcodes.DUP); + m.visitJumpInsn(Opcodes.IFNONNULL, label); + final AbstractInsnNode expectedFrom = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "kotlin/TypeCastException"); + m.visitInsn(Opcodes.DUP); + m.visitLdcInsn("null cannot be cast to non-null type kotlin.String"); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "kotlin/TypeCastException", + "<init>", "(Ljava/lang/String;)V", false); + m.visitInsn(Opcodes.ATHROW); + final AbstractInsnNode expectedTo = m.instructions.getLast(); + m.visitLabel(label); + + filter.filter(m, context, output); + + assertIgnored(new Range(expectedFrom, expectedTo)); + } + +} 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 03c85d7d..f6a7a1df 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 @@ -34,7 +34,8 @@ public final class Filters implements IFilter { new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), new EnumEmptyConstructorFilter(), new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), new KotlinLateinitFilter(), - new KotlinWhenFilter(), new KotlinWhenStringFilter()); + new KotlinWhenFilter(), new KotlinWhenStringFilter(), + new KotlinUnsafeCastOperatorFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java new file mode 100644 index 00000000..b65cac27 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * 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.JumpInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters branch in bytecode that Kotlin compiler generates for "unsafe" cast + * operator. + */ +public final class KotlinUnsafeCastOperatorFilter implements IFilter { + + private static final String KOTLIN_TYPE_CAST_EXCEPTION = "kotlin/TypeCastException"; + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + public void match(final AbstractInsnNode start, + final IFilterOutput output) { + + if (Opcodes.IFNONNULL != start.getOpcode()) { + return; + } + cursor = start; + + nextIsNew(KOTLIN_TYPE_CAST_EXCEPTION); + nextIs(Opcodes.DUP); + nextIs(Opcodes.LDC); + if (cursor == null) { + return; + } + final LdcInsnNode ldc = (LdcInsnNode) cursor; + if (!(ldc.cst instanceof String && ((String) ldc.cst) + .startsWith("null cannot be cast to non-null type"))) { + return; + } + nextIsInvokeSuper(KOTLIN_TYPE_CAST_EXCEPTION, + "(Ljava/lang/String;)V"); + nextIs(Opcodes.ATHROW); + if (cursor == null) { + return; + } + if (cursor.getNext() != ((JumpInsnNode) start).label) { + return; + } + + output.ignore(start, cursor); + } + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index dc364940..94184856 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,13 @@ <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2> +<h3>New Features</h3> +<ul> + <li>Branch added by the Kotlin compiler for "unsafe" cast operator is filtered + out during generation of report + (GitHub <a href="https://github.com/jacoco/jacoco/issues/761">#761</a>).</li> +</ul> + <h2>Release 0.8.2 (2018/08/21)</h2> <h3>New Features</h3> |