diff options
author | Evgeny Mandrikov <138671+Godin@users.noreply.github.com> | 2019-06-05 16:26:40 +0200 |
---|---|---|
committer | Marc R. Hoffmann <hoffmann@mountainminds.com> | 2019-06-05 16:26:40 +0200 |
commit | 219088deac4b5af5d5c7346da65042894585d5c4 (patch) | |
tree | 0b04e2680aaf018ee1130c52648fd49b7480b608 | |
parent | fcb8ba138c05044aef4cf69808980d212ae1d7f0 (diff) | |
download | jacoco-219088deac4b5af5d5c7346da65042894585d5c4.tar.gz |
Do not filter out synthetic constructors that contain values of default arguments in Kotlin (#888)
6 files changed, 95 insertions, 12 deletions
diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDefaultArgumentsTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDefaultArgumentsTarget.kt index c2922812..1a89eaba 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDefaultArgumentsTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDefaultArgumentsTarget.kt @@ -27,6 +27,10 @@ object KotlinDefaultArgumentsTarget { } } + class Constructor() { + constructor(a: Boolean, b: String = if (a) "a" else "b") : this() // assertFullyCovered(0, 2) + } + @JvmStatic fun main(args: Array<String>) { f(a = "a") @@ -38,6 +42,9 @@ object KotlinDefaultArgumentsTarget { branch(true) Open().f() + + Constructor(false) + Constructor(true) } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java index 8e79a5a7..721abfb0 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java @@ -150,4 +150,38 @@ public class KotlinDefaultArgumentsFilterTest extends FilterTestBase { new Range(m.instructions.get(11), m.instructions.get(11))); } + /** + * <pre> + * class C(a: Int = 42) + * </pre> + */ + @Test + public void should_filter_constructors() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_SYNTHETIC, "<init>", + "(IILkotlin/jvm/internal/DefaultConstructorMarker;)V", null, + null); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + m.visitVarInsn(Opcodes.ILOAD, 2); + m.visitInsn(Opcodes.ICONST_1); + m.visitInsn(Opcodes.IAND); + Label label = new Label(); + m.visitJumpInsn(Opcodes.IFEQ, label); + // default argument + m.visitLdcInsn(Integer.valueOf(42)); + m.visitVarInsn(Opcodes.ISTORE, 1); + m.visitLabel(label); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitVarInsn(Opcodes.ILOAD, 1); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "Owner", "<init>", "(I)V", + false); + m.visitInsn(Opcodes.RETURN); + + filter.filter(m, context, output); + + assertIgnored(new Range(m.instructions.get(3), m.instructions.get(3))); + } + } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java index 5bbae983..5b0a30ba 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java @@ -83,6 +83,21 @@ public class SyntheticFilterTest extends FilterTestBase { } @Test + public void should_not_filter_synthetic_constructor_containing_default_arguments_in_kotlin_classes() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_SYNTHETIC, "<init>", + "(IILkotlin/jvm/internal/DefaultConstructorMarker;)V", null, + null); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + m.visitInsn(Opcodes.NOP); + + filter.filter(m, context, output); + + assertIgnored(); + } + + @Test public void should_not_filter_synthetic_methods_whose_last_argument_is_kotlin_coroutine_continuation() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC, "example", diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java index 34f9562c..a7a05cf7 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java @@ -38,14 +38,28 @@ import org.objectweb.asm.tree.VarInsnNode; * </pre> * * Where <code>maskVar</code> is penultimate argument of synthetic method with - * suffix "$default". And its value can't be zero - invocation with all - * arguments uses original non synthetic method, thus <code>IFEQ</code> - * instructions should be ignored. + * suffix "$default" or of synthetic constructor with last argument + * "kotlin.jvm.internal.DefaultConstructorMarker". And its value can't be zero - + * invocation with all arguments uses original non synthetic method, thus + * <code>IFEQ</code> instructions should be ignored. */ public final class KotlinDefaultArgumentsFilter implements IFilter { - static boolean isDefaultArgumentsMethodName(final String methodName) { - return methodName.endsWith("$default"); + static boolean isDefaultArgumentsMethod(final MethodNode methodNode) { + return methodNode.name.endsWith("$default"); + } + + static boolean isDefaultArgumentsConstructor(final MethodNode methodNode) { + if (!"<init>".equals(methodNode.name)) { + return false; + } + final Type[] argumentTypes = Type.getMethodType(methodNode.desc) + .getArgumentTypes(); + if (argumentTypes.length < 2) { + return false; + } + return "kotlin.jvm.internal.DefaultConstructorMarker" + .equals(argumentTypes[argumentTypes.length - 1].getClassName()); } public void filter(final MethodNode methodNode, @@ -53,19 +67,20 @@ public final class KotlinDefaultArgumentsFilter implements IFilter { if ((methodNode.access & Opcodes.ACC_SYNTHETIC) == 0) { return; } - if (!isDefaultArgumentsMethodName(methodNode.name)) { - return; - } if (!KotlinGeneratedFilter.isKotlinClass(context)) { return; } - new Matcher().match(methodNode, output); + if (isDefaultArgumentsMethod(methodNode)) { + new Matcher().match(methodNode, output, false); + } else if (isDefaultArgumentsConstructor(methodNode)) { + new Matcher().match(methodNode, output, true); + } } private static class Matcher extends AbstractMatcher { public void match(final MethodNode methodNode, - final IFilterOutput output) { + final IFilterOutput output, final boolean constructor) { cursor = methodNode.instructions.getFirst(); nextIs(Opcodes.IFNULL); @@ -91,7 +106,7 @@ public final class KotlinDefaultArgumentsFilter implements IFilter { final Set<AbstractInsnNode> ignore = new HashSet<AbstractInsnNode>(); final int maskVar = Type.getMethodType(methodNode.desc) - .getArgumentTypes().length - 2; + .getArgumentTypes().length - (constructor ? 1 : 2); while (true) { if (cursor.getOpcode() != Opcodes.ILOAD) { break; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java index 69c4092a..46d4e6eb 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java @@ -31,7 +31,12 @@ public final class SyntheticFilter implements IFilter { if (KotlinGeneratedFilter.isKotlinClass(context)) { if (KotlinDefaultArgumentsFilter - .isDefaultArgumentsMethodName(methodNode.name)) { + .isDefaultArgumentsMethod(methodNode)) { + return; + } + + if (KotlinDefaultArgumentsFilter + .isDefaultArgumentsConstructor(methodNode)) { return; } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 252d7db7..25087b3a 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -27,6 +27,13 @@ (GitHub <a href="https://github.com/jacoco/jacoco/issues/887">#887</a>).</li> </ul> +<h3>Fixed bugs</h3> +<ul> + <li><code>synthetic</code> constructors that contain values of default arguments + in Kotlin should not be ignored + (GitHub <a href="https://github.com/jacoco/jacoco/issues/888">#888</a>).</li> +</ul> + <h2>Release 0.8.4 (2019/05/08)</h2> <h3>New Features</h3> |