If you wish to use the Checker Framework, see its user manual (HTML, PDF).
This document contains information for Checker Framework developers, including people who wish to edit its source code or make pull requests.
Contents:
The checker-framework repository contains several related projects:
framework
checker
javacutil
dataflow
The repository also contains the following directories:
docs
The checker-framework
project
depends on
the typetools/jdk
project,
the annotation-tools
project,
and the stubparser
project.
When making changes to one of these projects, you may also need to make changes to one or more of the others.
If you make related changes in the checker-framework
and jdk
repositories, use the same
branch name for each. The continuous integration framework will find
and use that branch when running tests.
For example, when continuous integration runs for branch B of fork F of checker-framework
, it will use branch B of fork F of the other repositories (if they exist).
The same is true for the other projects.
If a change spans multiple projects, make pull requests for all of them. Each pull request description's should link to all the others.
Furthermore, whenever you make a pull request from
a checker-framework
branch A into branch B, if B has a
corresponding jdk
branch, then A also needs one (even if identical to B's version).
Full instructions for building the Checker Framework from sources appear in the Checker Framework manual. This section describes the build system (the Gradle build tasks).
Don't run the gradle
command, which would use whatever version
of Gradle is installed on your computer. Instead, use
the gradlew
script in the checker-framework
directory, also known as
the Gradle
wrapper.
Frequently-used tasks:
assemble
: builds all jars.
build
: assemble
, plus runs all JUnit tests.
allTests
: runs all tests.
reformat
: reformats Java files.
NameOfJUnitTest
: runs the JUnit test with that name; for example, NullnessTest
.
task
: lists tasks; use --all
to see all tasks.
If you run a task from the main directory, then it will run that task in all
subprojects with a task by that name. So, if you run ./gradlew
allTests
that runs all tests everywhere. But (cd
framework && ../gradlew allTests)
only runs tests in
the framework
project.
Alternatively, running :framework:allTests
from the
main directory or any subproject runs the allTests
task only in the framework
project.
For writing new test cases, see file checker/tests/README
.
To test an optimization that should speed up type-checking, see
the test-daikon.sh
stage of the daikon_jdk8
job
of the Azure Pipelines CI job. Compare the run time of this stage (or of
the entire daikon_jdk8
job) between the master branch and a
branch with your improvements.
You can also compare run times of the Checker Framework test suite.
Code in this project follows the Google Java Style Guide (except 4 spaces are used for indentation), Michael Ernst's coding style guidelines, and Oracle's Java code conventions.
From the command line, you can format your code by running ./gradlew reformat
.
You
can configure
your IDE (Eclipse or IntelliJ) to use the formatting (don't forget the
non-standard -a
flag).
We don't use @author
Javadoc tags in code files.
Doing so clutters the code, and is misleading once that individual
is no longer maintaining the code.
Authorship (and who has made changes recently) can be obtained from the
version control system, such as by running git annotate filename
.
Every class, method, and field (even private ones) must have a descriptive Javadoc comment.
First clone and build all projects from their sources, from the command line, using the instructions at https://checkerframework.org/manual/#build-source. After that succeeds, import the projects into your IDE as Gradle projects.
If your IDE cannot find com.sun.source.*
packages, try changing the project JDK to JDK 11.
Each pull request should address a single concern, rather than (say) addressing multiple concerns such as fixing a bug, adding a feature, and changing formatting. Focusing each pull request on a single concern makes the commit easier to understand and review. It also makes the commit history (after the pull request is merged) easier to understand and (if necessary) revert.
The pull request title should clearly explain the change. It will be used as the commit message for your change. If the pull request fixes an issue in the issue tracker, its title should end with "; fixes #NNN" where NNN is the fixed issue.
Your pull request (whether it is a bug fix or a new feature) should include tests that fail before your change and pass afterward.
If you make a user-visible change, update the manual (or add a new section)
and add a brief description at the top of the changelog
(file docs/CHANGELOG.md
).
To reduce iterations of code review, please follow the coding conventions. Also enable continuous integration on your fork of the Checker Framework and ensure that it passes before you open a pull request.
A pull request marked as "draft" means it should not be reviewed. To use a
"draft" pull request for discussions, make it in a fork. If it were in
the typetools
GitHub organization, it would use CI resources
and thus slow down CI feedback for other pull requests.
Also see Michael Ernst's advice about creating GitHub pull requests.
It is good style to create a branch (in your fork of the Checker
Framework GitHub repository) for each independent change.
Do not make changes to your master
branch.
If you have write access to the typetools
repository, don't
work in a branch of it, because such a branch competes for CI resources
with all pull requests.
Azure Pipelines has a bug: whenever two CI jobs would run code with the same
commit hash, it re-uses a previous execution result. This is a bug because the
CI job's behavior may depend on the branch name and other factors that are
independent of the commit hash. This means that you may see spurious successes
or failures when your branch of (say) the jdk
repository has the
identical commit hash to some other branch that Azure Pipelines previous ran a
job for.
It is acceptable to commit small, noncontroversial changes directly to master. (This policy differs from some projects, which require an issue tracker issue and a pull request for every change, however minor.) As with pull requests, each commit should address a single concern. For any change where you want feedback, or where others might have useful comments or might disagree, please submit a pull request. Be conservative in your judgment; others might consider something controversial that you do not.
Try to review pull requests promptly, to avoid stalling others while waiting for your feedback. If you have been waiting for more than a week after the pull request was assigned with no feedback, then ping the assignee, wait at least another business day, and then go ahead and push your changes. It's great if reviewers can give feedback, but if they are too busy to do so, you should recognize that and move on.
When you installed Git, you should have set your name and email address. If you have not yet done so, do it now:
git config --global user.name "FIRST_NAME LAST_NAME" git config --global user.email "USERNAME@SOMEDOMAIN.COM"
Before you make any commits (even to your own fork), update your GitHub account profile so it contains your complete name. This is necessary to include you in the list of contributors.
You will want your own GitHub fork of any project you plan to modify. We recommend that, for each fork, you configure GitHub to delete branches after they are merged.
The Checker Framework has continuous integration jobs that run in Azure Pipelines, CircleCI, and/or Travis CI on each push to GitHub. We recommend Azure Pipelines.
To enable Azure Pipelines continuous integration for your fork: (This is a summary of the Azure Pipelines getting started directions.)
To enable Travis CI continuous integration for your fork:
Sometimes, CI tests for your pull request may fail even though your local build passed. This is usually because the CI service performed more tests than you ran locally.
First, examine the CI service's logs, which contain diagnostic output from the
failing command. You can determine which command was run from the logs, or
from the CI configuration file (such as azure-pipelines.yml
).
Don't open issues for code improvement ideas (such as potential refactorings). If it can be described concisely and is unlikely to be rediscovered by other people, write a TODO comment in the code. The code comment is more likely to be noticed by someone working with the code, and it is equally easy to search for. Furthermore, it doesn't clutter the issue tracker. Clutter in the issue tracker reduces morale, makes it harder to search, and makes the project appear lower-quality than it actually is.
We maintain annotated versions of some third-party libraries. The source
code appears in a fork in
the GitHub typetools
organization. Binaries are hosted
at Maven Central
in the org.checkerframework.annotatedlib
group.
Annotated libraries should be based on a released version of the upstream library, not an arbitrary commit in the upstream library's version control system. The library's version number is the same as the upstream version number.
When making a new version of an annotated library, between upstream releases, add ".0.1" to the end of the version number. For example, if we already uploaded version 6.2 to Maven Central, the next version we upload would be 6.2.0.1. This accommodates the possibility that the upstream maintainers release 6.2.1. Our further releases increment the last number, for example to 6.2.0.2.
See a separate document about the Checker Framework release process.