Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Lateinit unreachable code #5

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,32 @@ import org.jacoco.core.test.validation.targets.Stubs.nop
*/
object KotlinLateinitTarget {
private lateinit var x: String
lateinit var y: String

private class Example<T: Any> {
private lateinit var x: T
private lateinit var xx: Any
lateinit var y: T
lateinit var yy: Any
fun nop() {
x = Any() as T
xx = Any()
y = Any() as T
yy = Any()
nop(x) // assertFullyCovered()
nop(xx) // assertFullyCovered()
nop(y) // assertFullyCovered()
nop(yy) // assertFullyCovered()
}
}

@JvmStatic
fun main(args: Array<String>) {
x = ""
y = ""

nop(x) // assertFullyCovered()
nop(y) // assertFullyCovered()
Example<Any>().nop() // assertFullyCovered()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ public void testLateinitBranchIsFiltered() {
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitLabel(l2);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"android/os/PowerManager$WakeLock", "acquire", "", false);

Expand All @@ -61,39 +61,341 @@ public void testLateinitBranchIsFiltered() {

/**
* <pre>
* class Example {
* private lateinit var x: String
* fun example() = x
* class LateinitStringPrivate {
* private lateinit var member: String
*
* fun get(): String = member
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_5() {
public void should_filter_Kotlin_1_5_private() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"example", "()Ljava/lang/String;", null, null);
"get", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "Example", "x",
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitStringPrivate", "member",
"Ljava/lang/String;");
m.visitVarInsn(Opcodes.ASTORE, 1);
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitJumpInsn(Opcodes.IFNONNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitLdcInsn("x");
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitInsn(Opcodes.ACONST_NULL);
m.visitInsn(Opcodes.ATHROW);
m.visitLabel(label);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitInsn(Opcodes.ARETURN);

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitStringPublic {
* lateinit var member: String
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_5_public() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"getMember", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitStringPublic", "member",
"Ljava/lang/String;");
m.visitVarInsn(Opcodes.ASTORE, 1);
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitJumpInsn(Opcodes.IFNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitInsn(Opcodes.ARETURN);
m.visitLabel(label);
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitInsn(Opcodes.ACONST_NULL);
m.visitInsn(Opcodes.ATHROW);
final AbstractInsnNode expectedTo = m.instructions.getLast();

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitStringPrivate {
* private lateinit var member: String
*
* fun get(): String = member
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_5_30_private() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"get", "()Ljava/lang/String;", null, null);
Label l1 = new Label();
Label l2 = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitStringPrivate", "member",
"Ljava/lang/String;");
m.visitVarInsn(Opcodes.ASTORE, 1);
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitJumpInsn(Opcodes.IFNONNULL, l1);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitInsn(Opcodes.ACONST_NULL);
m.visitJumpInsn(Opcodes.GOTO, l2);
m.visitLabel(l1);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitLabel(l2);
m.visitInsn(Opcodes.ARETURN);

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitStringPublic {
* lateinit var member: String
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_5_30_public() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"getMember", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitStringPublic", "member",
"Ljava/lang/String;");
m.visitVarInsn(Opcodes.ASTORE, 1);
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitJumpInsn(Opcodes.IFNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitInsn(Opcodes.ARETURN);
m.visitLabel(label);
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitInsn(Opcodes.ACONST_NULL);
m.visitInsn(Opcodes.ARETURN);
final AbstractInsnNode expectedTo = m.instructions.getLast();

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitGenericPrivate<T : Any> {
* private lateinit var member: T
*
* fun get(): T = member
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_5_30_private_generic() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"get", "()Ljava/lang/String;", null, null);
Label l1 = new Label();
Label l2 = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitGenericPrivate", "member",
"Ljava/lang/Object;");
m.visitVarInsn(Opcodes.ASTORE, 1);
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitJumpInsn(Opcodes.IFNONNULL, l1);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitFieldInsn(Opcodes.GETSTATIC, "kotlin/Unit", "INSTANCE",
"Lkotlin/Unit;");
m.visitJumpInsn(Opcodes.GOTO, l2);
m.visitLabel(l1);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitLabel(l2);
m.visitInsn(Opcodes.ARETURN);

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitGenericPublic<T : Any> {
* lateinit var member: T
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_5_30_public_generic() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"getMember", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitGenericPublic", "member",
"Ljava/lang/Object;");
m.visitVarInsn(Opcodes.ASTORE, 1);
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitJumpInsn(Opcodes.IFNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitVarInsn(Opcodes.ALOAD, 1);
m.visitInsn(Opcodes.ARETURN);
m.visitLabel(label);
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitFieldInsn(Opcodes.GETSTATIC, "kotlin/Unit", "INSTANCE",
"Lkotlin/Unit;");
m.visitInsn(Opcodes.ARETURN);
final AbstractInsnNode expectedTo = m.instructions.getLast();

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitStringPrivate {
* private lateinit var member: String
*
* fun get(): String = member
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_6_private() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"get", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitStringPrivate", "member",
"Ljava/lang/String;");
m.visitInsn(Opcodes.DUP);
m.visitJumpInsn(Opcodes.IFNONNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitInsn(Opcodes.POP);
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitInsn(Opcodes.ACONST_NULL);
m.visitLabel(label);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitInsn(Opcodes.ARETURN);

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitGenericPrivate<T : Any> {
* private lateinit var member: T
*
* fun get(): T = member
* }
* </pre>
*/
@Test
public void should_filter_Kotlin_1_6_private_generic() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"get", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitGenericPrivate", "member",
"Ljava/lang/Object;");
m.visitInsn(Opcodes.DUP);
m.visitJumpInsn(Opcodes.IFNONNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitInsn(Opcodes.POP);
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitFieldInsn(Opcodes.GETSTATIC, "kotlin/Unit", "INSTANCE",
"Lkotlin/Unit;");
m.visitLabel(label);
final AbstractInsnNode expectedTo = m.instructions.getLast();
m.visitInsn(Opcodes.ARETURN);

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}

/**
* <pre>
* class LateinitStringPublic {
* lateinit var member: String
* }
* </pre>
*
* Kotlin 1.7.21 contains an additional frame node before the option pop.
*/
@Test
public void should_filter_Kotlin_1_7_21() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"get", "()Ljava/lang/String;", null, null);
Label label = new Label();
m.visitVarInsn(Opcodes.ALOAD, 0);
m.visitFieldInsn(Opcodes.GETFIELD, "LateinitStringPublic", "member",
"Ljava/lang/String;");
m.visitInsn(Opcodes.DUP);
m.visitJumpInsn(Opcodes.IFNULL, label);
final AbstractInsnNode expectedFrom = m.instructions.getLast();
m.visitInsn(Opcodes.ARETURN);
m.visitLabel(label);
m.visitFrame(Opcodes.F_SAME1, 0, new Object[] {}, 1,
new String[] { "java/lang/String" });
m.visitInsn(Opcodes.POP);
m.visitLdcInsn("member");
m.visitMethodInsn(Opcodes.INVOKESTATIC,
"kotlin/jvm/internal/Intrinsics",
"throwUninitializedPropertyAccessException",
"(Ljava/lang/String;)V", false);
m.visitInsn(Opcodes.ACONST_NULL);
m.visitInsn(Opcodes.ARETURN);
final AbstractInsnNode expectedTo = m.instructions.getLast();

filter.filter(m, context, output);

assertIgnored(new Range(expectedFrom, expectedTo));
}
}
Loading