Skip to content

Check that the annotated JDK's binary stub file agrees with its sources#55

Open
wmdietl wants to merge 2 commits into
main-eisopfrom
binary-stub-diff-test
Open

Check that the annotated JDK's binary stub file agrees with its sources#55
wmdietl wants to merge 2 commits into
main-eisopfrom
binary-stub-diff-test

Conversation

@wmdietl

@wmdietl wmdietl commented Jul 13, 2026

Copy link
Copy Markdown
Member

Follow-up to eisop/checker-framework#1853 , but needs to wait until there has been an EISOP CF release.

The EISOP Checker Framework generates a binary stub file for this project's annotated JDK at build time (see includeJSpecifyJDK) and reads it in preference to the JDK sources. Nothing checked that the two agree, and they did not: the differential check reported five records that the binary had and the text parse did not, a EISOP Checker Framework bug in parsing a record nested in another type, which its own annotated JDK does not contain and so had never exposed.

Add a binaryStubDiffTest task that runs the check. It compiles one throwaway file with the checker and -AbinaryStubDiffCheck: the check runs while the checker initializes, over every class in the binary stub file, so what is compiled does not matter. BinaryStubDiffChecker implements the check and ships in the EISOP Checker Framework's framework-test artifact.

Three things the task needs, none of them obvious:

  • Error Prone is disabled for it. The plugin decorates every JavaCompile task, and this one runs only the checker.
  • The checker's own qualifiers must be on the compilation classpath, not just the annotation-processor path: AnnotationBuilder resolves them through Elements.getTypeElement, which reads the compilation classpath.
  • It compiles against the running JDK, not this project's sourceCompatibility. The text parser resolves JDK elements against the compilation's JDK, so under an older --release an element that JDK lacks resolves to nothing and its annotations look like they are "only in binary" -- 116 phantom mismatches, all of them an artifact of the release level.

The Checker Framework generates a binary stub file for this project's annotated
JDK at build time (see includeJSpecifyJDK) and reads it in preference to the JDK
sources.  Nothing checked that the two agree, and they did not: the differential
check reported five records that the binary had and the text parse did not, a
Checker Framework bug in parsing a record nested in another type, which its own
annotated JDK does not contain and so had never exposed.

Add a binaryStubDiffTest task that runs the check.  It compiles one throwaway
file with the checker and -AbinaryStubDiffCheck: the check runs while the checker
initializes, over every class in the binary stub file, so what is compiled does
not matter.  BinaryStubDiffChecker implements the check and ships in the Checker
Framework's framework-test artifact.

Three things the task needs, none of them obvious:

- Error Prone is disabled for it.  The plugin decorates every JavaCompile task,
  and this one runs only the checker.
- The checker's own qualifiers must be on the compilation classpath, not just the
  annotation-processor path: AnnotationBuilder resolves them through
  Elements.getTypeElement, which reads the compilation classpath.
- It compiles against the running JDK, not this project's sourceCompatibility.
  The text parser resolves JDK elements against the compilation's JDK, so under an
  older --release an element that JDK lacks resolves to nothing and its
  annotations look like they are "only in binary" -- 116 phantom mismatches, all
  of them an artifact of the release level.
Copilot AI review requested due to automatic review settings July 13, 2026 16:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Gradle verification task to ensure the annotated JDK’s generated binary stub file matches the annotations that would be obtained by parsing the adjacent JDK sources, and wires that check into CI.

Changes:

  • Introduces a binaryStubDiffTest JavaCompile task that runs NullSpecChecker with -AbinaryStubDiffCheck and the required classpath/exports setup.
  • Adds a dedicated Gradle configuration/dependency to supply BinaryStubDiffChecker from the Checker Framework framework-test artifact.
  • Adds a tiny “trigger” Java source file and updates GitHub Actions to run the new task.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
tests/binary-stub-diff/TriggerBinaryStubDiff.java Adds a throwaway compilation unit to trigger the diff check during checker initialization.
build.gradle Defines the binaryStubDiffChecker configuration and the binaryStubDiffTest task wiring/flags.
.github/workflows/build.yml Runs binaryStubDiffTest in CI alongside existing build/test tasks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +6
// The binary-stub differential check runs once, while the checker initializes: for every class in
// the annotated JDK's binary stub file, it compares the annotations the binary produces against the
// ones the text parser produces from the JDK sources beside it, and reports any disagreement as an
// error. What is compiled here is therefore irrelevant -- this file exists only to make the checker
// run. See the binaryStubDiffTest task in build.gradle.
class TriggerBinaryStubDiff {}
Comment on lines 56 to 60
- name: Build and Test (EISOP release)
if: ${{ env.EISOP_RELEASE == 'true' }}
# If a released CF is needed, use the following:
run: ./gradlew build conformanceTests demoTest --include-build ../jspecify --warning-mode all
run: ./gradlew build conformanceTests demoTest binaryStubDiffTest --include-build ../jspecify --warning-mode all
env:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants