Kotlin / kotlinx-kover

Apache License 2.0
1.28k stars 48 forks source link

Merge nested classes for reports #498

Open shanshin opened 7 months ago

shanshin commented 7 months ago

When generating HTML reports and during verification, any nested classes are analyzed and displayed separately. From the point of view of Kotlin code, this is not entirely correct, because these class-files are features of the JVM compiler implementation and do not reflect the real coverage of the Kotlin class.

It is necessary to merge coverage for the following nested classes:

Example:

class NestedExample {
    companion object {
        // companion
    }

    private fun functionHandler(f: () -> String) {
        println("result ${f()}")
    }

    fun handle() {
        // local class
        class LocalClass { }

        // lambda
        functionHandler {
            "function"
        }

        // anonymous object
        object: Function<String> {
            override fun toString(): String = "Hi"
        }
    }
}

the coverage is evaluated separately for all classes, e.g.:

NestedExample line coverage: ..%
NestedExample$Companion line coverage: ..%
NestedExample$handle$1 line coverage: ..%
NestedExample$handle$2 line coverage: ..%
NestedExample$handle$LocalClass line coverage: ..%

Expected:

NestedExample line coverage: ..%

Important! At the same time, regular nested classes and inner classes should continue to be counted separately:

class Nested2Example {
    class Foo {
    }

    inner class Bar {
    }
}

should give

Nested2Example line coverage: ..%
Nested2Example$Bar line coverage: ..%
Nested2Example$Foo line coverage: ..%
zuevmaxim commented 4 months ago

@shanshin Do you mean only HTML report?

shanshin commented 4 months ago

@zuevmaxim No, HTML and verification.

shanshin commented 2 months ago

I. Lambda

fun a() {
    lambdaCall {
        sout("call")
    }
}
  1. remove lambda class from report
  2. remove separate lambda method from report
  3. move all line and instruction coverage to method a

*don't forget about nested lambdas

fun a() {
    lambdaCall {
        sout("call")
        lambdaCall {
            sout("call2")
        }
    }
}

Lambda always extends kotlin/jvm/internal/Lambda

shanshin commented 2 months ago

II. Companion merge content of companion objects in containing class: companion's methods renamed with companion_ prefix.

Example

class My {
  companion object {
    fun a() {
    }
  }

  fun a() {
  }
}

gives in XML

<class My>
  <method "companion_a">
  <method "a">
</>

It should be disabled by flag