The EISOP Checker Framework can run as an Error Prone plugin (a single Error Prone check
named eisopcf) in addition to its standalone annotation-processor mode.
User documentation — how to enable the plugin, select type systems, pass options,
configure severity, suppress warnings, and use suggested fixes — is in the manual, in the
"Error Prone" section of the "Integration with external tools" chapter
(docs/manual/external-tools.tex). This file collects only the developer-facing details
not covered there. For the design rationale and the decisions behind the implementation,
see cf-errorprone-decisions.md.
framework-errorproneis the only module that depends on Error Prone. It is a JDK-21+-only leaf module (Error Prone requires JDK 21+), gated insettings.gradle, so it is absent from the build on older JDKs and standalone users are unaffected. It contains:EisopCheckerFrameworkPlugin— the@BugPattern("eisopcf")ClassTreeMatcherregistered with Error Prone via a hand-writtenMETA-INF/services/com.google.errorprone.bugpatterns.BugCheckerresource.EisopContextAdapter— obtains the javacProcessingEnvironmentfrom Error Prone'sVisitorState.context(withContext.get, so that a context without one is diagnosed rather than silently given a fresh, unrelated environment), and reports which dataflow copy is loaded, so that a test can check that the Checker Framework's own (un-relocated) dataflow classes are used rather than Error Prone's shaded copy.CheckerFrameworkDriver— instantiates the selectedSourceCheckers by reflection and drives them per class through the externally-driven lifecycle. Contains no Error Prone types.
- The Checker Framework core modules (
checker-qual,javacutil,dataflow,framework,checker) contain no Error Prone dependency. The plugin consumes a publishederror_prone_check_api, so there is no dependency cycle with thedataflow-errorproneartifact that Error Prone itself consumes.
Fixes flow from a checker to Error Prone through a framework-agnostic channel, so the core
never references Error Prone. A checker attaches fixes to a finding by reporting a
DiagMessage that carries them:
checker.report(tree, DiagMessage.error("nullness.on.primitive").withFixes(fixes));Each fix is a SuggestedFixData, built from source positions with JDK types only (e.g.
SuggestedFixData.deleteTree(sourcePositions, root, annotationTree)); the plugin
translates it into an Error Prone SuggestedFix. See NullnessNoInitVisitor for a worked
example (removing a nullness annotation from a primitive type), and the decision log
(ADR-0007, ADR-0011) for the design.
The plugin's tests live in framework-errorprone/src/test and use Error Prone's
CompilationTestHelper / BugCheckerRefactoringTestHelper. They run automatically as part
of ./gradlew test whenever the build JDK is 21 or newer (the module is absent on older
JDKs), so no separate CI job is required.
The module is also dog-fooded: ./gradlew :framework-errorprone:checkNullness runs the
Nullness Checker over its entire source set (it is annotated with @Nullable where
applicable). Because the module is not framework or checker, the shared checkNullness
task checks all of it, without a per-file @AnnotatedFor("nullness") opt-in.
docs/examples/eisop-errorprone/ is a self-contained Gradle project that runs the Nullness
Checker as the eisopcf plugin, in two modes selected by the cfVersion property (like the
sibling examples):
cd docs/examples/eisop-errorprone
make all # -PcfVersion=local: the current checkout's jars
../../../gradlew build # default: the published io.github.eisop artifactsmake all runs gradlew -PcfVersion=local build, so the example exercises the current
development Checker Framework. The jars it consumes are built by the :checker:exampleTests
task (which depends on :framework-errorprone:jar and :checker:shadowJar), so running the
example under that task needs no separate build step. make all then checks that the expected
[eisopcf] [dereference.of.nullable] diagnostic is produced (JDK 21+; a no-op otherwise).
The default (non-local) mode consumes the published io.github.eisop artifacts, including
io.github.eisop:framework-errorprone; it fails until the first release that publishes that
module. Its build.gradle doubles as a template for a real, release-based build.