Giter Site home page Giter Site logo

checker-framework-plus-lombok's Introduction

Checker Framework + Lombok, in perfect (?) harmony

Despite claims to the contrary, the Checker Framework is actually compatible with Lombok. However, a quirk of how Lombok works means that the order of annotation processors matters, and the Checker Framework processors must be listed first. This is confusing because the Checker Framework processors are indended to run last.

This repo demonstrates a functioning project that combines the two.

Install Maven and run mvn verify to compile the project. It should fail (expected!) with

[ERROR] /Users/cloncaric/src/checker-framework-plus-lombok/src/main/java/calvin/example/Basics.java:[15,19] error: [dereference.of.nullable] dereference of possibly-null reference t.getVal()

This error indicates that the Checker Framework is working. It shows that the Checker Framework was able to report an error about a misuse of a Lombok-generated method.

You can also demonstrate this with ./compile-by-hand.sh, which shows a simple invocation of javac without all of Maven's machinery.

Why the Checker Framework must be listed first

Background: annotation processing

Javac runs annotation processors before typechecking. Each processor advertises a set of class-level annotations that it is interested in using the @SupportedAnnotationTypes annotation or by overriding getSupportedAnnotationTypes. Javac will only run a processor on a class if that class has a class-level annotation that the processor is interested in. A processor can advertise interest in all annotations using @SupportedAnnotationTypes("*"), in which case it will run on every class, even if the class has no class-level annotations.

One strange quirk of the annotation processing machinery is that if there are two processors with @SupportedAnnotationTypes("*") and the first of them returns true from its process method, then the second is not guaranteed to run.

Background: how Lombok processes annotations

Lombok's annotation processor adversises interest in all annotations. Furthermore, its process method returns true when all the annotations on the class are Lombok annotations and there is at least one of them.

Background: how the Checker Framework processes annotations

The Checker Framework annotation processors advertise interest in all annotations. Their process methods always return false. However, because javac runs annotation processors before typechecking, their process methods do not actually run the respective checker. Instead, they register a callback to be invoked later, after typechecking has completed.

Summing up

The unfortunate combination of background facts leads to incorrect behavior for classes that have class-level Lombok annotations and no other annotations, e.g.

@lombok.Slf4j
public class Basics {
    ...
}

For such classes, Lombok returns true from its process method, preventing the Checker Framework from running at all. By running the Checker Framework first, it has a chance to register its callback before Lombok ends javac's annotation processing. The callback will then run after typechecking, once Lombok has finished its rewriting work.

A bug in javac revealed by Lombok's ClaimingProcessor

There is a second issue related to a bug in javac (JDK-8312460), although the primary problem is the fact that Lombok's process method returns true in some cases (see above).

Lombok includes a second annotation processor called ClaimingProcessor that (1) advertises interest in only the lombok.* annotations and (2) returns true in its process method (but does nothing else). This annotation processor is an ideal, well-formed processor that does not inherit any of the quirks of @SupportedAnnotationTypes("*") processors.

Due to JDK-8312460, even if the Lombok team patched their process method to always return false, ClaimingProcessor would still prevent the Checker Framework from running. See the JDK-8312460 description linked above for more information.

Unfortunately the ticket was closed as "won't fix", although I suspect that the javac developers are very busy and did not fully understand this entirely-too-subtle issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.