Skip to content

Commit 04fe200

Browse files
authored
Add filter for Kotlin default methods (bazel-contrib#1012)
1 parent 5b225e7 commit 04fe200

File tree

6 files changed

+199
-1
lines changed

6 files changed

+199
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2009, 2020 Mountainminds GmbH & Co. KG and Contributors
3+
* This program and the accompanying materials are made available under
4+
* the terms of the Eclipse Public License 2.0 which is available at
5+
* http://www.eclipse.org/legal/epl-2.0
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Evgeny Mandrikov - initial API and implementation
11+
*
12+
*******************************************************************************/
13+
package org.jacoco.core.test.validation.kotlin;
14+
15+
import org.jacoco.core.test.validation.ValidationTestBase;
16+
import org.jacoco.core.test.validation.kotlin.targets.KotlinDefaultMethodsTarget;
17+
18+
/**
19+
* Test of code coverage in {@link KotlinDefaultMethodsTarget}.
20+
*/
21+
public class KotlinDefaultMethodsTest extends ValidationTestBase {
22+
23+
public KotlinDefaultMethodsTest() {
24+
super(KotlinDefaultMethodsTarget.class);
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2009, 2020 Mountainminds GmbH & Co. KG and Contributors
3+
* This program and the accompanying materials are made available under
4+
* the terms of the Eclipse Public License 2.0 which is available at
5+
* http://www.eclipse.org/legal/epl-2.0
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Evgeny Mandrikov - initial API and implementation
11+
*
12+
*******************************************************************************/
13+
package org.jacoco.core.test.validation.kotlin.targets
14+
15+
/**
16+
* This test target contains class implementing interface with default methods.
17+
*/
18+
object KotlinDefaultMethodsTarget {
19+
20+
interface I {
21+
fun m1() = Unit // assertNotCovered()
22+
fun m2() = Unit // assertFullyCovered()
23+
fun m3() = Unit // assertNotCovered()
24+
}
25+
26+
class C : I { // assertFullyCovered()
27+
override fun m1() = Unit // assertFullyCovered()
28+
}
29+
30+
@JvmStatic
31+
fun main(args: Array<String>) {
32+
C().m1()
33+
C().m2()
34+
}
35+
36+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2009, 2020 Mountainminds GmbH & Co. KG and Contributors
3+
* This program and the accompanying materials are made available under
4+
* the terms of the Eclipse Public License 2.0 which is available at
5+
* http://www.eclipse.org/legal/epl-2.0
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Evgeny Mandrikov - initial API and implementation
11+
*
12+
*******************************************************************************/
13+
package org.jacoco.core.internal.analysis.filter;
14+
15+
import org.jacoco.core.internal.instr.InstrSupport;
16+
import org.junit.Test;
17+
import org.objectweb.asm.Opcodes;
18+
import org.objectweb.asm.tree.MethodNode;
19+
20+
/**
21+
* Unit test for {@link KotlinDefaultMethodsFilter}.
22+
*/
23+
public class KotlinDefaultMethodsFilterTest extends FilterTestBase {
24+
25+
private final IFilter filter = new KotlinDefaultMethodsFilter();
26+
27+
@Test
28+
public void should_filter() {
29+
context.classAnnotations
30+
.add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
31+
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
32+
"m", "()V", null, null);
33+
m.visitVarInsn(Opcodes.ALOAD, 0);
34+
m.visitMethodInsn(Opcodes.INVOKESTATIC, "Target$DefaultImpls", "m",
35+
"(LTarget;)V", false);
36+
m.visitInsn(Opcodes.RETURN);
37+
38+
filter.filter(m, context, output);
39+
40+
assertMethodIgnored(m);
41+
}
42+
43+
@Test
44+
public void should_not_filter_when_invokestatic_owner_does_not_match() {
45+
context.classAnnotations
46+
.add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
47+
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
48+
"m", "()V", null, null);
49+
m.visitVarInsn(Opcodes.ALOAD, 0);
50+
m.visitMethodInsn(Opcodes.INVOKESTATIC, "Target", "m", "(LTarget;)V",
51+
false);
52+
m.visitInsn(Opcodes.RETURN);
53+
54+
filter.filter(m, context, output);
55+
56+
assertIgnored();
57+
}
58+
59+
@Test
60+
public void should_not_filter_when_instructions_do_not_match() {
61+
context.classAnnotations
62+
.add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
63+
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
64+
"m", "()V", null, null);
65+
m.visitInsn(Opcodes.RETURN);
66+
67+
filter.filter(m, context, output);
68+
69+
assertIgnored();
70+
}
71+
72+
@Test
73+
public void should_not_filter_when_not_kotlin() {
74+
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
75+
"m", "()V", null, null);
76+
m.visitVarInsn(Opcodes.ALOAD, 0);
77+
m.visitMethodInsn(Opcodes.INVOKESTATIC, "Target$DefaultImpls", "m",
78+
"(LTarget;)V", false);
79+
m.visitInsn(Opcodes.RETURN);
80+
81+
filter.filter(m, context, output);
82+
83+
assertIgnored();
84+
}
85+
86+
}

org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static IFilter all() {
4646
new KotlinUnsafeCastOperatorFilter(),
4747
new KotlinNotNullOperatorFilter(),
4848
new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter(),
49-
new KotlinCoroutineFilter());
49+
new KotlinCoroutineFilter(), new KotlinDefaultMethodsFilter());
5050
}
5151

5252
private Filters(final IFilter... filters) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2009, 2020 Mountainminds GmbH & Co. KG and Contributors
3+
* This program and the accompanying materials are made available under
4+
* the terms of the Eclipse Public License 2.0 which is available at
5+
* http://www.eclipse.org/legal/epl-2.0
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Evgeny Mandrikov - initial API and implementation
11+
*
12+
*******************************************************************************/
13+
package org.jacoco.core.internal.analysis.filter;
14+
15+
import org.objectweb.asm.Opcodes;
16+
import org.objectweb.asm.tree.MethodInsnNode;
17+
import org.objectweb.asm.tree.MethodNode;
18+
19+
/**
20+
* Filters methods that Kotlin compiler generates for non-overridden
21+
* non-abstract methods of interfaces.
22+
*/
23+
final class KotlinDefaultMethodsFilter implements IFilter {
24+
25+
public void filter(final MethodNode methodNode,
26+
final IFilterContext context, final IFilterOutput output) {
27+
if (!KotlinGeneratedFilter.isKotlinClass(context)) {
28+
return;
29+
}
30+
new Matcher().match(methodNode, output);
31+
}
32+
33+
private static class Matcher extends AbstractMatcher {
34+
private void match(final MethodNode methodNode,
35+
final IFilterOutput output) {
36+
firstIsALoad0(methodNode);
37+
nextIs(Opcodes.INVOKESTATIC);
38+
if (cursor != null && ((MethodInsnNode) cursor).owner
39+
.endsWith("$DefaultImpls")) {
40+
output.ignore(methodNode.instructions.getFirst(),
41+
methodNode.instructions.getLast());
42+
}
43+
}
44+
}
45+
46+
}

org.jacoco.doc/docroot/doc/changes.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ <h3>New Features</h3>
2929
(GitHub <a href="https://github.com/jacoco/jacoco/issues/990">#990</a>).</li>
3030
<li>Bridge methods are filtered out during generation of report
3131
(GitHub <a href="https://github.com/jacoco/jacoco/issues/1010">#1010</a>).</li>
32+
<li>Methods generated by Kotlin compiler for non-overridden non-abstract methods
33+
of interfaces are filtered out during generation of report
34+
(GitHub <a href="https://github.com/jacoco/jacoco/issues/1012">#1012</a>).</li>
3235
</ul>
3336

3437
<h3>Non-functional Changes</h3>

0 commit comments

Comments
 (0)