blob: 33ae0537b430839a031cf13ad8a42a0636ebcd37 [file] [log] [blame]
plugins {
id 'java-library'
}
ext {
annotatedJdkHome = '../../jdk'
}
sourceSets {
main {
resources {
// Stub files, message.properties, etc.
srcDirs += ['src/main/java', "${buildDir}/generated/resources"]
}
}
testannotations
}
sourcesJar {
// The resources duplicate content from the src directory.
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
def versions = [
autoValue : "1.7.4",
lombok : "1.18.20",
]
dependencies {
api project(':javacutil')
api project(':dataflow')
api files("${stubparserJar}")
// AFU is an "includedBuild" imported in checker-framework/settings.gradle, so the version number doesn't matter.
// https://docs.gradle.org/current/userguide/composite_builds.html#settings_defined_composite
api('org.checkerframework:annotation-file-utilities:*') {
exclude group: 'com.google.errorprone', module: 'javac'
}
api project(':checker-qual')
// External dependencies:
// If you add an external dependency, you must shadow its packages.
// See the comment in ../build.gradle in the shadowJar block.
implementation 'org.plumelib:plume-util:1.5.3'
implementation 'org.plumelib:reflection-util:1.0.3'
implementation 'io.github.classgraph:classgraph:4.8.105'
// TODO: it's a bug that annotatedlib:guava requires the error_prone_annotations dependency.
// Update the next two version numbers in tandem. Get the Error Prone version from the "compile
// dependencies" section of https://mvnrepository.com/artifact/com.google.guava/guava/28.2-jre .
// (It isn't at https://mvnrepository.com/artifact/org.checkerframework.annotatedlib/guava/28.2-jre, which is the bug.)
implementation 'com.google.errorprone:error_prone_annotations:2.7.1'
implementation ('org.checkerframework.annotatedlib:guava:30.1.1-jre') {
// So long as Guava only uses annotations from checker-qual, excluding it should not cause problems.
exclude group: 'org.checkerframework'
}
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
testImplementation project(':framework-test')
testImplementation sourceSets.testannotations.output
// AutoValue support in Returns Receiver Checker
testImplementation "com.google.auto.value:auto-value-annotations:${versions.autoValue}"
testImplementation "com.google.auto.value:auto-value:${versions.autoValue}"
// Lombok support in Returns Receiver Checker
testImplementation "org.projectlombok:lombok:${versions.lombok}"
}
task cloneTypetoolsJdk() {
description 'Obtain or update the annotated JDK.'
doLast {
if (file(annotatedJdkHome).exists()) {
exec {
workingDir annotatedJdkHome
executable 'git'
args = ['pull', '-q']
ignoreExitValue = true
}
} else {
println 'Cloning annotated JDK repository.'
exec {
workingDir "${annotatedJdkHome}/../"
executable 'git'
args = ['clone', '-q', '--depth', '1', 'https://github.com/typetools/jdk.git', 'jdk']
}
}
}
}
task copyAndMinimizeAnnotatedJdkFiles(dependsOn: cloneTypetoolsJdk, group: 'Build') {
dependsOn ':framework:compileJava'
def inputDir = "${annotatedJdkHome}/src"
def outputDir = "${buildDir}/generated/resources/annotated-jdk/"
description "Copy annotated JDK files to ${outputDir}. Removes private and package-private methods, method bodies, comments, etc. from the annotated JDK"
inputs.dir file(inputDir)
outputs.dir file(outputDir)
doLast {
FileTree tree = fileTree(dir: inputDir)
SortedSet<String> annotatedForFiles = new TreeSet<>();
tree.visit { FileVisitDetails fvd ->
if (!fvd.file.isDirectory() && fvd.file.name.matches(".*\\.java")
&& !fvd.file.path.contains("org/checkerframework")) {
fvd.getFile().readLines().any { line ->
if (line.contains("@AnnotatedFor") || line.contains("org.checkerframework")) {
annotatedForFiles.add(fvd.file.absolutePath)
return true;
}
}
}
}
String absolutejdkHome = file(annotatedJdkHome).absolutePath
int jdkDirStringSize = absolutejdkHome.size()
copy {
from(annotatedJdkHome)
into(outputDir)
for (String filename : annotatedForFiles) {
include filename.substring(jdkDirStringSize)
}
}
javaexec {
classpath = sourceSets.main.runtimeClasspath
main = 'org.checkerframework.framework.stub.JavaStubifier'
args outputDir
}
}
}
processResources.dependsOn(copyAndMinimizeAnnotatedJdkFiles)
task checkDependencies(dependsOn: ':maybeCloneAndBuildDependencies') {
doLast {
if (!file(stubparserJar).exists()) {
throw new GradleException("${stubparserJar} does not exist. Try running './gradlew cloneAndBuildDependencies'")
}
}
}
compileJava.dependsOn(checkDependencies)
task allSourcesJar(type: Jar, group: 'Build') {
description 'Creates a sources jar that includes sources for all Checker Framework classes in framework.jar'
destinationDirectory = file("${projectDir}/dist")
archiveFileName = "framework-source.jar"
from (project(':framework').sourceSets.main.java,
project(':dataflow').sourceSets.main.allJava,
project(':javacutil').sourceSets.main.allJava)
}
task allJavadocJar(type: Jar, group: 'Build') {
description 'Creates javadoc jar include Javadoc for all of the framework'
dependsOn rootProject.tasks.allJavadoc
destinationDirectory = file("${projectDir}/dist")
archiveFileName = "framework-javadoc.jar"
from (project(':framework').tasks.javadoc.destinationDir,
project(':dataflow').tasks.javadoc.destinationDir,
project(':javacutil').tasks.javadoc.destinationDir)
}
shadowJar {
description 'Creates the "fat" framework.jar in dist'
destinationDirectory = file("${projectDir}/dist")
archiveFileName = "framework.jar"
manifest {
attributes('Automatic-Module-Name': "org.checkerframework.framework")
}
}
createCheckTypeTask(project.name, "CompilerMessages",
'org.checkerframework.checker.compilermsgs.CompilerMessagesChecker')
checkCompilerMessages {
options.compilerArgs += [
'-Apropfiles=' + sourceSets.main.resources.filter { file -> file.name.equals('messages.properties') }.asPath
]
}
task loaderTests(dependsOn: 'shadowJar', group: 'Verification') {
description 'Run tests for the annotation class loader'
dependsOn(compileTestJava)
// TODO: this dependency on checker is a bit ugly.
dependsOn project(':checker-qual').tasks.jar
dependsOn project(':checker').tasks.assemble
doLast {
exec {
executable 'make'
args = ['-C', "tests/annotationclassloader/", "all"]
}
}
}
clean {
delete("tests/returnsreceiverdelomboked")
delete('dist')
}
task delombok {
description 'Delomboks the source code tree in tests/returnsreceiverlombok'
def srcDelomboked = 'tests/returnsreceiverdelomboked'
def srcJava = 'tests/returnsreceiverlombok'
inputs.files file(srcJava)
outputs.dir file(srcDelomboked)
// This dependency is required to ensure the checker-qual jar exists,
// to prevent lombok from emitting "cannot find symbol" errors for @This
// annotations in the test input code.
dependsOn project(':checker-qual').tasks.jar
doLast {
def collection = files(configurations.testCompileClasspath)
ant.taskdef(name: 'delombok', classname: 'lombok.delombok.ant.Tasks$Delombok',
classpath: collection.asPath)
ant.delombok(from: srcJava, to: srcDelomboked, classpath: collection.asPath)
}
}
tasks.test.dependsOn("delombok")