Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin 1.4 uses NullPoinerException instead of TypeCastException, KotlinUnsafeCastOperatorFilter no more filters 'unsafe' branch #1134

Closed
petertrr opened this issue Dec 14, 2020 · 2 comments · Fixed by #1143
Assignees
Labels
Projects
Milestone

Comments

@petertrr
Copy link

Summary

Similarly to #754, sometimes when as is used for casting to nun-nullable type, kotlin adds an additional null check in byte code, which is filtered out by jacoco for kotlin 1.3, but this is no more the case for kotlin 1.4.

Steps to reproduce

With this code snippet:

fun bar(f: () -> Unit) = f()

fun foo(x: Number) {
    bar {
        x as Int
    }
}

kotlin compiler <= 1.3 (or 1.4 with apiLevel=1.3) generates the following bytecode:

L0
    LINENUMBER 8 L0
    ALOAD 0
    GETFIELD FileKt$foo$1.$x : Ljava/lang/Number;
    DUP
    IFNONNULL L1
    NEW kotlin/TypeCastException
    DUP
    LDC "null cannot be cast to non-null type kotlin.Int"
    INVOKESPECIAL kotlin/TypeCastException.<init> (Ljava/lang/String;)V
    ATHROW
   L1
    CHECKCAST java/lang/Integer
    POP
   L2
    LINENUMBER 9 L2
    RETURN
   L3
    LOCALVARIABLE this LFileKt$foo$1; L0 L3 0
    MAXSTACK = 4
    MAXLOCALS = 1

and in kotlin 1.4 it generates the following:

L0
    LINENUMBER 8 L0
    ALOAD 0
    GETFIELD FileKt$foo$1.$x : Ljava/lang/Number;
    DUP
    IFNONNULL L1
    NEW java/lang/NullPointerException
    DUP
    LDC "null cannot be cast to non-null type kotlin.Int"
    INVOKESPECIAL java/lang/NullPointerException.<init> (Ljava/lang/String;)V
    ATHROW
   L1
    CHECKCAST java/lang/Integer
    POP
   L2
    LINENUMBER 9 L2
    RETURN
   L3
    LOCALVARIABLE this LFileKt$foo$1; L0 L3 0
    MAXSTACK = 4
    MAXLOCALS = 1

where TypeCastException is substituted with NullPointerException. I've found an announcement of this change.
Jacoco filters TypeCastException in the first case using KotlinUnsafeCastOperatorFilter, and doesn't filter in the latter case.

  • JaCoCo version: 0.8.6
  • Operating system: Linux and Windows
  • Tool integration: Maven
  • Complete executable reproducer: In this PR setting apiVersion to 1.4 causes dramatic decrease in code coverage.
  • Steps: code coverage reports are generated by jacoco and are sent to codecov. Coverage in pull request (kotlin apiVersion 1.4) is ~2.5% less than in main branch (with kotlin apiVersion 1.3).

Expected behaviour

Same as for kotlin 1.3: branch with null check is filtered out.

Actual behaviour

Code coverage decreases for all similar usages. Kotlin doesn't report such casts as unsafe, and even marks explicit null checks redundant (like adding if (x != null) to the first example).

@petertrr petertrr added the type: bug 🐛 Something isn't working label Dec 14, 2020
@Godin Godin self-assigned this Dec 14, 2020
@Godin Godin added this to To Do in Filtering via automation Dec 16, 2020
@jcenturion18
Copy link

I'm having the same issue with:

"string".toLowerCase()

Locking the code of toLowerCase also has an as

public actual inline fun String.toLowerCase(): String = (this as java.lang.String).toLowerCase()

@jcenturion18
Copy link

I just open a PR based on the solution on the issue #754

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Filtering
  
Done
3 participants