diff options
author | Fabian Mastenbroek <fabianishere@outlook.com> | 2018-07-11 21:36:11 +0200 |
---|---|---|
committer | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2018-07-11 21:36:11 +0200 |
commit | ce7de98c76b8bd107c05a061193de76d21c4c205 (patch) | |
tree | 5fa095296ab31165b1ac99c2eb1dfc85ea62ff50 | |
parent | c8b8c9d3b7605fc09517c78f385fe31dccf04e31 (diff) | |
download | jacoco-ce7de98c76b8bd107c05a061193de76d21c4c205.tar.gz |
Filter branch generated by kotlinc for reading lateinit properties (#707)
5 files changed, 148 insertions, 1 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java new file mode 100644 index 00000000..a2306f8a --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +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; + +public class KotlinLateinitFilterTest implements IFilterOutput { + private final KotlinLateinitFilter filter = new KotlinLateinitFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + @Test + public void testLateinitBranchIsFiltered() { + final Label l1 = new Label(); + final Label l2 = new Label(); + + m.visitLabel(l1); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitFieldInsn(Opcodes.GETFIELD, + "com/better/alarm/background/VibrationService", "wakeLock", + "Landroid/os/PowerManager$WakeLock;"); + m.visitInsn(Opcodes.DUP); + m.visitJumpInsn(Opcodes.IFNONNULL, l2); + + final AbstractInsnNode expectedFrom = m.instructions.getLast(); + + m.visitLdcInsn("wakelock"); + m.visitMethodInsn(Opcodes.INVOKESTATIC, + "kotlin/jvm/internal/Intrinsics", + "throwUninitializedPropertyAccessException", + "Ljava/lang/String;", false); + final AbstractInsnNode expectedTo = m.instructions.getLast(); + m.visitLabel(l2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "android/os/PowerManager$WakeLock", "acquire", "", false); + filter.filter(m, new FilterContextMock(), this); + + assertEquals(expectedFrom, fromInclusive); + assertEquals(expectedTo, toInclusive); + } + + public void ignore(AbstractInsnNode fromInclusive, + AbstractInsnNode toInclusive) { + assertNull(this.fromInclusive); + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + + public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { + fail(); + } +} 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 fcd1c888..d4b421ef 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 @@ -67,6 +67,18 @@ abstract class AbstractMatcher { cursor = null; } + final void nextIsInvokeStatic(final String owner, final String name) { + nextIs(Opcodes.INVOKESTATIC); + if (cursor == null) { + return; + } + final MethodInsnNode m = (MethodInsnNode) cursor; + if (owner.equals(m.owner) && name.equals(m.name)) { + return; + } + cursor = null; + } + final void nextIsVar(final int opcode, final String name) { nextIs(opcode); if (cursor == null) { 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 cafb1f77..b235e1e6 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 @@ -32,7 +32,7 @@ public final class Filters implements IFilter { new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), new StringSwitchJavacFilter(), new LombokGeneratedFilter(), new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter(), - new KotlinGeneratedFilter()); + new KotlinGeneratedFilter(), new KotlinLateinitFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java new file mode 100644 index 00000000..c1aee3ad --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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: + * Fabian Mastenbroek - 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.MethodNode; + +/** + * Filters branch in bytecode that Kotlin compiler generates for reading from + * <code>lateinit</code> properties. + */ +public class KotlinLateinitFilter implements IFilter { + + private final static String OWNER = "kotlin/jvm/internal/Intrinsics"; + private final static String NAME = "throwUninitializedPropertyAccessException"; + + public void filter(final MethodNode methodNode, final IFilterContext context, + final IFilterOutput output) { + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + if (i.getOpcode() != Opcodes.IFNONNULL) { + continue; + } + + final AbstractInsnNode end = new Matcher(i).match(); + + if (end != null) { + output.ignore(i, end); + } + } + } + + private static class Matcher extends AbstractMatcher { + private final AbstractInsnNode start; + + private Matcher(final AbstractInsnNode start) { + this.start = start; + } + + private AbstractInsnNode match() { + cursor = start; + nextIs(Opcodes.LDC); + nextIsInvokeStatic(OWNER, NAME); + return cursor; + } + } +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index c5930d39..02dc8cb1 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -27,6 +27,10 @@ <li>Methods added by the Kotlin compiler are filtered out during generation of report. Idea and implementation by Nikolay Krasko (GitHub <a href="https://github.com/jacoco/jacoco/issues/689">#689</a>).</li> + <li>Branch added by the Kotlin compiler for reading from <code>lateinit</code> + property is filtered out during generation of report. Implementation by + Fabian Mastenbroek + (GitHub <a href="https://github.com/jacoco/jacoco/issues/707">#707</a>).</li> </ul> <h3>Fixed Bugs</h3> |