kotlinx-kover icon indicating copy to clipboard operation
kotlinx-kover copied to clipboard

Difficulty excluding some generated code

Open ansman opened this issue 1 year ago • 7 comments

Describe the bug Dagger generates code that looks like this:

@ScopeMetadata
@QualifierMetadata
@DaggerGenerated
@Generated(
    value = "dagger.internal.codegen.ComponentProcessor",
    comments = "https://dagger.dev"
)
@SuppressWarnings({
    "unchecked",
    "rawtypes",
    "KotlinInternal",
    "KotlinInternalInJava",
    "cast",
    "deprecation"
})
public final class ElapsedRealTimeClockImpl_Factory implements Factory<ElapsedRealTimeClockImpl> {
  @Override
  public ElapsedRealTimeClockImpl get() {
    return newInstance();
  }

  public static ElapsedRealTimeClockImpl_Factory create() {
    return InstanceHolder.INSTANCE;
  }

  public static ElapsedRealTimeClockImpl newInstance() {
    return new ElapsedRealTimeClockImpl();
  }

  private static final class InstanceHolder {
    private static final ElapsedRealTimeClockImpl_Factory INSTANCE = new ElapsedRealTimeClockImpl_Factory();
  }
}

We exclude this by excluding classes annotated by @Generated and @DaggerGenerated. The issue is the inner InstanceHolder class which isn't annotated.

Expected behavior I'm not sure I'd honestly expect it to exclude this class since it's not annotated, but most code generation frameworks will only annotate the top class and most people will want to exclude the inner class too so there should be some mechanism for excluding these.

Reports image

Environment

  • Kover Gradle Plugin version: 0.9.0-RC
  • Gradle version: 8.10.2
  • Kotlin project type: Android
  • Coverage Toolset: Kover
  • Other context important for this bug: macOS 14.7

ansman avatar Oct 03 '24 14:10 ansman

Unfortunately they don't want to spread the exclusion of annotated classes to their inner classes.

https://github.com/Kotlin/kotlinx-kover/issues/331

That being said, I have exactly the same issue, and even more "conventional" way of excluding this nasty inner class InstanceHolder won't work. I tried everything I could think of, this ain't moving from the report.

kover {
    reports {
        filters {
            excludes {
                ...
                packages(
                    "InstanceHolder",
                    "*InstanceHolder",
                    "\$*InstanceHolder",
                    "*\$*InstanceHolder",
                    "*\$InstanceHolder",
                    "*ProvideFactory\$InstanceHolder",
                )
                ...
            }
        }
    }
}

Coverage:
image

JADX bytecode inspection: image

NinoDLC avatar Oct 10 '24 20:10 NinoDLC

You can exclude them by name:

excludedClasses.addAll(
    "*\$InstanceHolder",
    "ComposableSingletons*",
    "Hilt_*",
    "*\$DefaultImpls"
)

ansman avatar Oct 10 '24 20:10 ansman

Also, like I mentioned in my description I agree that excluding annotated classes probably shouldn't exclude inner classes if they're not annotated but I do think kover need to add a mechanism for excluding based on parent annotation to allow excluding these types of files

ansman avatar Oct 10 '24 20:10 ansman

Oh yes I was confused between classes and packages 🙈

NinoDLC avatar Oct 10 '24 20:10 NinoDLC

Hi, the problem with the additional filter will be that it is needed in very rare cases, it will confuse users who do not need it, and when you add it, report generation will slow down significantly - because it will be necessary for any class to scan its containing class for annotations.

Could you give an example of nested classes other than InstanceHolder that are not solved by specifying the excludes.classes("*\$NestedName") filter?

shanshin avatar Oct 14 '24 12:10 shanshin

I ignored all hilt classes by these lines (until better solution):

packages(
    "dagger.hilt.internal.aggregatedroot.codegen",
    "hilt_aggregated_deps",
)
annotatedBy(
    "javax.annotation.processing.Generated",
    "dagger.internal.DaggerGenerated",
    "dagger.hilt.android.internal.lifecycle.HiltViewModelMap\$KeySet",
)
classes(
    "*\$InstanceHolder",
    "*Hilt_*",
    "*BindsModule*",
    "*\$DefaultImpls"
)

beigirad avatar Oct 29 '24 11:10 beigirad

This task will be taken into account when migrating to Kotlin Gradle Plugin.

In the future, it will be moved to the Kotlin task tracker, or closed if it loses relevance.

shanshin avatar Jan 03 '25 20:01 shanshin

as mentioned in https://github.com/Kotlin/kotlinx-kover/issues/370#issuecomment-1557314746, the above configured javax.annotation.processing.Generated is ignored by kover because the annotation retention is SOURCE, so adding this to the config is useless.

However, I'd like to assume that the implementation in Kotlin Gradle Plugin will take SOURCE annotations into account, can you confirm @shanshin?

jogerj avatar Aug 29 '25 10:08 jogerj

However, I'd like to assume that the implementation in Kotlin Gradle Plugin will take SOURCE annotations into account, can you confirm @shanshin?

@jogerj, Unfortunately, no.

In this case, the problem is not in the Gradle plugin, but much deeper. The annotation with SOURCE exists only before the compiler is started. Report generation (and as a result, filtering), in turn, works on already compiled class-files.

To filter by SOURCE annotations, it is necessary either for the report generator to contain the actual part of the compiler responsible for building the AST and be able to work with it correctly, or for instrumentation to occur during compilation.

However, neither one nor the other is included in the mid-term plans.

shanshin avatar Sep 01 '25 12:09 shanshin