This plugin configures JavaCompile
tasks to use the Checker Framework for pluggable type-checking.
Add the following to your build.gradle
file:
plugins {
// Checker Framework pluggable type-checking
id 'org.checkerframework' version '0.3.25'
}
apply plugin: 'org.checkerframework'
The checkerFramework.checkers
property lists which checkers will be run.
For example:
checkerFramework {
checkers = [
'org.checkerframework.checker.nullness.NullnessChecker',
'org.checkerframework.checker.units.UnitsChecker'
]
}
For a list of checkers, see the Checker Framework Manual.
You can set the checkerFramework.extraJavacArgs
property in order to pass additional options to the compiler when running
a typechecker.
For example, to use a stub file:
checkerFramework {
extraJavacArgs = [
'-Werror',
'-Astubs=/path/to/my/stub/file.astub'
]
}
To use a third-party typechecker (i.e. one that is not distributed with the Checker Framework),
add a dependency to the checkerFramework
dependency configuration.
For example, to use the Glacier immutability checker:
dependencies {
...
checkerFramework 'edu.cmu.cs.glacier:glacier:0.1'
}
This plugin uses Checker Framework version 2.10.0 by default. Anytime you upgrade to a newer version of this plugin, it might use a different version of the Checker Framework.
If you wish to use a specific Checker Framework
version,
add text like the following to build.gradle
, after apply plugin: 'org.checkerframework'
:
dependencies {
compileOnly 'org.checkerframework:checker-qual:2.8.0'
testCompileOnly 'org.checkerframework:checker-qual:2.8.0'
checkerFramework 'org.checkerframework:checker:2.8.0'
checkerFrameworkAnnotatedJDK 'org.checkerframework:jdk8:2.8.0'
}
You can also use a locally-built version of the Checker Framework:
// To use a locally-built Checker Framework, run gradle with "-PcfLocal".
if (project.hasProperty("cfLocal")) {
def cfHome = String.valueOf(System.getenv("CHECKERFRAMEWORK"))
dependencies {
compileOnly files(cfHome + "/checker/dist/checker-qual.jar")
testCompileOnly files(cfHome + "/checker/dist/checker-qual.jar")
checkerFramework files(cfHome + "/checker/dist/checker.jar")
checkerFrameworkAnnotatedJDK files(cfHome + "/checker/dist/jdk8.jar")
}
}
-
By default, the plugin applies the selected checkers to all
JavaCompile
targets.Here is how to prevent checkers from being applied to test targets:
checkerFramework { excludeTests = true }
The check for test targets is entirely syntactic: this option will not apply the checkers to any task whose name includes "test", ignoring case.
-
If you encounter errors of the form
zip file name too long
when configuring your Gradle project, you can use the following code to skip this plugin's version check, which reads the manifest file of the version of the Checker Framework you are actually using:checkerFramework { skipVersionCheck = true }
By default, checkers are run on all subprojects of the project to which the plugin is applied.
In most projects with subprojects, the top-level project is not a Java
project. You should not configure such a non-Java project. Instead, move
all Checker Framework configuration (the checkerFramework
block and any
dependencies
) into a subprojects
block. For example:
subprojects { subproject ->
checkerFramework {
checkers = ['org.checkerframework.checker.index.IndexChecker']
}
dependencies {
checkerFramework 'org.checkerframework:checker:2.10.0'
implementation 'org.checkerframework:checker-qual:2.10.0'
}
}
To not apply the plugin to all subprojects, set the applyToSubprojects
flag to false
:
checkerFramework {
applyToSubprojects = false
}
Then, apply the plugin to the build.gradle
in each subproject where you
do want to run the checker.
Error Prone uses the Checker Framework's dataflow analysis library. Unfortunately, Error Prone uses an old version of the library, so you cannot use both Error Prone and the current Checker Framework (because each one depends on a different version of the library).
You can resolve this via a switch that causes your build to use either Error Prone or the Checker Framework, but not both. Here is how do change the above instructions:
plugins {
id "net.ltgt.errorprone-base" version "0.0.16" apply false
// To do Checker Framework pluggable type-checking (and disable Error Prone), run:
// ./gradlew compileJava -PuseCheckerFramework=true
id 'org.checkerframework' version '0.3.25' apply false
}
if (!project.hasProperty("useCheckerFramework")) {
ext.useCheckerFramework = "false"
}
if ("true".equals(project.ext.useCheckerFramework)) {
apply plugin: 'org.checkerframework'
} else {
apply plugin: 'net.ltgt.errorprone-base'
}
def checkerFrameworkVersion = "2.10.0"
dependencies {
if ("true".equals(project.ext.useCheckerFramework)) {
checkerFramework 'org.checkerframework:checker:' + checkerFrameworkVersion
checkerFramework 'org.checkerframework:jdk8:' + checkerFrameworkVersion
checkerFramework 'org.checkerframework:checker-qual:' + checkerFrameworkVersion
} else {
errorprone group: 'com.google.errorprone', name: 'error_prone_core', version: '2.3.3'
}
}
if ("true".equals(project.ext.useCheckerFramework)) {
checkerFramework {
checkers = [
'org.checkerframework.checker.interning.InterningChecker',
'org.checkerframework.checker.signature.SignatureChecker'
]
}
} else {
// Configuration for the Error Prone linter.
tasks.withType(JavaCompile).each { t ->
if (!t.name.equals("compileTestInputJava") && !t.name.startsWith("checkTypes")) {
t.toolChain ErrorProneToolChain.create(project)
t.options.compilerArgs += [
'-Xep:StringSplitter:OFF',
'-Xep:ReferenceEquality:OFF' // use Interning Checker instead
]
}
}
}
When using a Checker Framework version above 3.0.0 that is compatible with Java 9 and executing on a Java 8 JVM, this plugin will automatically substitute a Checker Framework-compatible Error Prone Java compiler version (from com.google.errorprone:javac). This is necessary because Checker Framework versions starting at 3.0.0 build on the Java 9 compiler.
When using a Checker Framework version above 3.0.0 and executing on a Java 9+ JVM, the host Java compiler is used.
This plugin automatically interacts with the Lombok Gradle Plugin to delombok your source code before it is passed to the Checker Framework for typechecking. This plugin does not support any other use of Lombok.
You can build the plugin locally rather than downloading it from Maven Central.
To build the plugin from source, run ./gradlew build
.
If you want to use a locally-built version of the plugin, you can publish the plugin to your
local Maven repository by running ./gradlew publish
. In the build.gradle
file for each
project for which you want to use the locally-built plugin, make sure that mavenLocal()
is the first entry in the repositories
block within the buildscript
block. A full example
will look like this:
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'gradle.plugin.org.checkerframework:checkerframework-gradle-plugin:0.3.25-SNAPSHOT'
}
}
apply plugin: 'org.checkerframework'
This project started as a fork of a plugin built by jaredsburrows.
Copyright (C) 2017 Jared Burrows, 2019 Martin Kellogg
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.