Skip to content

Commit de76181

Browse files
authored
KotlinSerializableFilter should filter more methods (#1971)
1 parent 89c4bd5 commit de76181

File tree

10 files changed

+276
-38
lines changed

10 files changed

+276
-38
lines changed

org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSerializableEnumTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import org.jacoco.core.test.validation.ValidationTestBase;
1616
import org.jacoco.core.test.validation.kotlin.targets.KotlinSerializableEnumTarget;
17+
import org.junit.Test;
1718

1819
/**
1920
* Test of code coverage in {@link KotlinSerializableEnumTarget}.
@@ -24,4 +25,9 @@ public KotlinSerializableEnumTest() {
2425
super(KotlinSerializableEnumTarget.class);
2526
}
2627

28+
@Test
29+
public void test_method_count() {
30+
assertMethodCount(/* main + static initializer */2);
31+
}
32+
2733
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2009, 2025 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.KotlinSerializableObjectTarget;
17+
import org.junit.Test;
18+
19+
/**
20+
* Test of code coverage in {@link KotlinSerializableObjectTarget}.
21+
*/
22+
public class KotlinSerializableObjectTest extends ValidationTestBase {
23+
24+
public KotlinSerializableObjectTest() {
25+
super(KotlinSerializableObjectTarget.class);
26+
}
27+
28+
@Test
29+
public void test_method_count() {
30+
assertMethodCount(/* main + static initializer */2);
31+
}
32+
33+
}

org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSerializableSealedTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
*******************************************************************************/
1313
package org.jacoco.core.test.validation.kotlin;
1414

15+
import java.util.Collection;
16+
import java.util.Collections;
17+
1518
import org.jacoco.core.test.validation.ValidationTestBase;
1619
import org.jacoco.core.test.validation.kotlin.targets.KotlinSerializableSealedTarget;
20+
import org.junit.Test;
1721

1822
/**
1923
* Test of code coverage in {@link KotlinSerializableSealedTarget}.
@@ -24,4 +28,16 @@ public KotlinSerializableSealedTest() {
2428
super(KotlinSerializableSealedTarget.class);
2529
}
2630

31+
@Override
32+
protected Collection<String> additionalClassesForAnalysis() {
33+
return Collections.singletonList(
34+
"org.jacoco.core.test.validation.kotlin.targets.KotlinSerializableSealedTarget$Sealed$A$$serializer");
35+
}
36+
37+
@Test
38+
public void test_method_count() {
39+
assertMethodCount(
40+
/* main + static initializer + constructor + getter */4);
41+
}
42+
2743
}

org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSerializableTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
*******************************************************************************/
1313
package org.jacoco.core.test.validation.kotlin;
1414

15+
import java.util.Collection;
16+
import java.util.Collections;
17+
1518
import org.jacoco.core.test.validation.ValidationTestBase;
1619
import org.jacoco.core.test.validation.kotlin.targets.KotlinSerializableTarget;
1720
import org.junit.Test;
@@ -25,6 +28,12 @@ public KotlinSerializableTest() {
2528
super(KotlinSerializableTarget.class);
2629
}
2730

31+
@Override
32+
protected Collection<String> additionalClassesForAnalysis() {
33+
return Collections.singletonList(
34+
"org.jacoco.core.test.validation.kotlin.targets.KotlinSerializableTarget$Example$$serializer");
35+
}
36+
2837
@Test
2938
public void test_method_count() {
3039
assertMethodCount(

org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSerializableEnumTarget.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import kotlinx.serialization.Serializable
1919
*/
2020
object KotlinSerializableEnumTarget {
2121

22-
@Serializable
23-
enum class E {
24-
V
25-
}
22+
@Serializable // assertFullyCovered()
23+
enum class E { // assertEmpty()
24+
V // assertFullyCovered()
25+
} // assertFullyCovered()
2626

2727
@JvmStatic
2828
fun main(args: Array<String>) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2009, 2025 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+
import kotlinx.serialization.Serializable
16+
17+
/**
18+
* Test target with [Serializable] `object`.
19+
*/
20+
object KotlinSerializableObjectTarget {
21+
22+
@Serializable // assertFullyCovered()
23+
private object Example { // assertEmpty()
24+
} // assertFullyCovered()
25+
26+
@JvmStatic
27+
fun main(args: Array<String>) {
28+
Example.toString()
29+
}
30+
31+
}

org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSerializableSealedTarget.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ import kotlinx.serialization.Serializable
1919
*/
2020
object KotlinSerializableSealedTarget {
2121

22-
@Serializable
23-
private sealed class Sealed {
24-
@Serializable
25-
data class A(val data: String): Sealed()
26-
}
22+
@Serializable // assertFullyCovered()
23+
private sealed class Sealed { // assertEmpty()
24+
@Serializable // assertFullyCovered()
25+
data class A( // assertFullyCovered()
26+
val data: String // assertFullyCovered()
27+
): Sealed() // assertEmpty()
28+
} // assertFullyCovered()
2729

2830
@JvmStatic
2931
fun main(args: Array<String>) {

org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinSerializableFilterTest.java

Lines changed: 129 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ public void should_not_filter_hand_written_serializer_method() {
172172
}
173173

174174
/**
175+
* <code>Example.serializer</code> in case of
176+
*
177+
* <pre>
178+
* &#064;kotlinx.serialization.Serializable // line 1
179+
* object Example
180+
* </pre>
181+
*
182+
* <code>Example$Companion.serializer</code> in case of
183+
*
175184
* <pre>
176185
* &#064;kotlinx.serialization.Serializable // line 1
177186
* enum class Example {
@@ -181,20 +190,12 @@ public void should_not_filter_hand_written_serializer_method() {
181190
*
182191
* <pre>
183192
* &#064;kotlinx.serialization.Serializable // line 1
184-
* sealed class Example {
185-
* }
193+
* sealed class Example
186194
* </pre>
187195
*/
188196
@Test
189-
public void should_filter_generated_serializer_method_in_companions_of_enum_and_sealed_class() {
190-
context.className = "Example$Companion";
191-
192-
final MethodNode initMethod = new MethodNode(Opcodes.ACC_PRIVATE,
193-
"<init>", "()V", null, null);
194-
final Label initMethodLineNumberLabel = new Label();
195-
initMethod.visitLabel(initMethodLineNumberLabel);
196-
initMethod.visitLineNumber(1, initMethodLineNumberLabel);
197-
filter.filter(initMethod, context, output);
197+
public void should_filter_generated_serializer_method_in_objects_and_companions_of_enum_and_sealed_class() {
198+
context.className = "Example";
198199

199200
final MethodNode m = new MethodNode(
200201
Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "serializer",
@@ -204,15 +205,129 @@ public void should_filter_generated_serializer_method_in_companions_of_enum_and_
204205
m.visitLabel(label0);
205206
m.visitLineNumber(1, label0);
206207
m.visitVarInsn(Opcodes.ALOAD, 0);
207-
m.visitMethodInsn(Opcodes.INVOKESPECIAL, "Example$Companion",
208+
m.visitMethodInsn(Opcodes.INVOKESPECIAL, "Example",
208209
"get$cachedSerializer", "()Lkotlinx/serialization/KSerializer;",
209210
false);
210211
m.visitInsn(Opcodes.ARETURN);
211212

212213
filter.filter(m, context, output);
213214

214-
// FIXME https://github.com/jacoco/jacoco/issues/1971
215-
assertIgnored(m);
215+
assertMethodIgnored(m);
216+
}
217+
218+
/**
219+
* <code>Example.get$cachedSerializer</code> in case of
220+
*
221+
* <pre>
222+
* &#064;kotlinx.serialization.Serializable
223+
* object Example
224+
* </pre>
225+
*
226+
* <code>Example$Companion.get$cachedSerializer</code> in case of
227+
*
228+
* <pre>
229+
* &#064;kotlinx.serialization.Serializable
230+
* enum class Example {
231+
* V
232+
* }
233+
* </pre>
234+
*
235+
* <pre>
236+
* &#064;kotlinx.serialization.Serializable
237+
* sealed class Example
238+
* </pre>
239+
*/
240+
@Test
241+
public void should_filter_synthetic_get_cachedSerializer_method() {
242+
context.className = "Example";
243+
244+
MethodNode m = new MethodNode(
245+
Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
246+
"get$cachedSerializer", "()Lkotlinx/serialization/KSerializer;",
247+
null, null);
248+
m.visitInsn(Opcodes.NOP);
249+
250+
filter.filter(m, context, output);
251+
252+
assertMethodIgnored(m);
253+
}
254+
255+
/**
256+
* <pre>
257+
* &#064;kotlinx.serialization.Serializable
258+
* object Example
259+
* </pre>
260+
*
261+
* <pre>
262+
* &#064;kotlinx.serialization.Serializable
263+
* enum class Example
264+
* </pre>
265+
*
266+
* <pre>
267+
* &#064;kotlinx.serialization.Serializable
268+
* sealed class Example
269+
* </pre>
270+
*
271+
* lazy initializer
272+
*
273+
* <pre>
274+
* $cachedSerializer$delegate = lazy { ... }
275+
* </pre>
276+
*
277+
* not executed when serializer is not used
278+
*
279+
* https://github.com/JetBrains/kotlin/commit/3f034e8b6735a50ed5733e82811fc2bdb73f5632
280+
*/
281+
@Test
282+
public void should_filter_synthetic_lazy_cachedSerializer() {
283+
context.className = "Example";
284+
285+
final MethodNode m = new MethodNode(
286+
Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC
287+
| Opcodes.ACC_SYNTHETIC,
288+
"_init_$_anonymous_", "()Lkotlinx/serialization/KSerializer;",
289+
null, null);
290+
m.visitInsn(Opcodes.NOP);
291+
292+
filter.filter(m, context, output);
293+
294+
assertMethodIgnored(m);
295+
}
296+
297+
/**
298+
* <pre>
299+
* &#064;kotlinx.serialization.Serializable
300+
* data class Example(
301+
* val data1: List&lt;String&gt;,
302+
* val data2: List&lt;String&gt;,
303+
* )
304+
* </pre>
305+
*
306+
* lazy initializer
307+
*
308+
* <pre>
309+
* $childSerializers = arrayOf(lazy { ... }, lazy { ... })
310+
* </pre>
311+
*
312+
* not executed when serializer is not used
313+
*
314+
* https://github.com/JetBrains/kotlin/commit/b35161e241df6a7b245b5a5d81232b0ea5a3129a
315+
* https://github.com/JetBrains/kotlin/commit/3f034e8b6735a50ed5733e82811fc2bdb73f5632
316+
*/
317+
@Test
318+
public void should_filter_synthetic_lazy_childSerializers() {
319+
context.className = "Example";
320+
321+
final MethodNode m = new MethodNode(
322+
Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC
323+
| Opcodes.ACC_SYNTHETIC,
324+
"_childSerializers$_anonymous_$0",
325+
"()Lkotlinx/serialization/KSerializer;", null, null);
326+
m.visitInsn(Opcodes.NOP);
327+
328+
filter.filter(m, context, output);
329+
330+
assertMethodIgnored(m);
216331
}
217332

218333
}

0 commit comments

Comments
 (0)