Skip to content

Kotlin SMAPs in synthetic classes should be processed#1985

Merged
Godin merged 9 commits into
jacoco:masterfrom
Godin:kotlin_inline_reference
Mar 6, 2026
Merged

Kotlin SMAPs in synthetic classes should be processed#1985
Godin merged 9 commits into
jacoco:masterfrom
Godin:kotlin_inline_reference

Conversation

@Godin

@Godin Godin commented Oct 28, 2025

Copy link
Copy Markdown
Member

No description provided.

@Godin Godin self-assigned this Oct 28, 2025
@Godin Godin added this to Filtering Oct 28, 2025
@Godin Godin added component: core.filters language: Kotlin Tickets about Kotlin language support labels Oct 28, 2025
@github-project-automation github-project-automation Bot moved this to Awaiting triage in Filtering Oct 28, 2025
@Godin Godin moved this from Awaiting triage to To Do in Filtering Oct 28, 2025
@Godin Godin moved this from To Do to In Progress in Filtering Oct 29, 2025
@Godin Godin added this to the 0.8.15 milestone Oct 29, 2025
@Godin Godin marked this pull request as ready for review November 15, 2025 00:29
@Godin Godin enabled auto-merge (squash) November 15, 2025 00:30
@Godin Godin changed the title SMAPs in synthetic classes should be processed Kotlin SMAPs in synthetic classes should be processed Nov 15, 2025
@Godin Godin requested review from marchof and removed request for marchof November 15, 2025 00:30
@marchof

marchof commented Nov 17, 2025

Copy link
Copy Markdown
Member

Hi @Godin I wonder whether this change has side effects: So far we did not process synthetic classes at all and did not report them. Now we process them and report them to ICoverageVisitor.visitCoverage(). I wonder whether synthetic classes will now show up as empty classes in our reports?

@Godin

Godin commented Jan 29, 2026

Copy link
Copy Markdown
Member Author

@marchof see #817 - since quite some time "empty" classes do not increase counters and we deliberately preserve them in our XML reports, while do not show in HTML and CSV reports.

So new behavior in respect to synthetic classes is IMO not quite new in respect to empty classes. And more consistent - for example for the following Example.java as well as for other cases of synthetic and empty classes

enum Example {
  E;
  static void example(Example e) {
    switch (e) {
    }
  }
  public static void main(String[] args) {
    example(E);
  }
}
interface I {
}

execution of

javac Example.java -d classes && ls -1 classes

shows 3 produced class files

I.class
Example$1.class
Example.class

and execution of

java -javaagent:jacoco-0.8.14/lib/jacocoagent.jar -cp classes Example
java -jar jacoco-0.8.14/lib/jacococli.jar execinfo jacoco.exec

clearly shows

[INFO] Loading exec file jacoco.exec.
CLASS ID         HITS/PROBES   CLASS NAME
Session "MAC9003-da920919": Wed Jan 28 15:49:06 CET 2026 - Wed Jan 28 15:49:06 CET 2026
c966c402206c6798    1 of   1   Example$1
c3e55ed53a7558c1    7 of   8   Example

that execution data contains Example$1 even without this change, however execution of

java -jar jacoco-0.8.14/lib/jacococli.jar classinfo classes

without this change does not show this class while shows empty class of interface

  INST   BRAN   LINE   METH   CXTY   ELEMENT
     0      0      0      0      0   class 0x7b2d6d0c22f5309f I
    18      0      6      3      3   class 0xe6c876fba2f4b842 Example

and after this change will show

  INST   BRAN   LINE   METH   CXTY   ELEMENT
     0      0      0      0      0   class 0x7b2d6d0c22f5309f I
    18      0      6      3      3   class 0xe6c876fba2f4b842 Example
     0      0      0      0      0   class 0xc966c402206c6798 Example$1

Note that as far as I know Java compiler generates synthetic classes only in two cases:

Also after this change will be unambiguously clear that classes not presented in XML report are the ones that user explicitly excluded or not included from/into analysis.

Of course this PR can be changed to read SMAPs from synthetic classes while not passing them to ICoverageVisitor.visitCoverage, however then for

(in both Kotlin compiler generates synthetic classes whose content should appear in coverage reports)

one will need new internal filtering API to be able to exclude class from visitCoverage rather than simply (re)using existing code and of this PR, which given all the above IMO unnecessary increase of complexity.

We also briefly discussed such change some time ago, but at that time it was postponed - see #668 (comment) Seems that time to reconsider has come 😉

@Godin Godin requested review from marchof and removed request for marchof January 29, 2026 09:58
@Godin Godin disabled auto-merge January 29, 2026 10:02
@marchof

marchof commented Jan 31, 2026

Copy link
Copy Markdown
Member

Many thanks for the detailed explanation!

@Godin Godin marked this pull request as draft February 2, 2026 15:54
@Godin

Godin commented Feb 3, 2026

Copy link
Copy Markdown
Member Author

@marchof actually I forgot one more case of synthetic class in Java - package-info 😞

if users in case of split packages perform analysis without proper split on bundles and for the same package there are two package-info.class with different classId, ie in case of

src1/org/example/A.java

class A {
}

src1/org/example/package-info.java

package org.example;

src2/org/example/B.java

package org.example;
class B {
}

src2/org/example/package-info.java

@Deprecated
package org.example;

execution of

javac \
  src1/org/example/package-info.java \
  src1/org/example/A.java \
  -d classes1

javac \
  src2/org/example/package-info.java \
  src2/org/example/B.java \
  -d classes1

java -jar jacococli.jar \
  report \
  --classfiles classes1 \
  --classfiles classes2 \
  --html report

after this change will lead to

java.lang.IllegalStateException: Can't add different class with same name: org/example/package-info

Unfortunately to get aggregated reports users have (or at least had in past) tendency to mix multiple modules without proper split on bundles - see #858 which was about module-info.class, and while probability to get such exception in case of package-info.class might be lower, it is not zero unfortunately.

As is one will need to explicitly exclude **/package-info.class from analysis, which might be not a big deal for the ones who have exclusions for split packages with already conflicting other classes.

Or we can restore exclusion of synthetic classes in Analyzer, but only for package-info, or exclude it prior to duplicate check in CoverageBuilder, or some other option.

WDYT?

@Godin Godin requested a review from marchof February 3, 2026 21:33
@marchof

marchof commented Feb 6, 2026

Copy link
Copy Markdown
Member

@Godin I don't see a use case of package-info.class files in our reports, especially as they never contain code. I would therefore hard-code the filtering of module-info and package-info in the analyzer.

@Godin Godin marked this pull request as ready for review February 6, 2026 23:29
@Godin Godin merged commit 3376300 into jacoco:master Mar 6, 2026
55 checks passed
@Godin Godin deleted the kotlin_inline_reference branch March 6, 2026 22:33
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Filtering Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: core.filters language: Kotlin Tickets about Kotlin language support

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants