From af2a9a5e432774e83a184fcdabc17aa52f71db53 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 19 Jan 2023 19:04:02 -0800 Subject: [PATCH] Format Gradle files --- build.gradle | 1833 +++++++++++++------------ checker-qual-android/build.gradle | 94 +- checker-qual/build.gradle | 60 +- checker-util/build.gradle | 42 +- checker/build.gradle | 1572 ++++++++++----------- dataflow/build.gradle | 397 +++--- docs/examples/errorprone/build.gradle | 36 +- docs/examples/lombok/build.gradle | 22 +- framework-test/build.gradle | 54 +- framework/build.gradle | 318 +++-- gradle-mvn-push.gradle | 42 +- javacutil/build.gradle | 58 +- settings.gradle | 8 +- 13 files changed, 2327 insertions(+), 2209 deletions(-) diff --git a/build.gradle b/build.gradle index 9f260d227e1..c90367f17e5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,19 +1,20 @@ import de.undercouch.gradle.tasks.download.Download plugins { - // https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow - id 'com.github.johnrengelman.shadow' version '7.1.2' - // https://plugins.gradle.org/plugin/de.undercouch.download - id 'de.undercouch.download' version '5.3.0' - id 'java' - // https://github.com/tbroyer/gradle-errorprone-plugin - id 'net.ltgt.errorprone' version '3.0.1' - // https://plugins.gradle.org/plugin/org.ajoberstar.grgit - id 'org.ajoberstar.grgit' version '4.1.1' apply false - - // Code formatting; defines targets "spotlessApply" and "spotlessCheck". - // https://github.com/diffplug/spotless/tags ; see tags starting "gradle/" - id 'com.diffplug.spotless' version '6.12.0' + // https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow + id 'com.github.johnrengelman.shadow' version '7.1.2' + // https://plugins.gradle.org/plugin/de.undercouch.download + id 'de.undercouch.download' version '5.3.0' + id 'java' + // https://github.com/tbroyer/gradle-errorprone-plugin + id 'net.ltgt.errorprone' version '3.0.1' + // https://plugins.gradle.org/plugin/org.ajoberstar.grgit + id 'org.ajoberstar.grgit' version '4.1.1' apply false + + id 'groovy' // needed for formatting Gradle files + // Code formatting; defines targets "spotlessApply" and "spotlessCheck". + // https://github.com/diffplug/spotless/tags ; see tags starting "gradle/" + id 'com.diffplug.spotless' version '6.12.0' } apply plugin: 'de.undercouch.download' @@ -22,75 +23,75 @@ import org.ajoberstar.grgit.Grgit // There is another `repositories { ... }` block below; if you change this one, change that one as well. repositories { - mavenCentral() + mavenCentral() } ext { - release = false + release = false - // On a Java 8 JVM, use error-prone javac and source/target 8. - // On a Java 9+ JVM, use the host javac, default source/target, and required module flags. - isJava8 = JavaVersion.current() == JavaVersion.VERSION_1_8 - // As of 2022-11-30, delombok crashes under JDK 19. - // As of mid-January 2023, a lombok release for Java 19 is coming "in a week". - skipDelombok = JavaVersion.current() == JavaVersion.VERSION_19 + // On a Java 8 JVM, use error-prone javac and source/target 8. + // On a Java 9+ JVM, use the host javac, default source/target, and required module flags. + isJava8 = JavaVersion.current() == JavaVersion.VERSION_1_8 + // As of 2022-11-30, delombok crashes under JDK 19. + // As of mid-January 2023, a lombok release for Java 19 is coming "in a week". + skipDelombok = JavaVersion.current() == JavaVersion.VERSION_19 - // This call to `isCompatibleWith` causes a Gradle run-time failure: "No signature of method". - // isJava17compatible = JavaVersion.isCompatibleWith(JavaVersion.VERSION_17) - isJava17orHigher = JavaVersion.current() >= JavaVersion.VERSION_17 + // This call to `isCompatibleWith` causes a Gradle run-time failure: "No signature of method". + // isJava17compatible = JavaVersion.isCompatibleWith(JavaVersion.VERSION_17) + isJava17orHigher = JavaVersion.current() >= JavaVersion.VERSION_17 - errorproneJavacVersion = '9+181-r4173-1' + errorproneJavacVersion = '9+181-r4173-1' - parentDir = file("${rootDir}/../").absolutePath + parentDir = file("${rootDir}/../").absolutePath - annotationTools = "${parentDir}/annotation-tools" - afu = "${annotationTools}/annotation-file-utilities" + annotationTools = "${parentDir}/annotation-tools" + afu = "${annotationTools}/annotation-file-utilities" - stubparser = "${parentDir}/stubparser" - stubparserJar = "${stubparser}/javaparser-core/target/stubparser-3.24.10.jar" + stubparser = "${parentDir}/stubparser" + stubparserJar = "${stubparser}/javaparser-core/target/stubparser-3.24.10.jar" - plumeScriptsHome = "${project(':checker').projectDir}/bin-devel/.plume-scripts" - htmlToolsHome = "${project(':checker').projectDir}/bin-devel/.html-tools" + plumeScriptsHome = "${project(':checker').projectDir}/bin-devel/.plume-scripts" + htmlToolsHome = "${project(':checker').projectDir}/bin-devel/.html-tools" - javadocMemberLevel = JavadocMemberLevel.PROTECTED + javadocMemberLevel = JavadocMemberLevel.PROTECTED - // The local git repository, typically in the .git directory, but not for worktrees. - // This value is always overwritten, but Gradle needs the variable to be initialized. - localRepo = '.git' + // The local git repository, typically in the .git directory, but not for worktrees. + // This value is always overwritten, but Gradle needs the variable to be initialized. + localRepo = '.git' } // Keep in sync with check in // framework/src/main/java/org/checkerframework/framework/source/SourceChecker.java . switch (JavaVersion.current()) { - case JavaVersion.VERSION_1_8: - case JavaVersion.VERSION_11: - case JavaVersion.VERSION_17: - case JavaVersion.VERSION_19: - break; // Supported versions - default: - logger.info('The Checker Framework has only been tested with JDK 8, 11, 17, and 19.' + - ' You are using JDK ' + JavaVersion.current().majorVersion + '.'); - break; + case JavaVersion.VERSION_1_8: + case JavaVersion.VERSION_11: + case JavaVersion.VERSION_17: + case JavaVersion.VERSION_19: + break; // Supported versions + default: + logger.info('The Checker Framework has only been tested with JDK 8, 11, 17, and 19.' + + ' You are using JDK ' + JavaVersion.current().majorVersion + '.'); + break; } task setLocalRepo(type:Exec) { - commandLine 'git', 'worktree', 'list' - standardOutput = new ByteArrayOutputStream() - doLast { - String worktreeList = standardOutput.toString() - localRepo = worktreeList.substring(0, worktreeList.indexOf(' ')) + '/.git' - } + commandLine 'git', 'worktree', 'list' + standardOutput = new ByteArrayOutputStream() + doLast { + String worktreeList = standardOutput.toString() + localRepo = worktreeList.substring(0, worktreeList.indexOf(' ')) + '/.git' + } } // No group so it does not show up in the output of `gradlew tasks` task installGitHooks(type: Copy, dependsOn: 'setLocalRepo') { - description 'Copies git hooks to .git directory' - from files('checker/bin-devel/git.post-merge', 'checker/bin-devel/git.pre-commit') - rename('git\\.(.*)', '$1') - into localRepo + '/hooks' + description 'Copies git hooks to .git directory' + from files('checker/bin-devel/git.post-merge', 'checker/bin-devel/git.pre-commit') + rename('git\\.(.*)', '$1') + into localRepo + '/hooks' } spotless { - // Resolve the spottless plugin dependencies from the buildscript repositories rather than the + // Resolve the Spotless plugin dependencies from the buildscript repositories rather than the // project repositories. That way the spotless plugin does not use the locally built version of // checker-qual as a dependency. Without this, errors like the follow are issued when running // a spotless task without a locally-built version of checker-qual.jar: @@ -112,47 +113,50 @@ spotlessPredeclare { java { googleJavaFormat() } + groovyGradle { + greclipse() + } } allprojects { - tasks.withType(JavaCompile).configureEach { - options.fork = true - } + tasks.withType(JavaCompile).configureEach { + options.fork = true + } - apply plugin: 'java' - apply plugin: 'com.github.johnrengelman.shadow' - apply plugin: 'de.undercouch.download' - apply plugin: 'net.ltgt.errorprone' - apply plugin: 'com.diffplug.spotless' - - group 'org.checkerframework' - // Increment the minor version (second number) rather than just the patch - // level (third number) if: - // * any new checkers have been added, or - // * backward-incompatible changes have been made to APIs or elsewhere. - version '3.29.1-SNAPSHOT' - - repositories { - mavenCentral() - } + apply plugin: 'java' + apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'de.undercouch.download' + apply plugin: 'net.ltgt.errorprone' + apply plugin: 'com.diffplug.spotless' - configurations { - javacJar + group 'org.checkerframework' + // Increment the minor version (second number) rather than just the patch + // level (third number) if: + // * any new checkers have been added, or + // * backward-incompatible changes have been made to APIs or elsewhere. + version '3.29.1-SNAPSHOT' - // Holds the combined classpath of all subprojects including the subprojects themselves. - allProjects + repositories { + mavenCentral() + } - // Exclude checker-qual dependency added by Error Prone to avoid a circular dependency. - annotationProcessor.exclude group:'org.checkerframework', module:'checker-qual' - } + configurations { + javacJar - dependencies { - javacJar group: 'com.google.errorprone', name: 'javac', version: "$errorproneJavacVersion" + // Holds the combined classpath of all subprojects including the subprojects themselves. + allProjects - errorproneJavac("com.google.errorprone:javac:$errorproneJavacVersion") + // Exclude checker-qual dependency added by Error Prone to avoid a circular dependency. + annotationProcessor.exclude group:'org.checkerframework', module:'checker-qual' + } - allProjects subprojects - } + dependencies { + javacJar group: 'com.google.errorprone', name: 'javac', version: "$errorproneJavacVersion" + + errorproneJavac("com.google.errorprone:javac:$errorproneJavacVersion") + + allProjects subprojects + } ext { // A list of add-export and add-open arguments to be used when running the Checker Framework. @@ -160,19 +164,28 @@ allprojects { // the sections with labels "javac-jdk11-non-modularized", "maven", and "sbt" in the manual // and in the checker-framework-gradle-plugin, CheckerFrameworkPlugin#applyToProject compilerArgsForRunningCF = [ - // These are required in Java 16+ because the --illegal-access option is set to deny - // by default. None of these packages are accessed via reflection, so the module - // only needs to be exported, but not opened. - '--add-exports', 'jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - '--add-exports', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - // Required because the Checker Framework reflectively accesses private members in com.sun.tools.javac.comp. - '--add-opens', 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + // These are required in Java 16+ because the --illegal-access option is set to deny + // by default. None of these packages are accessed via reflection, so the module + // only needs to be exported, but not opened. + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-exports', + 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + // Required because the Checker Framework reflectively accesses private members in com.sun.tools.javac.comp. + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', ] reflectionUtilVersion = '1.0.5' @@ -180,39 +193,42 @@ allprojects { } spotless { - - // If you add any formatters to this block that require dependencies here, then you must also + // If you add any formatters to this block that require dependencies, then you must also // add them to spotlessPredeclare block. + format 'misc', { // define the files to apply `misc` to - target '*.gradle', '*.md', '.gitignore' + target '**/*.gradle', '*.md', '.gitignore' // define the steps to apply to those files - trimTrailingWhitespace() indentWithSpaces(2) - endWithNewline() + trimTrailingWhitespace() + // endWithNewline() // Don't want to end empty files with a newline } + java { def targets = [ - // add target folders here - 'checker', - 'checker-qual', - 'checker-util', - 'dataflow', - 'docs/examples', - 'docs/tutorial', - 'framework', - 'framework-test', - 'javacutil', + // add target folders here + 'checker', + 'checker-qual', + 'checker-util', + 'dataflow', + 'docs/examples', + 'docs/tutorial', + 'framework', + 'framework-test', + 'javacutil', ] - targets = targets.collectMany {[ + targets = targets.collectMany { + [ // must call toString() to convert GString to String "${it}/**/*.java".toString(), // Not .ajava files because formatting would remove import statements. - ]} + ]} target targets - def doNotFormat = [ 'dataflow/manual/examples/', + def doNotFormat = [ + 'dataflow/manual/examples/', '**/nullness-javac-errors/*', '**/calledmethods-delomboked/*', '**/returnsreceiverdelomboked/*', @@ -225,18 +241,27 @@ allprojects { targetExclude doNotFormat, '**/java17/', '**/*record*/' } - googleJavaFormat() + googleJavaFormat() // the formatter to apply to Java files formatAnnotations() - // Remove addTypeAnnotation after a Spotless release is made (2022-01-15). - .addTypeAnnotation("AinferDefaultType") - .addTypeAnnotation("AinferParent") - .addTypeAnnotation("AinferSibling1") - .addTypeAnnotation("AinferSibling2") - .addTypeAnnotation("AinferTop") - .addTypeAnnotation("AinferImplicitAnno") - .addTypeAnnotation("AinferSiblingWithFields") - .addTypeAnnotation("DoesNotMatchRegex") + // Remove addTypeAnnotation after a Spotless release is made (2022-01-15). + .addTypeAnnotation("AinferDefaultType") + .addTypeAnnotation("AinferParent") + .addTypeAnnotation("AinferSibling1") + .addTypeAnnotation("AinferSibling2") + .addTypeAnnotation("AinferTop") + .addTypeAnnotation("AinferImplicitAnno") + .addTypeAnnotation("AinferSiblingWithFields") + .addTypeAnnotation("DoesNotMatchRegex") } + + groovyGradle { + target '**/*.gradle' + greclipse() // which formatter Spotless should use to format .gradle files. + indentWithSpaces(2) + trimTrailingWhitespace() + // endWithNewline() // Don't want to end empty files with a newline + } + } // The Spotless plugin uses the latest version of google-java-format // that is compatible with the currently running JVM. Under Java 8, @@ -249,215 +274,220 @@ allprojects { } - // After all the tasks have been created, modify some of them. - afterEvaluate { - configurations { - checkerFatJar { - canBeConsumed = false - canBeResolved = true - } + // After all the tasks have been created, modify some of them. + afterEvaluate { + configurations { + checkerFatJar { + canBeConsumed = false + canBeResolved = true } + } - dependencies { - checkerFatJar(project(path: ':checker', configuration: 'fatJar')) - } + dependencies { + checkerFatJar(project(path: ':checker', configuration: 'fatJar')) + } - // Add the fat checker.jar to the classpath of every Javadoc task. This allows Javadoc in - // any module to reference classes in any other module. - // Also, build and use ManualTaglet as a taglet. - tasks.withType(Javadoc) { - def tagletVersion = isJava8 ? 'tagletJdk8' : 'taglet' - - dependsOn(':checker:shadowJar') - dependsOn(":framework-test:${tagletVersion}Classes") - doFirst { - options.encoding = 'UTF-8' - if (!name.equals('javadocDoclintAll')) { - options.memberLevel = javadocMemberLevel - } - classpath += configurations.getByName('checkerFatJar').asFileTree - if (isJava8) { - classpath += configurations.javacJar - } - options.taglets 'org.checkerframework.taglet.ManualTaglet' - options.tagletPath(project(':framework-test').sourceSets."${tagletVersion}".output.classesDirs.getFiles() as File[]) - - // We want to link to Java 9 documentation of the compiler classes since we use Java 9 - // versions of those classes and Java 8 for everything else. Because the compiler classes are not - // a part of the main documentation of Java 8, javadoc links to the Java 9 versions. - // TODO, this creates broken links to the com.sun.tools.javac package. - // Only add the links of building with Java 8. This prevents the following error: - // warning: URL https://docs.oracle.com/javase/8/docs/api/element-list was redirected - // to https://docs.oracle.com/en/java/javase/19/ -- Update the command-line options - // to suppress this warning. - if (isJava8) { - options.links = ['https://docs.oracle.com/javase/8/docs/api/', 'https://docs.oracle.com/javase/9/docs/api/'] - } - // This file is looked for by Javadoc. - file("${destinationDir}/resources/fonts/").mkdirs() - ant.touch(file: "${destinationDir}/resources/fonts/dejavu.css") - options.addStringOption('source', '8') - // "-Xwerror" requires Javadoc everywhere. Currently, CI jobs require Javadoc only - // on changed lines. Enable -Xwerror in the future when all Javadoc exists. - // options.addBooleanOption('Xwerror', true) - options.addStringOption('Xmaxwarns', '99999') - } + // Add the fat checker.jar to the classpath of every Javadoc task. This allows Javadoc in + // any module to reference classes in any other module. + // Also, build and use ManualTaglet as a taglet. + tasks.withType(Javadoc) { + def tagletVersion = isJava8 ? 'tagletJdk8' : 'taglet' + + dependsOn(':checker:shadowJar') + dependsOn(":framework-test:${tagletVersion}Classes") + doFirst { + options.encoding = 'UTF-8' + if (!name.equals('javadocDoclintAll')) { + options.memberLevel = javadocMemberLevel } + classpath += configurations.getByName('checkerFatJar').asFileTree + if (isJava8) { + classpath += configurations.javacJar + } + options.taglets 'org.checkerframework.taglet.ManualTaglet' + options.tagletPath(project(':framework-test').sourceSets."${tagletVersion}".output.classesDirs.getFiles() as File[]) + + // We want to link to Java 9 documentation of the compiler classes since we use Java 9 + // versions of those classes and Java 8 for everything else. Because the compiler classes are not + // a part of the main documentation of Java 8, javadoc links to the Java 9 versions. + // TODO, this creates broken links to the com.sun.tools.javac package. + // Only add the links of building with Java 8. This prevents the following error: + // warning: URL https://docs.oracle.com/javase/8/docs/api/element-list was redirected + // to https://docs.oracle.com/en/java/javase/19/ -- Update the command-line options + // to suppress this warning. + if (isJava8) { + options.links = [ + 'https://docs.oracle.com/javase/8/docs/api/', + 'https://docs.oracle.com/javase/9/docs/api/' + ] + } + // This file is looked for by Javadoc. + file("${destinationDir}/resources/fonts/").mkdirs() + ant.touch(file: "${destinationDir}/resources/fonts/dejavu.css") + options.addStringOption('source', '8') + // "-Xwerror" requires Javadoc everywhere. Currently, CI jobs require Javadoc only + // on changed lines. Enable -Xwerror in the future when all Javadoc exists. + // options.addBooleanOption('Xwerror', true) + options.addStringOption('Xmaxwarns', '99999') + } + } - // Add standard javac options - tasks.withType(JavaCompile) { compilationTask -> - dependsOn(':installGitHooks') - // Sorting is commented out because it disables incremental compilation. - // Uncomment when needed. - // // Put source files in deterministic order, for debugging. - // compilationTask.source = compilationTask.source.sort() - - // Don't try to use `options.release.set(8)` here. - // Because CI compiles under JDK 8, we know no Java 9+ features are used. - sourceCompatibility = 8 - targetCompatibility = 8 - // Because the target is 8, all of the public compiler classes are accessible, so - // --add-exports are not required (nor are they allowed with target 8). See - // https://openjdk.org/jeps/247 for details on compiling for older versions. - - // When sourceCompatibility or release is changed to 11, then the following will be required. - // options.compilerArgs += [ - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - // '--add-exports', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - // ] - // This is equivalent to writing "exports jdk.compiler/... to ALL-UNNAMED" in the - // module-info.java of jdk.compiler, so corresponding --add-opens are only required for - // reflective access to private members. - // - // From https://openjdk.org/jeps/261, Section titled: "Breaking encapsulation" - // "The effect of each instance [of --add-exports] is to add a qualified export of the - // named package from the source module to the target module. This is, essentially, a - // command-line form of an exports clause in a module declaration[...]. - // [...] - // The --add-exports option enables access to the public types of a specified package. - // It is sometimes necessary to go further and enable access to all non-public elements - // via the setAccessible method of the core reflection API. The --add-opens option can - // be used, at run time, to do this." - - options.failOnError = true - options.deprecation = true - options.compilerArgs += [ - '-g', - '-Werror', - // -options: To not get a warning about missing bootstrap classpath for Java 8 (once we use Java 9). - // -fallthrough: Don't check fallthroughs. Instead, use Error Prone. Its - // warnings are suppressible with a "// fall through" comment. - // -classfile: classgraph jar file and https://bugs.openjdk.org/browse/JDK-8190452 - '-Xlint:-options,-fallthrough,-classfile', - '-Xlint', - ] - - options.encoding = 'UTF-8' - options.fork = true - if (isJava8) { - options.forkOptions.jvmArgs += ["-Xbootclasspath/p:${configurations.javacJar.asPath}".toString()] - } + // Add standard javac options + tasks.withType(JavaCompile) { compilationTask -> + dependsOn(':installGitHooks') + // Sorting is commented out because it disables incremental compilation. + // Uncomment when needed. + // // Put source files in deterministic order, for debugging. + // compilationTask.source = compilationTask.source.sort() + + // Don't try to use `options.release.set(8)` here. + // Because CI compiles under JDK 8, we know no Java 9+ features are used. + sourceCompatibility = 8 + targetCompatibility = 8 + // Because the target is 8, all of the public compiler classes are accessible, so + // --add-exports are not required (nor are they allowed with target 8). See + // https://openjdk.org/jeps/247 for details on compiling for older versions. + + // When sourceCompatibility or release is changed to 11, then the following will be required. + // options.compilerArgs += [ + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + // '--add-exports', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + // ] + // This is equivalent to writing "exports jdk.compiler/... to ALL-UNNAMED" in the + // module-info.java of jdk.compiler, so corresponding --add-opens are only required for + // reflective access to private members. + // + // From https://openjdk.org/jeps/261, Section titled: "Breaking encapsulation" + // "The effect of each instance [of --add-exports] is to add a qualified export of the + // named package from the source module to the target module. This is, essentially, a + // command-line form of an exports clause in a module declaration[...]. + // [...] + // The --add-exports option enables access to the public types of a specified package. + // It is sometimes necessary to go further and enable access to all non-public elements + // via the setAccessible method of the core reflection API. The --add-opens option can + // be used, at run time, to do this." + + options.failOnError = true + options.deprecation = true + options.compilerArgs += [ + '-g', + '-Werror', + // -options: To not get a warning about missing bootstrap classpath for Java 8 (once we use Java 9). + // -fallthrough: Don't check fallthroughs. Instead, use Error Prone. Its + // warnings are suppressible with a "// fall through" comment. + // -classfile: classgraph jar file and https://bugs.openjdk.org/browse/JDK-8190452 + '-Xlint:-options,-fallthrough,-classfile', + '-Xlint', + ] - // Error Prone depends on checker-qual.jar, so don't run it on that project to avoid a circular dependency. - // TODO: enable Error Prone on test classes. - if (compilationTask.name.equals('compileJava') && !project.name.startsWith('checker-qual')) { - // Error Prone must be available in the annotation processor path - options.annotationProcessorPath = configurations.errorprone - // Enable Error Prone - options.errorprone.enabled = !isJava8 - options.errorprone.disableWarningsInGeneratedCode = true - options.errorprone.errorproneArgs = [ - // Many compiler classes are interned. - '-Xep:ReferenceEquality:OFF', - // These might be worth fixing. - '-Xep:DefaultCharset:OFF', - // Not useful to suggest Splitter; maybe clean up. - '-Xep:StringSplitter:OFF', - // Too broad, rejects seemingly-correct code. - '-Xep:EqualsGetClass:OFF', - // Not a real problem - '-Xep:MixedMutabilityReturnType:OFF', - // Don't want to add a dependency to ErrorProne. - '-Xep:AnnotateFormatMethod:OFF', - // Warns for every use of "@checker_framework.manual" - '-Xep:InvalidBlockTag:OFF', - // Recommends writing @InlineMe which is an Error-Prone-specific annotation - '-Xep:InlineMeSuggester:OFF', - // Recommends writing @CanIgnoreReturnValue which is an Error-Prone-specific annotation. - // It would be great if Error Prone recognized the @This annotation. - '-Xep:CanIgnoreReturnValueSuggester:OFF', - // Should be turned off when using the Checker Framework. - '-Xep:ExtendsObject:OFF', - // -Werror halts the build if Error Prone issues a warning, which ensures that - // the errors get fixed. On the downside, Error Prone (or maybe the compiler?) - // stops as soon as it issues one warning, rather than outputting them all. - // https://github.com/google/error-prone/issues/436 - '-Werror', - ] - } else { - options.errorprone.enabled = false - } - } + options.encoding = 'UTF-8' + options.fork = true + if (isJava8) { + options.forkOptions.jvmArgs += [ + "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() + ] + } + + // Error Prone depends on checker-qual.jar, so don't run it on that project to avoid a circular dependency. + // TODO: enable Error Prone on test classes. + if (compilationTask.name.equals('compileJava') && !project.name.startsWith('checker-qual')) { + // Error Prone must be available in the annotation processor path + options.annotationProcessorPath = configurations.errorprone + // Enable Error Prone + options.errorprone.enabled = !isJava8 + options.errorprone.disableWarningsInGeneratedCode = true + options.errorprone.errorproneArgs = [ + // Many compiler classes are interned. + '-Xep:ReferenceEquality:OFF', + // These might be worth fixing. + '-Xep:DefaultCharset:OFF', + // Not useful to suggest Splitter; maybe clean up. + '-Xep:StringSplitter:OFF', + // Too broad, rejects seemingly-correct code. + '-Xep:EqualsGetClass:OFF', + // Not a real problem + '-Xep:MixedMutabilityReturnType:OFF', + // Don't want to add a dependency to ErrorProne. + '-Xep:AnnotateFormatMethod:OFF', + // Warns for every use of "@checker_framework.manual" + '-Xep:InvalidBlockTag:OFF', + // Recommends writing @InlineMe which is an Error-Prone-specific annotation + '-Xep:InlineMeSuggester:OFF', + // Recommends writing @CanIgnoreReturnValue which is an Error-Prone-specific annotation. + // It would be great if Error Prone recognized the @This annotation. + '-Xep:CanIgnoreReturnValueSuggester:OFF', + // Should be turned off when using the Checker Framework. + '-Xep:ExtendsObject:OFF', + // -Werror halts the build if Error Prone issues a warning, which ensures that + // the errors get fixed. On the downside, Error Prone (or maybe the compiler?) + // stops as soon as it issues one warning, rather than outputting them all. + // https://github.com/google/error-prone/issues/436 + '-Werror', + ] + } else { + options.errorprone.enabled = false + } } + } } task cloneAndBuildDependencies(type: Exec, group: 'Build') { - description 'Clones (or updates) and builds all dependencies' - executable 'checker/bin-devel/build.sh' + description 'Clones (or updates) and builds all dependencies' + executable 'checker/bin-devel/build.sh' } task maybeCloneAndBuildDependencies() { - // No group so it does not show up in the output of `gradlew tasks` - description 'Clones (or updates) and builds all dependencies if they are not present.' - onlyIf { - !file(stubparserJar).exists() - // The jdk repository is cloned via the copyAndMinimizeAnnotatedJdkFiles task that is run if - // the repository does not exist when building checker.jar. - } + // No group so it does not show up in the output of `gradlew tasks` + description 'Clones (or updates) and builds all dependencies if they are not present.' + onlyIf { + !file(stubparserJar).exists() + // The jdk repository is cloned via the copyAndMinimizeAnnotatedJdkFiles task that is run if + // the repository does not exist when building checker.jar. + } - doFirst { - if (file(stubparser).exists()) { - exec { - workingDir stubparser - executable 'git' - args = ['pull', '-q'] - ignoreExitValue = true - } - exec { - workingDir stubparser - executable "${stubparser}/.build-without-test.sh" - } - } else { - exec { - executable 'checker/bin-devel/build.sh' - } - } + doFirst { + if (file(stubparser).exists()) { + exec { + workingDir stubparser + executable 'git' + args = ['pull', '-q'] + ignoreExitValue = true + } + exec { + workingDir stubparser + executable "${stubparser}/.build-without-test.sh" + } + } else { + exec { + executable 'checker/bin-devel/build.sh' + } } - doLast { - if (!file(stubparserJar).exists()) { - println "The contents of ${stubparser}/javaparser-core/target (which does not contain stubparser.jar!) are:" - exec { - workingDir "${stubparser}/javaparser-core/target" - executable 'ls' - ignoreExitValue = true - } - throw new RuntimeException('Can\'t find stubparser jar: ' + stubparserJar) - } + } + doLast { + if (!file(stubparserJar).exists()) { + println "The contents of ${stubparser}/javaparser-core/target (which does not contain stubparser.jar!) are:" + exec { + workingDir "${stubparser}/javaparser-core/target" + executable 'ls' + ignoreExitValue = true + } + throw new RuntimeException('Can\'t find stubparser jar: ' + stubparserJar) } + } } task version(group: 'Documentation') { - description 'Print Checker Framework version' - doLast { - println version - } + description 'Print Checker Framework version' + doLast { + println version + } } /** @@ -470,53 +500,56 @@ task version(group: 'Documentation') { * @param args list of arguments to pass to the checker */ def createCheckTypeTask(projectName, taskName, checker, args = []) { - project("${projectName}").tasks.create(name: "check${taskName}", type: JavaCompile, dependsOn: ':checker:shadowJar') { - description "Run the ${taskName} Checker on the main sources." - group 'Verification' - // Always run the task. - outputs.upToDateWhen { false } - source = project("${projectName}").sourceSets.main.java - classpath = files(project("${projectName}").compileJava.classpath,project(':checker-qual').sourceSets.main.output) - destinationDirectory = file("${buildDir}") - - options.annotationProcessorPath = files(project(':checker').tasks.shadowJar.archivePath) - options.compilerArgs += [ - '-processor', "${checker}", - '-proc:only', - '-Xlint:-processing', - '-Xmaxerrs', '10000', - '-Xmaxwarns', '10000', - '-ArequirePrefixInWarningSuppressions', - '-AwarnUnneededSuppressions', - ] - options.compilerArgs += args - options.forkOptions.jvmArgs += ['-Xmx2g'] + project("${projectName}").tasks.create(name: "check${taskName}", type: JavaCompile, dependsOn: ':checker:shadowJar') { + description "Run the ${taskName} Checker on the main sources." + group 'Verification' + // Always run the task. + outputs.upToDateWhen { false } + source = project("${projectName}").sourceSets.main.java + classpath = files(project("${projectName}").compileJava.classpath,project(':checker-qual').sourceSets.main.output) + destinationDirectory = file("${buildDir}") + + options.annotationProcessorPath = files(project(':checker').tasks.shadowJar.archivePath) + options.compilerArgs += [ + '-processor', + "${checker}", + '-proc:only', + '-Xlint:-processing', + '-Xmaxerrs', + '10000', + '-Xmaxwarns', + '10000', + '-ArequirePrefixInWarningSuppressions', + '-AwarnUnneededSuppressions', + ] + options.compilerArgs += args + options.forkOptions.jvmArgs += ['-Xmx2g'] - if (isJava8) { - options.compilerArgs += [ - '-source', - '8', - '-target', - '8' - ] - } else { - options.fork = true - options.forkOptions.jvmArgs += compilerArgsForRunningCF - } + if (isJava8) { + options.compilerArgs += [ + '-source', + '8', + '-target', + '8' + ] + } else { + options.fork = true + options.forkOptions.jvmArgs += compilerArgsForRunningCF } + } } task htmlValidate(type: Exec, group: 'Format') { - description 'Validate that HTML files are well-formed' - executable 'html5validator' - args = [ - '--ignore', - '/api/', - '/build/', - '/docs/manual/manual.html', - '/docs/manual/plume-bib/docs/index.html', - '/checker/jdk/nullness/src/java/lang/ref/package.html' - ] + description 'Validate that HTML files are well-formed' + executable 'html5validator' + args = [ + '--ignore', + '/api/', + '/build/', + '/docs/manual/manual.html', + '/docs/manual/plume-bib/docs/index.html', + '/checker/jdk/nullness/src/java/lang/ref/package.html' + ] } @@ -527,9 +560,9 @@ task htmlValidate(type: Exec, group: 'Format') { // To make javadoc for only one subproject, run `./gradlew javadoc` // in the subproject or `./gradlew :checker:javadoc` at the top level. task allJavadoc(type: Javadoc, group: 'Documentation') { - description = 'Generates API documentation that includes all the modules.' - dependsOn(':checker:shadowJar', 'getPlumeScripts', 'getHtmlTools') - destinationDir = file("${rootDir}/docs/api") + description = 'Generates API documentation that includes all the modules.' + dependsOn(':checker:shadowJar', 'getPlumeScripts', 'getHtmlTools') + destinationDir = file("${rootDir}/docs/api") source( project(':checker-util').sourceSets.main.allJava, project(':checker-qual').sourceSets.main.allJava, @@ -538,53 +571,59 @@ task allJavadoc(type: Javadoc, group: 'Documentation') { project(':dataflow').sourceSets.main.allJava, project(':javacutil').sourceSets.main.allJava, project(':framework-test').sourceSets.main.allJava, - ) + ) - doFirst { - source( + doFirst { + source( project(':framework-test').sourceSets."${isJava8 ? 'tagletJdk8' : 'taglet'}".allJava - ) - } + ) + } - classpath = configurations.allProjects - if (isJava8) { - classpath += configurations.javacJar + classpath = configurations.allProjects + if (isJava8) { + classpath += configurations.javacJar + } + doLast { + exec { + // Javadoc for to com.sun.tools.java.* is not publicly available, so these links are broken. + // This command removes those links. + workingDir "${rootDir}/docs/api" + executable "${plumeScriptsHome}/preplace" + args += [ + ' - String junitClassName = file.name.replaceAll('.java', '') - tasks.create(name: "${junitClassName}", type: Test) { - description "Run ${junitClassName} tests." - include "**/${name}.class" + } catch (Exception ex) { + if (ex.getCause() != null && ex.getCause().getCause()!= null) { + String msg = ex.getCause().getLocalizedMessage() + ':\n' + msg += ex.getCause().getCause().getLocalizedMessage() + '\n' + msg += 'Have you installed jtreg?' + println msg } + throw ex + } } + } + } - // Configure JUnit tests - tasks.withType(Test) { - if (isJava8) { - jvmArgs "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() - } else { - jvmArgs += compilerArgsForRunningCF - } - - maxParallelForks = Integer.MAX_VALUE + // Create a task for each JUnit test class whose name is the same as the JUnit class name. + sourceSets.test.allJava.filter { it.path.contains('test/junit') }.forEach { file -> + String junitClassName = file.name.replaceAll('.java', '') + tasks.create(name: "${junitClassName}", type: Test) { + description "Run ${junitClassName} tests." + include "**/${name}.class" + } + } - if (project.name.is('checker')) { - dependsOn('copyJarsToDist') - } + // Configure JUnit tests + tasks.withType(Test) { + if (isJava8) { + jvmArgs "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() + } else { + jvmArgs += compilerArgsForRunningCF + } - if (project.hasProperty('emit.test.debug')) { - systemProperties += ['emit.test.debug': 'true'] - } + maxParallelForks = Integer.MAX_VALUE - testLogging { - showStandardStreams = true - // Always run the tests - outputs.upToDateWhen { false } + if (project.name.is('checker')) { + dependsOn('copyJarsToDist') + } - // Show the found unexpected diagnostics and expected diagnostics not found. - exceptionFormat 'full' - events 'failed' - } + if (project.hasProperty('emit.test.debug')) { + systemProperties += ['emit.test.debug': 'true'] + } - // After each test, print a summary. - afterSuite { desc, result -> - if (desc.getClassName() != null) { - long mils = result.getEndTime() - result.getStartTime() - double seconds = mils / 1000.0 + testLogging { + showStandardStreams = true + // Always run the tests + outputs.upToDateWhen { false } - println "Testsuite: ${desc.getClassName()}\n" + - "Tests run: ${result.testCount}, " + - "Failures: ${result.failedTestCount}, " + - "Skipped: ${result.skippedTestCount}, " + - "Time elapsed: ${seconds} sec\n" - } + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat 'full' + events 'failed' + } - } + // After each test, print a summary. + afterSuite { desc, result -> + if (desc.getClassName() != null) { + long mils = result.getEndTime() - result.getStartTime() + double seconds = mils / 1000.0 + + println "Testsuite: ${desc.getClassName()}\n" + + "Tests run: ${result.testCount}, " + + "Failures: ${result.failedTestCount}, " + + "Skipped: ${result.skippedTestCount}, " + + "Time elapsed: ${seconds} sec\n" } - // Create a nonJunitTests task per project - tasks.create(name: 'nonJunitTests', group: 'Verification') { - description 'Run all Checker Framework tests except for the Junit tests and inference tests.' - if (project.name.is('framework') || project.name.is('checker')) { - dependsOn('jtregTests') - } - if (project.name.is('framework')) { - dependsOn('loaderTests') - } + } + } - if (project.name.is('checker')) { - if (!isJava8) { - dependsOn('jtregJdk11Tests') - } - dependsOn('nullnessExtraTests', 'commandLineTests', 'tutorialTests') - } + // Create a nonJunitTests task per project + tasks.create(name: 'nonJunitTests', group: 'Verification') { + description 'Run all Checker Framework tests except for the Junit tests and inference tests.' + if (project.name.is('framework') || project.name.is('checker')) { + dependsOn('jtregTests') + } + if (project.name.is('framework')) { + dependsOn('loaderTests') + } - if (project.name.is('dataflow')) { - dependsOn('liveVariableTest') - dependsOn('issue3447Test') - dependsOn('constantPropagationTest') - } + if (project.name.is('checker')) { + if (!isJava8) { + dependsOn('jtregJdk11Tests') } + dependsOn('nullnessExtraTests', 'commandLineTests', 'tutorialTests') + } - // Create an inferenceTests task per project - tasks.create(name: 'inferenceTests', group: 'Verification') { - description 'Run inference tests.' - if (project.name.is('checker')) { - dependsOn('ainferTest', 'wpiManyTest', 'wpiPlumeLibTest') - } - } + if (project.name.is('dataflow')) { + dependsOn('liveVariableTest') + dependsOn('issue3447Test') + dependsOn('constantPropagationTest') + } + } - // Create a typecheck task per project (dogfooding the Checker Framework on itself). - // This isn't a test of the Checker Framework as the test and nonJunitTests tasks are. - // Tasks such as 'checkInterning' are constructed by createCheckTypeTask. - tasks.create(name: 'typecheck', group: 'Verification') { - description 'Run the Checker Framework on itself' - dependsOn('checkFormatter', 'checkInterning', 'checkPurity', 'checkResourceLeak', 'checkSignature') - if (project.name.is('framework') || project.name.is('checker')) { - dependsOn('checkNullnessOnlyAnnotatedFor', 'checkCompilerMessages') - } else { - dependsOn('checkNullness') - } - } + // Create an inferenceTests task per project + tasks.create(name: 'inferenceTests', group: 'Verification') { + description 'Run inference tests.' + if (project.name.is('checker')) { + dependsOn('ainferTest', 'wpiManyTest', 'wpiPlumeLibTest') + } + } - // Create an allTests task per project. - // allTests = test + nonJunitTests + inferenceTests + typecheck - tasks.create(name: 'allTests', group: 'Verification') { - description 'Run all Checker Framework tests' - // The 'test' target is just the JUnit tests. - dependsOn('test', 'nonJunitTests', 'inferenceTests', 'typecheck') - } + // Create a typecheck task per project (dogfooding the Checker Framework on itself). + // This isn't a test of the Checker Framework as the test and nonJunitTests tasks are. + // Tasks such as 'checkInterning' are constructed by createCheckTypeTask. + tasks.create(name: 'typecheck', group: 'Verification') { + description 'Run the Checker Framework on itself' + dependsOn('checkFormatter', 'checkInterning', 'checkPurity', 'checkResourceLeak', 'checkSignature') + if (project.name.is('framework') || project.name.is('checker')) { + dependsOn('checkNullnessOnlyAnnotatedFor', 'checkCompilerMessages') + } else { + dependsOn('checkNullness') + } + } - task javadocPrivate(dependsOn: javadoc) { - doFirst { - javadocMemberLevel = JavadocMemberLevel.PRIVATE - } - doLast { - javadocMemberLevel = JavadocMemberLevel.PROTECTED - } - } + // Create an allTests task per project. + // allTests = test + nonJunitTests + inferenceTests + typecheck + tasks.create(name: 'allTests', group: 'Verification') { + description 'Run all Checker Framework tests' + // The 'test' target is just the JUnit tests. + dependsOn('test', 'nonJunitTests', 'inferenceTests', 'typecheck') + } + + task javadocPrivate(dependsOn: javadoc) { + doFirst { + javadocMemberLevel = JavadocMemberLevel.PRIVATE + } + doLast { + javadocMemberLevel = JavadocMemberLevel.PROTECTED + } } + } } // The assemble task also produces Javadoc jars, because its purpose is to build @@ -1010,151 +1068,154 @@ subprojects { assemble.dependsOn(':checker:copyJarsToDist') task checkBasicStyle(group: 'Format') { - description 'Check basic style guidelines, mostly whitespace. Not related to Checkstyle tool.' - String[] ignoreDirectories = ['.git', - '.gradle', - '.html-tools', - '.idea', - '.plume-scripts', - 'annotated', - 'api', - 'plume-bib', - 'bootstrap', - 'build', - 'jdk'] - - String[] ignoreFilePatterns = [ - '*.aux', - '*.bib', - '*.class', - '*.dvi', - '*.expected', - '*.gif', - '*.jar', - '*.jtr', - '*.log', - '*.out', - '*.patch', - '*.pdf', - '*.png', - '*.sty', - '*.toc', - '*.xcf', - '*~', - '#*#', - 'CFLogo.ai', - 'logfile.log.rec.index', - 'manual.html', - 'manual.html-e', - 'junit.*.properties', - 'securerandom.*', - 'checker/dist/META-INF/maven/org.apache.bcel/bcel/pom.xml', - 'checker/dist/META-INF/maven/org.apache.commons/commons-text/pom.xml', - 'checker/nullness/junit-assertions.astub', - 'framework/src/main/resources/git.properties'] - doLast { - FileTree tree = fileTree(dir: projectDir) - for (String dir : ignoreDirectories) { - tree.exclude "**/${dir}/**" + description 'Check basic style guidelines, mostly whitespace. Not related to Checkstyle tool.' + String[] ignoreDirectories = [ + '.git', + '.gradle', + '.html-tools', + '.idea', + '.plume-scripts', + 'annotated', + 'api', + 'plume-bib', + 'bootstrap', + 'build', + 'jdk' + ] + + String[] ignoreFilePatterns = [ + '*.aux', + '*.bib', + '*.class', + '*.dvi', + '*.expected', + '*.gif', + '*.jar', + '*.jtr', + '*.log', + '*.out', + '*.patch', + '*.pdf', + '*.png', + '*.sty', + '*.toc', + '*.xcf', + '*~', + '#*#', + 'CFLogo.ai', + 'logfile.log.rec.index', + 'manual.html', + 'manual.html-e', + 'junit.*.properties', + 'securerandom.*', + 'checker/dist/META-INF/maven/org.apache.bcel/bcel/pom.xml', + 'checker/dist/META-INF/maven/org.apache.commons/commons-text/pom.xml', + 'checker/nullness/junit-assertions.astub', + 'framework/src/main/resources/git.properties' + ] + doLast { + FileTree tree = fileTree(dir: projectDir) + for (String dir : ignoreDirectories) { + tree.exclude "**/${dir}/**" + } + for (String file : ignoreFilePatterns) { + tree.exclude "**/${file}" + } + boolean failed = false + tree.visit { + if (!it.file.isDirectory()) { + boolean blankLineAtEnd = false + String fileName = it.file.getName() + boolean checkTabs = !fileName.equals('Makefile') + it.file.eachLine { line -> + if (line.endsWith(' ')) { + println("Trailing whitespace: ${it.file.absolutePath}") + failed = true + } + if (checkTabs && line.contains('\t')) { + println("Contains tab (use spaces): ${it.file.absolutePath}") + failed = true + checkTabs = false + } + if (!line.startsWith('\\') && + (line.matches('^.* (else|finally|try)\\{}.*$') + || line.matches('^.*}(catch|else|finally) .*$') + || line.matches('^.* (catch|for|if|while)\\('))) { + // This runs on non-java files, too. + println("Missing space: ${it.file.absolutePath}") + failed = true + } + if (line.isEmpty()) { + blankLineAtEnd = true; + } else { + blankLineAtEnd = false; + } } - for (String file : ignoreFilePatterns) { - tree.exclude "**/${file}" + + if (blankLineAtEnd) { + println("Blank line at end of file: ${it.file.absolutePath}") + failed = true } - boolean failed = false - tree.visit { - if (!it.file.isDirectory()) { - boolean blankLineAtEnd = false - String fileName = it.file.getName() - boolean checkTabs = !fileName.equals('Makefile') - it.file.eachLine { line -> - if (line.endsWith(' ')) { - println("Trailing whitespace: ${it.file.absolutePath}") - failed = true - } - if (checkTabs && line.contains('\t')) { - println("Contains tab (use spaces): ${it.file.absolutePath}") - failed = true - checkTabs = false - } - if (!line.startsWith('\\') && - (line.matches('^.* (else|finally|try)\\{}.*$') - || line.matches('^.*}(catch|else|finally) .*$') - || line.matches('^.* (catch|for|if|while)\\('))) { - // This runs on non-java files, too. - println("Missing space: ${it.file.absolutePath}") - failed = true - } - if (line.isEmpty()) { - blankLineAtEnd = true; - } else { - blankLineAtEnd = false; - } - } - - if (blankLineAtEnd) { - println("Blank line at end of file: ${it.file.absolutePath}") - failed = true - } - - RandomAccessFile file - try { - file = new RandomAccessFile(it.file, 'r') - int end = file.length() - 1; - if (end > 0) { - file.seek(end) - byte last = file.readByte() - if (last != '\n') { - println("Missing newline at end of file: ${it.file.absolutePath}") - failed = true - } - } - } finally { - if (file != null) { - file.close() - } - } + + RandomAccessFile file + try { + file = new RandomAccessFile(it.file, 'r') + int end = file.length() - 1; + if (end > 0) { + file.seek(end) + byte last = file.readByte() + if (last != '\n') { + println("Missing newline at end of file: ${it.file.absolutePath}") + failed = true } + } + } finally { + if (file != null) { + file.close() + } } - if (failed) { - throw new GradleException('Files do not meet basic style guidelines.') - } + } } + if (failed) { + throw new GradleException('Files do not meet basic style guidelines.') + } + } } assemble.mustRunAfter(clean) task buildAll(group: 'Build') { - description 'Build all jar files, including source and javadoc jars' - dependsOn(allJavadoc) - subprojects { Project subproject -> - dependsOn("${subproject.name}:assemble") - dependsOn("${subproject.name}:javadocJar") - dependsOn("${subproject.name}:sourcesJar") - } - dependsOn('framework:allJavadocJar', 'framework:allSourcesJar', 'checker:allJavadocJar', 'checker:allSourcesJar', 'checker-qual:jar', 'checker-util:jar') + description 'Build all jar files, including source and javadoc jars' + dependsOn(allJavadoc) + subprojects { Project subproject -> + dependsOn("${subproject.name}:assemble") + dependsOn("${subproject.name}:javadocJar") + dependsOn("${subproject.name}:sourcesJar") + } + dependsOn('framework:allJavadocJar', 'framework:allSourcesJar', 'checker:allJavadocJar', 'checker:allSourcesJar', 'checker-qual:jar', 'checker-util:jar') } task releaseBuild(group: 'Build') { - description 'Build everything required for a release' - dependsOn(clean) - doFirst { - release = true - if (!isJava8) { - throw new RuntimeException('You must use Java 8 when making a release. You are using ' + JavaVersion.current() + '.') - } + description 'Build everything required for a release' + dependsOn(clean) + doFirst { + release = true + if (!isJava8) { + throw new RuntimeException('You must use Java 8 when making a release. You are using ' + JavaVersion.current() + '.') } - // Use finalizedBy rather than dependsOn so that release is set to true before any of the tasks are run. - finalizedBy(buildAll) - finalizedBy('checker:copyJarsToDist') + } + // Use finalizedBy rather than dependsOn so that release is set to true before any of the tasks are run. + finalizedBy(buildAll) + finalizedBy('checker:copyJarsToDist') } // No group so it does not show up in the output of `gradlew tasks` task releaseAndTest { - description 'Build everything required for a release and run allTests' - dependsOn(releaseBuild) - subprojects { Project subproject -> - dependsOn("${subproject.name}:allTests") - } + description 'Build everything required for a release and run allTests' + dependsOn(releaseBuild) + subprojects { Project subproject -> + dependsOn("${subproject.name}:allTests") + } } // Don't create an empty checker-framework-VERSION.jar @@ -1165,31 +1226,31 @@ jar.onlyIf {false} * @param publication MavenPublication */ final sharedPublicationConfiguration(publication) { - publication.pom { - url = 'https://checkerframework.org' - developers { - // These are the lead developers/maintainers, not all the developers or contributors. - developer { - id = 'mernst' - name = 'Michael Ernst' - email = 'mernst@cs.washington.edu' - url = 'https://homes.cs.washington.edu/~mernst/' - organization = 'University of Washington' - organizationUrl = 'https://www.cs.washington.edu/' - } - developer { - id = 'smillst' - name = 'Suzanne Millstein' - email = 'smillst@cs.washington.edu' - organization = 'University of Washington' - organizationUrl = 'https://www.cs.washington.edu/' - } - } + publication.pom { + url = 'https://checkerframework.org' + developers { + // These are the lead developers/maintainers, not all the developers or contributors. + developer { + id = 'mernst' + name = 'Michael Ernst' + email = 'mernst@cs.washington.edu' + url = 'https://homes.cs.washington.edu/~mernst/' + organization = 'University of Washington' + organizationUrl = 'https://www.cs.washington.edu/' + } + developer { + id = 'smillst' + name = 'Suzanne Millstein' + email = 'smillst@cs.washington.edu' + organization = 'University of Washington' + organizationUrl = 'https://www.cs.washington.edu/' + } + } - scm { - url = 'https://github.com/typetools/checker-framework.git' - connection = 'scm:git:git://github.com/typetools/checker-framework.git' - developerConnection = 'scm:git:ssh://git@github.com/typetools/checker-framework.git' - } + scm { + url = 'https://github.com/typetools/checker-framework.git' + connection = 'scm:git:git://github.com/typetools/checker-framework.git' + developerConnection = 'scm:git:ssh://git@github.com/typetools/checker-framework.git' } + } } diff --git a/checker-qual-android/build.gradle b/checker-qual-android/build.gradle index ea591652d60..7242d8aad4a 100644 --- a/checker-qual-android/build.gradle +++ b/checker-qual-android/build.gradle @@ -1,78 +1,78 @@ evaluationDependsOn(':checker-qual') task copySources(type: Copy) { - description 'Copy checker-qual source to checker-qual-android' + description 'Copy checker-qual source to checker-qual-android' - includeEmptyDirs = false - doFirst { - // Delete the directory in case a previously copied file should no longer be in checker-qual - delete file('src') - } - from files('../checker-qual/src/main') - include '**/*.java' - exclude '**/SignednessUtilExtra.java' - into file('src/main') + includeEmptyDirs = false + doFirst { + // Delete the directory in case a previously copied file should no longer be in checker-qual + delete file('src') + } + from files('../checker-qual/src/main') + include '**/*.java' + exclude '**/SignednessUtilExtra.java' + into file('src/main') - // Not read only because "replaceAnnotations" tasks writes to the files. - fileMode(0666) - dirMode(0777) + // Not read only because "replaceAnnotations" tasks writes to the files. + fileMode(0666) + dirMode(0777) } sourcesJar.dependsOn(copySources) /** -* Types annotated with runtime annotations are always kept in the main dex by the default Android Gradle plugin. -* Using the standard Checker Framework annotations can lead to main dex overflows; -* users of the Checker Framework may find themselves unable to build their Android apps. -* By contrast, class-retention annotations are stripped out before packaging by all build systems as a convention. -*/ + * Types annotated with runtime annotations are always kept in the main dex by the default Android Gradle plugin. + * Using the standard Checker Framework annotations can lead to main dex overflows; + * users of the Checker Framework may find themselves unable to build their Android apps. + * By contrast, class-retention annotations are stripped out before packaging by all build systems as a convention. + */ task replaceAnnotations { - doLast { - fileTree(dir: 'src', include: '**/*.java').each { - it.text = it.text.replaceAll('RetentionPolicy.RUNTIME', 'RetentionPolicy.CLASS') - } + doLast { + fileTree(dir: 'src', include: '**/*.java').each { + it.text = it.text.replaceAll('RetentionPolicy.RUNTIME', 'RetentionPolicy.CLASS') } + } } replaceAnnotations.dependsOn copySources compileJava.dependsOn replaceAnnotations clean { - delete file('src') + delete file('src') } apply from: rootProject.file('gradle-mvn-push.gradle') /** Adds information to the publication for uploading to Maven repositories. */ final checkerQualAndroidPom(publication) { - sharedPublicationConfiguration(publication) - publication.from components.java - publication.pom { - name = 'Checker Qual Android' - description = 'checker-qual-android contains annotations (type qualifiers) that a programmer\n' + - 'writes to specify Java code for type-checking by the Checker Framework.\n' + - '\n' + - 'The checker-qual-android artifact is identical to the checker-qual\n' + - 'artifact, except that in checker-qual-android annotations have classfile\n' + - 'retention. The default Android Gradle plugin retains types annotated with\n' + - 'runtime annotations in the main dex, but strips out class-retention\n' + - 'annotations.\n' - licenses { - license { - name = 'The MIT License' - url = 'http://opensource.org/licenses/MIT' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + publication.from components.java + publication.pom { + name = 'Checker Qual Android' + description = 'checker-qual-android contains annotations (type qualifiers) that a programmer\n' + + 'writes to specify Java code for type-checking by the Checker Framework.\n' + + '\n' + + 'The checker-qual-android artifact is identical to the checker-qual\n' + + 'artifact, except that in checker-qual-android annotations have classfile\n' + + 'retention. The default Android Gradle plugin retains types annotated with\n' + + 'runtime annotations in the main dex, but strips out class-retention\n' + + 'annotations.\n' + licenses { + license { + name = 'The MIT License' + url = 'http://opensource.org/licenses/MIT' + distribution = 'repo' + } } + } } publishing { - publications { - checkerQualAndroid(MavenPublication) { - checkerQualAndroidPom it - } + publications { + checkerQualAndroid(MavenPublication) { + checkerQualAndroidPom it } + } } signing { - sign publishing.publications.checkerQualAndroid + sign publishing.publications.checkerQualAndroid } diff --git a/checker-qual/build.gradle b/checker-qual/build.gradle index 647394cff11..c0d04cdf804 100644 --- a/checker-qual/build.gradle +++ b/checker-qual/build.gradle @@ -1,54 +1,54 @@ buildscript { - repositories { - mavenCentral() - } - dependencies { - // Create OSGI bundles - classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:6.3.1' - // Don't add implementation dependencies; checker-qual.jar should have no dependencies. - } + repositories { + mavenCentral() + } + dependencies { + // Create OSGI bundles + classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:6.3.1' + // Don't add implementation dependencies; checker-qual.jar should have no dependencies. + } } plugins { - id 'java-library' + id 'java-library' } apply plugin: 'biz.aQute.bnd.builder' jar { - manifest { - attributes('Export-Package': '*') - } + manifest { + attributes('Export-Package': '*') + } } apply from: rootProject.file('gradle-mvn-push.gradle') /** Adds information to the publication for uploading to Maven repositories. */ final checkerQualPom(publication) { - sharedPublicationConfiguration(publication) - publication.from components.java - publication.pom { - name = 'Checker Qual' - description = 'checker-qual contains annotations (type qualifiers) that a programmer\n' + - 'writes to specify Java code for type-checking by the Checker Framework.\n' - licenses { - license { - name = 'The MIT License' - url = 'http://opensource.org/licenses/MIT' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + publication.from components.java + publication.pom { + name = 'Checker Qual' + description = 'checker-qual contains annotations (type qualifiers) that a programmer\n' + + 'writes to specify Java code for type-checking by the Checker Framework.\n' + licenses { + license { + name = 'The MIT License' + url = 'http://opensource.org/licenses/MIT' + distribution = 'repo' + } } + } } publishing { - publications { - checkerQual(MavenPublication) { - checkerQualPom it - } + publications { + checkerQual(MavenPublication) { + checkerQualPom it } + } } signing { - sign publishing.publications.checkerQual + sign publishing.publications.checkerQual } diff --git a/checker-util/build.gradle b/checker-util/build.gradle index c1cde552659..f4f50518607 100644 --- a/checker-util/build.gradle +++ b/checker-util/build.gradle @@ -1,41 +1,41 @@ plugins { - id 'java-library' + id 'java-library' } dependencies { - api project(':checker-qual') - // Don't add implementation dependencies; checker-util.jar should have no dependencies. + api project(':checker-qual') + // Don't add implementation dependencies; checker-util.jar should have no dependencies. - testImplementation group: 'junit', name: 'junit', version: '4.13.2' + testImplementation group: 'junit', name: 'junit', version: '4.13.2' } apply from: rootProject.file('gradle-mvn-push.gradle') /** Adds information to the publication for uploading to Maven repositories. */ final checkerUtilPom(publication) { - sharedPublicationConfiguration(publication) - publication.from components.java - publication.pom { - name = 'Checker Util' - description = 'checker-util contains utility classes for programmers to use at run time.' - licenses { - license { - name = 'The MIT License' - url = 'http://opensource.org/licenses/MIT' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + publication.from components.java + publication.pom { + name = 'Checker Util' + description = 'checker-util contains utility classes for programmers to use at run time.' + licenses { + license { + name = 'The MIT License' + url = 'http://opensource.org/licenses/MIT' + distribution = 'repo' + } } + } } publishing { - publications { - checkerUtil(MavenPublication) { - checkerUtilPom it - } + publications { + checkerUtil(MavenPublication) { + checkerUtilPom it } + } } signing { - sign publishing.publications.checkerUtil + sign publishing.publications.checkerUtil } diff --git a/checker/build.gradle b/checker/build.gradle index 8b17079890a..0070bc41a91 100644 --- a/checker/build.gradle +++ b/checker/build.gradle @@ -1,21 +1,21 @@ plugins { - // https://github.com/n0mer/gradle-git-properties ; target is: generateGitProperties - id 'com.gorylenko.gradle-git-properties' version '2.4.1' + // https://github.com/n0mer/gradle-git-properties ; target is: generateGitProperties + id 'com.gorylenko.gradle-git-properties' version '2.4.1' } sourceSets { - main { - resources { - // Stub files, message.properties, etc. - srcDirs += ['src/main/java'] - } + main { + resources { + // Stub files, message.properties, etc. + srcDirs += ['src/main/java'] } - testannotations + } + testannotations } sourcesJar { - // The resources duplicate content from the src directory. - duplicatesStrategy = DuplicatesStrategy.EXCLUDE + // The resources duplicate content from the src directory. + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } configurations { @@ -27,51 +27,51 @@ configurations { } dependencies { - implementation project(':javacutil') - implementation project(':dataflow') - implementation project(':framework') - // 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 - implementation('org.checkerframework:annotation-file-utilities:*') { - exclude group: 'com.google.errorprone', module: 'javac' - } - implementation project(':checker-qual') - implementation project(':checker-util') - - // External dependencies: - // If you add an external dependency, you must shadow its packages. - // See the comment in ../build.gradle in the shadowJar block. - - // As of 2019-12-16, the version of reflection-util in the Annotation - // File Utilities takes priority over this version, in the fat jar - // file. :-( So update it and re-build it locally when updating this. - implementation "org.plumelib:reflection-util:${reflectionUtilVersion}" - implementation "org.plumelib:plume-util:${plumeUtilVersion}" - - // Dependencies added to "shadow" appear as dependencies in Maven Central. - shadow project(':checker-qual') - shadow project(':checker-util') - - // Called Methods Checker AutoValue + Lombok support - testImplementation 'com.google.auto.value:auto-value-annotations:1.7.4' - testImplementation 'com.google.auto.value:auto-value:1.7.4' - testImplementation 'com.ryanharter.auto.value:auto-value-parcel:0.2.9' - testImplementation 'org.projectlombok:lombok:1.18.24' - // Called Methods Checker support for detecting misuses of AWS APIs - testImplementation 'com.amazonaws:aws-java-sdk-ec2' - testImplementation 'com.amazonaws:aws-java-sdk-kms' - // The AWS SDK is used for testing the Called Methods Checker. - testImplementation platform('com.amazonaws:aws-java-sdk-bom:1.12.293') - // For the Resource Leak Checker's support for JavaEE. - testImplementation 'javax.servlet:javax.servlet-api:3.1.0' - // For the Resource Leak Checker's support for IOUtils. - testImplementation 'commons-io:commons-io:2.11.0' - - testImplementation group: 'junit', name: 'junit', version: '4.13.2' - testImplementation project(':framework-test') - testImplementation sourceSets.testannotations.output - - testannotationsImplementation project(':checker-qual') + implementation project(':javacutil') + implementation project(':dataflow') + implementation project(':framework') + // 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 + implementation('org.checkerframework:annotation-file-utilities:*') { + exclude group: 'com.google.errorprone', module: 'javac' + } + implementation project(':checker-qual') + implementation project(':checker-util') + + // External dependencies: + // If you add an external dependency, you must shadow its packages. + // See the comment in ../build.gradle in the shadowJar block. + + // As of 2019-12-16, the version of reflection-util in the Annotation + // File Utilities takes priority over this version, in the fat jar + // file. :-( So update it and re-build it locally when updating this. + implementation "org.plumelib:reflection-util:${reflectionUtilVersion}" + implementation "org.plumelib:plume-util:${plumeUtilVersion}" + + // Dependencies added to "shadow" appear as dependencies in Maven Central. + shadow project(':checker-qual') + shadow project(':checker-util') + + // Called Methods Checker AutoValue + Lombok support + testImplementation 'com.google.auto.value:auto-value-annotations:1.7.4' + testImplementation 'com.google.auto.value:auto-value:1.7.4' + testImplementation 'com.ryanharter.auto.value:auto-value-parcel:0.2.9' + testImplementation 'org.projectlombok:lombok:1.18.24' + // Called Methods Checker support for detecting misuses of AWS APIs + testImplementation 'com.amazonaws:aws-java-sdk-ec2' + testImplementation 'com.amazonaws:aws-java-sdk-kms' + // The AWS SDK is used for testing the Called Methods Checker. + testImplementation platform('com.amazonaws:aws-java-sdk-bom:1.12.293') + // For the Resource Leak Checker's support for JavaEE. + testImplementation 'javax.servlet:javax.servlet-api:3.1.0' + // For the Resource Leak Checker's support for IOUtils. + testImplementation 'commons-io:commons-io:2.11.0' + + testImplementation group: 'junit', name: 'junit', version: '4.13.2' + testImplementation project(':framework-test') + testImplementation sourceSets.testannotations.output + + testannotationsImplementation project(':checker-qual') } // It's not clear why this dependencies exists, but Gradle issues the following warning: @@ -85,296 +85,304 @@ dependencies { generateGitProperties.dependsOn(':installGitHooks') jar { - manifest { - attributes('Main-Class': 'org.checkerframework.framework.util.CheckerMain') - } + manifest { + attributes('Main-Class': 'org.checkerframework.framework.util.CheckerMain') + } } // checker.jar is copied to checker/dist/ when it is built by the shadowJar task. task copyJarsToDist(dependsOn: shadowJar, group: 'Build') { - description 'Builds or downloads jars required by CheckerMain and puts them in checker/dist/.' - dependsOn project(':checker-qual').tasks.jar - doLast { - def checkerQualJarFile = file(project(':checker-qual').tasks.getByName('jar').archivePath) - if (!checkerQualJarFile.exists()) { - throw new GradleException('File not found: ' + checkerQualJarFile) - } - copy { - from checkerQualJarFile - into "${projectDir}/dist" - rename { String fileName -> - // remove version number on checker-qual.jar - fileName.replace(fileName, 'checker-qual.jar') - } - } + description 'Builds or downloads jars required by CheckerMain and puts them in checker/dist/.' + dependsOn project(':checker-qual').tasks.jar + doLast { + def checkerQualJarFile = file(project(':checker-qual').tasks.getByName('jar').archivePath) + if (!checkerQualJarFile.exists()) { + throw new GradleException('File not found: ' + checkerQualJarFile) + } + copy { + from checkerQualJarFile + into "${projectDir}/dist" + rename { String fileName -> + // remove version number on checker-qual.jar + fileName.replace(fileName, 'checker-qual.jar') + } + } - def checkerUtilJarFile = file(project(':checker-util').tasks.getByName('jar').archivePath) - if (!checkerUtilJarFile.exists()) { - throw new GradleException('File not found: ' + checkerUtilJarFile) - } - copy { - from checkerUtilJarFile - into "${projectDir}/dist" - rename { String fileName -> - // remove version number on checker-util.jar - fileName.replace(fileName, 'checker-util.jar') - } - } + def checkerUtilJarFile = file(project(':checker-util').tasks.getByName('jar').archivePath) + if (!checkerUtilJarFile.exists()) { + throw new GradleException('File not found: ' + checkerUtilJarFile) + } + copy { + from checkerUtilJarFile + into "${projectDir}/dist" + rename { String fileName -> + // remove version number on checker-util.jar + fileName.replace(fileName, 'checker-util.jar') + } + } - copy { - from configurations.javacJar - into "${projectDir}/dist" - rename { String fileName -> - fileName.replace(fileName, 'javac.jar') - } - } + copy { + from configurations.javacJar + into "${projectDir}/dist" + rename { String fileName -> + fileName.replace(fileName, 'javac.jar') + } } + } } assemble.dependsOn copyJarsToDist task allSourcesJar(type: Jar, group: 'Build') { - description 'Creates a sources jar that includes sources for all Checker Framework classes in checker.jar' - destinationDirectory = file("${projectDir}/dist") - archiveFileName = 'checker-source.jar' - archiveClassifier = 'sources' - from (sourceSets.main.java, project(':framework').sourceSets.main.allJava, - project(':dataflow').sourceSets.main.allJava, project(':javacutil').sourceSets.main.allJava, - project(':checker-qual').sourceSets.main.allJava, project(':checker-util').sourceSets.main.allJava) + description 'Creates a sources jar that includes sources for all Checker Framework classes in checker.jar' + destinationDirectory = file("${projectDir}/dist") + archiveFileName = 'checker-source.jar' + archiveClassifier = 'sources' + from (sourceSets.main.java, project(':framework').sourceSets.main.allJava, + project(':dataflow').sourceSets.main.allJava, project(':javacutil').sourceSets.main.allJava, + project(':checker-qual').sourceSets.main.allJava, project(':checker-util').sourceSets.main.allJava) } task allJavadocJar(type: Jar, group: 'Build') { - description 'Creates javadoc jar including Javadoc for all of the Checker Framework' - dependsOn rootProject.tasks.allJavadoc - destinationDirectory = file("${projectDir}/dist") - archiveFileName = 'checker-javadoc.jar' - archiveClassifier = 'javadoc' - from rootProject.tasks.allJavadoc.destinationDir + description 'Creates javadoc jar including Javadoc for all of the Checker Framework' + dependsOn rootProject.tasks.allJavadoc + destinationDirectory = file("${projectDir}/dist") + archiveFileName = 'checker-javadoc.jar' + archiveClassifier = 'javadoc' + from rootProject.tasks.allJavadoc.destinationDir } // Shadowing Test Sources and Dependencies import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar task checkerJar(type: ShadowJar, dependsOn: compileJava, group: 'Build') { - description "Builds checker-${project.version}.jar with all dependencies except checker-qual and checker-util." - includeEmptyDirs = false - archivesBaseName = 'checker' - archiveClassifier = '' - - from shadowJar.source - configurations = shadowJar.configurations - // To see what files are incorporated into the shadow jar file: - // doLast { println sourceSets.main.runtimeClasspath.asPath } - manifest { - attributes('Main-Class': 'org.checkerframework.framework.util.CheckerMain') - } - exclude 'org/checkerframework/**/qual/*' - exclude 'org/checkerframework/checker/*/util/*' - relocators = shadowJar.getRelocators() + description "Builds checker-${project.version}.jar with all dependencies except checker-qual and checker-util." + includeEmptyDirs = false + archivesBaseName = 'checker' + archiveClassifier = '' + + from shadowJar.source + configurations = shadowJar.configurations + // To see what files are incorporated into the shadow jar file: + // doLast { println sourceSets.main.runtimeClasspath.asPath } + manifest { + attributes('Main-Class': 'org.checkerframework.framework.util.CheckerMain') + } + exclude 'org/checkerframework/**/qual/*' + exclude 'org/checkerframework/checker/*/util/*' + relocators = shadowJar.getRelocators() } jar { - dependsOn(checkerJar) - // Never build the skinny jar. - onlyIf {false} - archiveClassifier = 'skinny' + dependsOn(checkerJar) + // Never build the skinny jar. + onlyIf {false} + archiveClassifier = 'skinny' } shadowJar { - description 'Creates checker-VERSION-all.jar and copies it to dist/checker.jar.' - // To see what files are incorporated into the shadow jar file: - // doFirst { println sourceSets.main.runtimeClasspath.asPath } - doLast{ - copy { - from archiveFile.get() - into file("${projectDir}/dist") - rename 'checker.*', 'checker.jar' - } + description 'Creates checker-VERSION-all.jar and copies it to dist/checker.jar.' + // To see what files are incorporated into the shadow jar file: + // doFirst { println sourceSets.main.runtimeClasspath.asPath } + doLast{ + copy { + from archiveFile.get() + into file("${projectDir}/dist") + rename 'checker.*', 'checker.jar' } + } } artifacts { - // Don't add this here or else the Javadoc and the sources jar is built during the assemble task. - // archives allJavadocJar - // archives allSourcesJar - archives shadowJar - archives checkerJar + // Don't add this here or else the Javadoc and the sources jar is built during the assemble task. + // archives allJavadocJar + // archives allSourcesJar + archives shadowJar + archives checkerJar - fatJar(shadowJar) + fatJar(shadowJar) } clean { - delete "${projectDir}/dist" - delete 'tests/calledmethods-delomboked' - delete('tests/ainfer-testchecker/annotated') - delete('tests/ainfer-testchecker/inference-output') - delete('tests/ainfer-nullness/annotated') - delete('tests/ainfer-nullness/inference-output') - delete('tests/ainfer-index/annotated') - delete('tests/ainfer-index/inference-output') - delete('tests/ainfer-resourceleak/annotated') - delete('tests/ainfer-resourceleak/inference-output') + delete "${projectDir}/dist" + delete 'tests/calledmethods-delomboked' + delete('tests/ainfer-testchecker/annotated') + delete('tests/ainfer-testchecker/inference-output') + delete('tests/ainfer-nullness/annotated') + delete('tests/ainfer-nullness/inference-output') + delete('tests/ainfer-index/annotated') + delete('tests/ainfer-index/inference-output') + delete('tests/ainfer-resourceleak/annotated') + delete('tests/ainfer-resourceleak/inference-output') } // Add non-junit tests createCheckTypeTask(project.name, 'CompilerMessages', 'org.checkerframework.checker.compilermsgs.CompilerMessagesChecker') checkCompilerMessages { - doFirst { - options.compilerArgs += [ - '-Apropfiles=' + sourceSets.main.resources.filter { file -> file.name.equals('messages.properties') }.asPath + File.pathSeparator - + project(':framework').sourceSets.main.resources.filter { file -> file.name.equals('messages.properties') }.asPath - ] - } + doFirst { + options.compilerArgs += [ + '-Apropfiles=' + sourceSets.main.resources.filter { file -> file.name.equals('messages.properties') }.asPath + File.pathSeparator + + project(':framework').sourceSets.main.resources.filter { file -> file.name.equals('messages.properties') }.asPath + ] + } } task nullnessExtraTests(type: Exec, dependsOn: copyJarsToDist, group: 'Verification') { - description 'Run extra tests for the Nullness Checker.' - executable 'make' - environment JAVAC: "${projectDir}/bin/javac", JAVAP: 'javap' - args = ['-C', 'tests/nullness-extra/'] + description 'Run extra tests for the Nullness Checker.' + executable 'make' + environment JAVAC: "${projectDir}/bin/javac", JAVAP: 'javap' + args = ['-C', 'tests/nullness-extra/'] } task commandLineTests(type: Exec, dependsOn: copyJarsToDist, group: 'Verification') { - description 'Run tests that need a special command line.' - executable 'make' - environment JAVAC: "${projectDir}/bin/javac" - args = ['-C', 'tests/command-line/'] + description 'Run tests that need a special command line.' + executable 'make' + environment JAVAC: "${projectDir}/bin/javac" + args = ['-C', 'tests/command-line/'] } task tutorialTests(dependsOn: copyJarsToDist, group: 'Verification') { - description 'Test that the tutorial is working as expected.' - doLast { - ant.ant(dir: "${rootDir}/docs/tutorial/tests", useNativeBasedir: 'true', inheritAll: 'false') { - target(name: 'check-tutorial') - } + description 'Test that the tutorial is working as expected.' + doLast { + ant.ant(dir: "${rootDir}/docs/tutorial/tests", useNativeBasedir: 'true', inheritAll: 'false') { + target(name: 'check-tutorial') } + } } task exampleTests(type: Exec, dependsOn: copyJarsToDist, group: 'Verification') { - description 'Run tests for the example programs.' - executable 'make' - environment JAVAC: "${projectDir}/bin/javac" - args = ['-C', '../docs/examples'] + description 'Run tests for the example programs.' + executable 'make' + environment JAVAC: "${projectDir}/bin/javac" + args = ['-C', '../docs/examples'] } task demosTests(dependsOn: copyJarsToDist, group: 'Verification') { - description 'Test that the demos are working as expected.' - doLast { - if (JavaVersion.current() == JavaVersion.VERSION_1_8) { - File demosDir = new File(projectDir, '../../checker-framework.demos'); - if (!demosDir.exists()) { - exec { - workingDir file(demosDir.toString() + '/../') - executable 'git' - args = ['clone', '--depth', '1', 'https://github.com/typetools/checker-framework.demos.git'] - } - } else { - exec { - workingDir demosDir - executable 'git' - args = ['pull', 'https://github.com/typetools/checker-framework.demos.git'] - ignoreExitValue = true - } - } - ant.properties.put('checker.lib', file("${projectDir}/dist/checker.jar").absolutePath) - ant.ant(dir: demosDir.toString()) - } else { - println('Skipping demosTests because they only work with Java 8.') + description 'Test that the demos are working as expected.' + doLast { + if (JavaVersion.current() == JavaVersion.VERSION_1_8) { + File demosDir = new File(projectDir, '../../checker-framework.demos'); + if (!demosDir.exists()) { + exec { + workingDir file(demosDir.toString() + '/../') + executable 'git' + args = [ + 'clone', + '--depth', + '1', + 'https://github.com/typetools/checker-framework.demos.git' + ] } + } else { + exec { + workingDir demosDir + executable 'git' + args = [ + 'pull', + 'https://github.com/typetools/checker-framework.demos.git' + ] + ignoreExitValue = true + } + } + ant.properties.put('checker.lib', file("${projectDir}/dist/checker.jar").absolutePath) + ant.ant(dir: demosDir.toString()) + } else { + println('Skipping demosTests because they only work with Java 8.') } + } } task allNullnessTests(type: Test, group: 'Verification') { - description 'Run all Junit tests for the Nullness Checker.' - include '**/Nullness*.class' + description 'Run all Junit tests for the Nullness Checker.' + include '**/Nullness*.class' } task allCalledMethodsTests(type: Test, group: 'Verification') { - description 'Run all Junit tests for the Called Methods Checker.' - include '**/CalledMethods*.class' - if (!skipDelombok) { - dependsOn 'delombok' - } + description 'Run all Junit tests for the Called Methods Checker.' + include '**/CalledMethods*.class' + if (!skipDelombok) { + dependsOn 'delombok' + } } // These are tests that should only be run with JDK 11+. task jtregJdk11Tests(group: 'Verification') { - description 'Run the jtreg tests made for JDK 11+.' - dependsOn('compileJava') - dependsOn('compileTestJava') - dependsOn('shadowJar') - - String jtregOutput = "${buildDir}/jtregJdk11" - String name = 'all' - doLast { - if (isJava8) { - println 'This test is only run with JDK 11+.' - return; - } - exec { - executable 'jtreg' - args = [ - "-dir:${projectDir}/jtregJdk11", - "-workDir:${jtregOutput}/${name}/work", - "-reportDir:${jtregOutput}/${name}/report", - '-verbose:summary', - '-javacoptions:-g', - '-keywords:!ignore', - '-samevm', - "-javacoptions:-classpath ${tasks.shadowJar.archiveFile.get()}:${sourceSets.test.output.asPath}", - "-vmoptions:-classpath ${tasks.shadowJar.archiveFile.get()}:${sourceSets.test.output.asPath}", - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - "-javacoptions:-classpath ${sourceSets.testannotations.output.asPath}", - // Location of jtreg tests - '.' - ] - } + description 'Run the jtreg tests made for JDK 11+.' + dependsOn('compileJava') + dependsOn('compileTestJava') + dependsOn('shadowJar') + + String jtregOutput = "${buildDir}/jtregJdk11" + String name = 'all' + doLast { + if (isJava8) { + println 'This test is only run with JDK 11+.' + return; + } + exec { + executable 'jtreg' + args = [ + "-dir:${projectDir}/jtregJdk11", + "-workDir:${jtregOutput}/${name}/work", + "-reportDir:${jtregOutput}/${name}/report", + '-verbose:summary', + '-javacoptions:-g', + '-keywords:!ignore', + '-samevm', + "-javacoptions:-classpath ${tasks.shadowJar.archiveFile.get()}:${sourceSets.test.output.asPath}", + "-vmoptions:-classpath ${tasks.shadowJar.archiveFile.get()}:${sourceSets.test.output.asPath}", + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + "-javacoptions:-classpath ${sourceSets.testannotations.output.asPath}", + // Location of jtreg tests + '.' + ] + } - } + } } // JSpecify tests are excluded by default. To run them: // ./gradlew NullnessJSpecifySamplesTest test { - exclude '**/org/checkerframework/checker/test/junit/NullnessJSpecifySamplesTest.class' + exclude '**/org/checkerframework/checker/test/junit/NullnessJSpecifySamplesTest.class' } task delombok { - description 'Delomboks the source code tree in tests/calledmethods-lombok' + description 'Delomboks the source code tree in tests/calledmethods-lombok' - def srcDelomboked = 'tests/calledmethods-delomboked' - def srcJava = 'tests/calledmethods-lombok' + def srcDelomboked = 'tests/calledmethods-delomboked' + def srcJava = 'tests/calledmethods-lombok' - inputs.files file(srcJava) - outputs.dir file(srcDelomboked) + inputs.files file(srcJava) + outputs.dir file(srcDelomboked) - // Because there are Checker Framework annotations in the test source. - dependsOn project(':checker-qual').tasks.jar + // Because there are Checker Framework annotations in the test source. + dependsOn project(':checker-qual').tasks.jar - doLast { - if(!skipDelombok) { - 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) - } + doLast { + if(!skipDelombok) { + 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) } + } } if (skipDelombok) { - delombok.enabled = false + delombok.enabled = false } else { - tasks.test.dependsOn('delombok') + tasks.test.dependsOn('delombok') } /// @@ -382,131 +390,131 @@ if (skipDelombok) { /// test { - useJUnit { - // These are run in task ainferTest. - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferTestCheckerJaifsTest' - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferTestCheckerStubsTest' - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferTestCheckerAjavaTest' - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferNullnessJaifsTest' - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferNullnessAjavaTest' - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferIndexAjavaTest' - excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferResourceLeakAjavaTest' - } + useJUnit { + // These are run in task ainferTest. + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferTestCheckerJaifsTest' + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferTestCheckerStubsTest' + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferTestCheckerAjavaTest' + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferNullnessJaifsTest' + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferNullnessAjavaTest' + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferIndexAjavaTest' + excludeCategories 'org.checkerframework.checker.test.junit.ainferrunners.AinferResourceLeakAjavaTest' + } } task ainferTestCheckerGenerateStubs(type: Test) { - description 'Internal task. Users should run ainferTestCheckerStubTest instead. This type-checks the ainfer-testchecker files with -Ainfer=stubs to generate stub files.' + description 'Internal task. Users should run ainferTestCheckerStubTest instead. This type-checks the ainfer-testchecker files with -Ainfer=stubs to generate stub files.' - dependsOn(compileTestJava) - doFirst { - delete('tests/ainfer-testchecker/annotated') - delete("${buildDir}/ainfer-testchecker/") - } + dependsOn(compileTestJava) + doFirst { + delete('tests/ainfer-testchecker/annotated') + delete("${buildDir}/ainfer-testchecker/") + } + outputs.upToDateWhen { false } + include '**/AinferTestCheckerStubsTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferTestCheckerStubsTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-testchecker') - // The stub file format doesn't support annotations on anonymous inner classes, so - // this test also expects errors on these tests that expect annotations to be inferred - // inside anonymous classes. - delete('tests/ainfer-testchecker/annotated/UsesAnonymous.java') - delete('tests/ainfer-testchecker/annotated/AnonymousClassWithField.java') - - // This test causes an error when its corresponding stub file is read, because the test - // contains an annotation definition. The stub file parser does not support reading - // files that define annotations; this test can be reinstated if the stub parser - // is extended to support annotation definitions. - delete('tests/ainfer-testchecker/annotated/all-systems/Issue4083.java') - - copy { - from file('tests/ainfer-testchecker/non-annotated/UsesAnonymous.java') - into file('tests/ainfer-testchecker/annotated') - } + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-testchecker') + // The stub file format doesn't support annotations on anonymous inner classes, so + // this test also expects errors on these tests that expect annotations to be inferred + // inside anonymous classes. + delete('tests/ainfer-testchecker/annotated/UsesAnonymous.java') + delete('tests/ainfer-testchecker/annotated/AnonymousClassWithField.java') + + // This test causes an error when its corresponding stub file is read, because the test + // contains an annotation definition. The stub file parser does not support reading + // files that define annotations; this test can be reinstated if the stub parser + // is extended to support annotation definitions. + delete('tests/ainfer-testchecker/annotated/all-systems/Issue4083.java') + + copy { + from file('tests/ainfer-testchecker/non-annotated/UsesAnonymous.java') + into file('tests/ainfer-testchecker/annotated') } + } } task ainferTestCheckerValidateStubs(type: Test) { - description 'Internal task. Users should run ainferTestCheckerStubTest instead. This type-checks the ainfer-testchecker tests using the stub files generated by ainferTestCheckerGenerateStubs.' + description 'Internal task. Users should run ainferTestCheckerStubTest instead. This type-checks the ainfer-testchecker tests using the stub files generated by ainferTestCheckerGenerateStubs.' - dependsOn(ainferTestCheckerGenerateStubs) + dependsOn(ainferTestCheckerGenerateStubs) + outputs.upToDateWhen { false } + include '**/AinferTestCheckerStubsValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferTestCheckerStubsValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } task ainferTestCheckerGenerateAjava(type: Test) { - description 'Internal task. Users should run ainferTestCheckerAjavaTest instead. This type-checks the ainfer-testchecker files with -Ainfer=ajava to generate ajava files.' + description 'Internal task. Users should run ainferTestCheckerAjavaTest instead. This type-checks the ainfer-testchecker files with -Ainfer=ajava to generate ajava files.' - dependsOn(compileTestJava) - doFirst { - delete('tests/ainfer-testchecker/annotated') - delete("${buildDir}/ainfer-testchecker/") - } + dependsOn(compileTestJava) + doFirst { + delete('tests/ainfer-testchecker/annotated') + delete("${buildDir}/ainfer-testchecker/") + } + outputs.upToDateWhen { false } + include '**/AinferTestCheckerAjavaTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferTestCheckerAjavaTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-testchecker') - - // AinferTestCheckerAjavaValidationTest fails with "warning: (purity.methodref)", whenever - // there is a user-defined generic interface, and a variable of that type is assigned a - // method reference. - delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/Issue946.java') - delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/Receivers.java') - - // This test must be deleted, because otherwise an error about a missing type in an - // ajava file is issued. The test itself shouldn't be run as an all-systems test while testing - // WPI; see the copy in the non-annotated WPI tests for an explanation. - delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/Purity.java') - - // There is some kind of bad interaction between the purity checker's inference mode - // and method references to constructors: every one of them in this test causes a - // purity.methodref warning during validation. This problem only occurs for ajava-based - // inference because the relevant purity annotations that seem to trigger it are on - // inner classes, which stubs cannot annotate. - // TODO: investigate the cause of this error in the Purity checker, fix it, and then reinstate this test. - delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/MemberReferences.java') - } + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-testchecker') + + // AinferTestCheckerAjavaValidationTest fails with "warning: (purity.methodref)", whenever + // there is a user-defined generic interface, and a variable of that type is assigned a + // method reference. + delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/Issue946.java') + delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/Receivers.java') + + // This test must be deleted, because otherwise an error about a missing type in an + // ajava file is issued. The test itself shouldn't be run as an all-systems test while testing + // WPI; see the copy in the non-annotated WPI tests for an explanation. + delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/Purity.java') + + // There is some kind of bad interaction between the purity checker's inference mode + // and method references to constructors: every one of them in this test causes a + // purity.methodref warning during validation. This problem only occurs for ajava-based + // inference because the relevant purity annotations that seem to trigger it are on + // inner classes, which stubs cannot annotate. + // TODO: investigate the cause of this error in the Purity checker, fix it, and then reinstate this test. + delete('tests/ainfer-testchecker/annotated/all-systems/java8/memberref/MemberReferences.java') + } } task ainferTestCheckerValidateAjava(type: Test) { - description 'Internal task. Users should run ainferTestCheckerAjavaTest instead. This re-type-checks the ainfer-testchecker files using the ajava files generated by ainferTestCheckerGenerateAjava' + description 'Internal task. Users should run ainferTestCheckerAjavaTest instead. This re-type-checks the ainfer-testchecker files using the ajava files generated by ainferTestCheckerGenerateAjava' - dependsOn(ainferTestCheckerGenerateAjava) + dependsOn(ainferTestCheckerGenerateAjava) + outputs.upToDateWhen { false } + include '**/AinferTestCheckerAjavaValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferTestCheckerAjavaValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } // Copies directories as needed by WPI tests. @@ -515,543 +523,549 @@ task ainferTestCheckerValidateAjava(type: Test) { // 1. Copies whole-program inference test source code from the non-annotated/ to the annotated/ directory. // 2. Copies WPI output, such as .jaif or .stub files, to the inferference-output/ directory. void copyNonannotatedToAnnotatedDirectory(String testdir) { - // Copying all test files to another directory, removing all expected errors that should not - // occur after inserting inferred annotations from .jaif files. - copy { - from files("tests/${testdir}/non-annotated") - into file("tests/${testdir}/annotated") - filter { String line -> - line.contains('// :: error:') - // Don't remove unchecked cast warnings, because they're genuinely expected in some all-systems - // tests, such as GenericsCasts.java. - || (line.contains('// :: warning:') && !line.contains('// :: warning: [unchecked]')) - ? null : line - } - } - // The only file for which expected errors are maintained is ExpectedErrors.java, so we copy it over. - delete("tests/${testdir}/annotated/ExpectedErrors.java") - copy { - from file("tests/${testdir}/non-annotated/ExpectedErrors.java") - into file("tests/${testdir}/annotated") + // Copying all test files to another directory, removing all expected errors that should not + // occur after inserting inferred annotations from .jaif files. + copy { + from files("tests/${testdir}/non-annotated") + into file("tests/${testdir}/annotated") + filter { String line -> + (line.contains('// :: error:') + // Don't remove unchecked cast warnings, because they're genuinely expected in some all-systems + // tests, such as GenericsCasts.java. + || (line.contains('// :: warning:') && !line.contains('// :: warning: [unchecked]'))) + ? null : line } + } + // The only file for which expected errors are maintained is ExpectedErrors.java, so we copy it over. + delete("tests/${testdir}/annotated/ExpectedErrors.java") + copy { + from file("tests/${testdir}/non-annotated/ExpectedErrors.java") + into file("tests/${testdir}/annotated") + } - delete("tests/${testdir}/inference-output") - file('build/whole-program-inference').renameTo(file("tests/${testdir}/inference-output")) + delete("tests/${testdir}/inference-output") + file('build/whole-program-inference').renameTo(file("tests/${testdir}/inference-output")) } // This task is similar to the ainferTestCheckerJaifTest task below, but it doesn't // run the insert-annotations-to-source tool. Instead, it tests the -Ainfer=stubs feature // and the -AmergeStubsWithSource feature to do WPI using stub files. task ainferTestCheckerStubTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using stub files' - dependsOn(ainferTestCheckerValidateStubs) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using stub files' + dependsOn(ainferTestCheckerValidateStubs) + outputs.upToDateWhen { false } } // Like ainferTestCheckerStubTest, but with ajava files instead task ainferTestCheckerAjavaTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using ajava files' - dependsOn(ainferTestCheckerValidateAjava) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using ajava files' + dependsOn(ainferTestCheckerValidateAjava) + outputs.upToDateWhen { false } } task ainferTestCheckerGenerateJaifs(type: Test) { - description 'Internal task. Users should run ainferTestCheckerJaifTest instead. This type-checks the ainfer-testchecker files with -Ainfer=jaifs to generate .jaif files' + description 'Internal task. Users should run ainferTestCheckerJaifTest instead. This type-checks the ainfer-testchecker files with -Ainfer=jaifs to generate .jaif files' - dependsOn(compileTestJava) - dependsOn(':checker-qual:jar') // For the Value Checker annotations. - doFirst { - delete('tests/ainfer-testchecker/annotated') - } + dependsOn(compileTestJava) + dependsOn(':checker-qual:jar') // For the Value Checker annotations. + doFirst { + delete('tests/ainfer-testchecker/annotated') + } + outputs.upToDateWhen { false } + include '**/AinferTestCheckerJaifsTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferTestCheckerJaifsTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-testchecker') - - // JAIF-based WPI fails these tests, which were added for stub-based WPI. - // See issue here: https://github.com/typetools/checker-framework/issues/3009 - delete('tests/ainfer-testchecker/annotated/ConflictingAnnotationsTest.java') - delete('tests/ainfer-testchecker/annotated/MultiDimensionalArrays.java') - - // JAIF-based WPI also fails this test. It used to pass, but the test was changed - // in a way that exposed a bug in the Annotation File Utilities: the AFU - // places annotations incorrectly on qualified types. In this test, a failure occurs because - // the AFU prints "@Annotation Outer.Inner this", rather than "Outer.@Annotation Inner this" - // (see an explanation of the syntax here: - // https://checkerframework.org/manual/#common-problems-non-typechecking). - // TODO: fix this bug in the AFU, then reinstate this test. - delete('tests/ainfer-testchecker/annotated/OverriddenMethodsTest.java') - - // Inserting annotations from .jaif files in-place. - String jaifsDir = 'tests/ainfer-testchecker/inference-output'; - List jaifs = fileTree(jaifsDir).matching { - include '*.jaif' - }.asList() - if (jaifs.isEmpty()) { - throw new GradleException("no .jaif files found in ${jaifsDir}") - } - String javasDir = 'tests/ainfer-testchecker/annotated/'; - List javas = fileTree(javasDir).matching { - include '*.java' - }.asList() - if (javas.isEmpty()) { - throw new GradleException("no .java files found in ${javasDir}") - } - exec { - executable "${afu}/scripts/insert-annotations-to-source" - // Script argument -cp must precede Java program argument -i. - // checker-qual is needed for Constant Value Checker annotations. - // Note that "/" works on Windows as well as on Linux. - args = ['-cp', "${sourceSets.test.output.asPath}:${project(':checker-qual').tasks.jar.archivePath}:" + file('tests/build/testclasses')] - args += ['-i'] - for (File jaif : jaifs) { - args += [jaif.toString()] - } - for (File javaFile : javas) { - args += [javaFile.toString()] - } - } + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-testchecker') + + // JAIF-based WPI fails these tests, which were added for stub-based WPI. + // See issue here: https://github.com/typetools/checker-framework/issues/3009 + delete('tests/ainfer-testchecker/annotated/ConflictingAnnotationsTest.java') + delete('tests/ainfer-testchecker/annotated/MultiDimensionalArrays.java') + + // JAIF-based WPI also fails this test. It used to pass, but the test was changed + // in a way that exposed a bug in the Annotation File Utilities: the AFU + // places annotations incorrectly on qualified types. In this test, a failure occurs because + // the AFU prints "@Annotation Outer.Inner this", rather than "Outer.@Annotation Inner this" + // (see an explanation of the syntax here: + // https://checkerframework.org/manual/#common-problems-non-typechecking). + // TODO: fix this bug in the AFU, then reinstate this test. + delete('tests/ainfer-testchecker/annotated/OverriddenMethodsTest.java') + + // Inserting annotations from .jaif files in-place. + String jaifsDir = 'tests/ainfer-testchecker/inference-output'; + List jaifs = fileTree(jaifsDir).matching { + include '*.jaif' + }.asList() + if (jaifs.isEmpty()) { + throw new GradleException("no .jaif files found in ${jaifsDir}") + } + String javasDir = 'tests/ainfer-testchecker/annotated/'; + List javas = fileTree(javasDir).matching { + include '*.java' + }.asList() + if (javas.isEmpty()) { + throw new GradleException("no .java files found in ${javasDir}") + } + exec { + executable "${afu}/scripts/insert-annotations-to-source" + // Script argument -cp must precede Java program argument -i. + // checker-qual is needed for Constant Value Checker annotations. + // Note that "/" works on Windows as well as on Linux. + args = [ + '-cp', + "${sourceSets.test.output.asPath}:${project(':checker-qual').tasks.jar.archivePath}:" + file('tests/build/testclasses') + ] + args += ['-i'] + for (File jaif : jaifs) { + args += [jaif.toString()] + } + for (File javaFile : javas) { + args += [javaFile.toString()] + } } + } } task ainferTestCheckerValidateJaifs(type: Test) { - description 'Internal task. Users should run ainferTestCheckerJaifTest instead. This type-checks the ainfer-testchecker files using the .jaif files generated by ainferTestCheckerGenerateJaifs' + description 'Internal task. Users should run ainferTestCheckerJaifTest instead. This type-checks the ainfer-testchecker files using the .jaif files generated by ainferTestCheckerGenerateJaifs' - dependsOn(ainferTestCheckerGenerateJaifs) + dependsOn(ainferTestCheckerGenerateJaifs) + outputs.upToDateWhen { false } + include '**/AinferTestCheckerJaifsValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferTestCheckerJaifsValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } task ainferTestCheckerJaifTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using .jaif files' - dependsOn(ainferTestCheckerValidateJaifs) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using .jaif files' + dependsOn(ainferTestCheckerValidateJaifs) + outputs.upToDateWhen { false } } task ainferIndexGenerateAjava(type: Test) { - description 'Internal task. Users should run ainferIndexAjavaTest instead. This type-checks the ainfer-index files with -Ainfer=ajava to generate ajava files.' + description 'Internal task. Users should run ainferIndexAjavaTest instead. This type-checks the ainfer-index files with -Ainfer=ajava to generate ajava files.' - dependsOn(compileTestJava) - doFirst { - delete('tests/ainfer-index/annotated') - delete("${buildDir}/ainfer-index/") - } + dependsOn(compileTestJava) + doFirst { + delete('tests/ainfer-index/annotated') + delete("${buildDir}/ainfer-index/") + } + outputs.upToDateWhen { false } + include '**/AinferIndexAjavaTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferIndexAjavaTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-index') - } + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-index') + } } task ainferIndexValidateAjava(type: Test) { - description 'Internal task. Users should run ainferIndexAjavaTest instead. This re-type-checks the ainfer-index files using the ajava files generated by ainferIndexGenerateAjava' + description 'Internal task. Users should run ainferIndexAjavaTest instead. This re-type-checks the ainfer-index files using the ajava files generated by ainferIndexGenerateAjava' - dependsOn(ainferIndexGenerateAjava) + dependsOn(ainferIndexGenerateAjava) + outputs.upToDateWhen { false } + include '**/AinferIndexAjavaValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferIndexAjavaValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } task ainferIndexAjavaTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using ajava files and the Index Checker' - dependsOn(ainferIndexValidateAjava) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using ajava files and the Index Checker' + dependsOn(ainferIndexValidateAjava) + outputs.upToDateWhen { false } } task ainferNullnessGenerateAjava(type: Test) { - description 'Internal task. Users should run ainferNullnessAjavaTest instead. This type-checks the ainfer-nullness files with -Ainfer=ajava to generate ajava files.' + description 'Internal task. Users should run ainferNullnessAjavaTest instead. This type-checks the ainfer-nullness files with -Ainfer=ajava to generate ajava files.' - dependsOn(compileTestJava) - doFirst { - delete('tests/ainfer-nullness/annotated') - delete("${buildDir}/ainfer-nullness/") - } + dependsOn(compileTestJava) + doFirst { + delete('tests/ainfer-nullness/annotated') + delete("${buildDir}/ainfer-nullness/") + } + outputs.upToDateWhen { false } + include '**/AinferNullnessAjavaTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferNullnessAjavaTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-nullness') - } + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-nullness') + } } task ainferNullnessValidateAjava(type: Test) { - description 'Internal task. Users should run ainferNullnessAjavaTest instead. This re-type-checks the ainfer-nullness files using the ajava files generated by ainferNullnessGenerateAjava' + description 'Internal task. Users should run ainferNullnessAjavaTest instead. This re-type-checks the ainfer-nullness files using the ajava files generated by ainferNullnessGenerateAjava' - dependsOn(ainferNullnessGenerateAjava) + dependsOn(ainferNullnessGenerateAjava) + outputs.upToDateWhen { false } + include '**/AinferNullnessAjavaValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferNullnessAjavaValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } task ainferNullnessAjavaTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using ajava files and the Nullness Checker' - dependsOn(ainferNullnessValidateAjava) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using ajava files and the Nullness Checker' + dependsOn(ainferNullnessValidateAjava) + outputs.upToDateWhen { false } } task ainferResourceLeakGenerateAjava(type: Test) { - description 'Internal task. Users should run ainferResourceLeakAjavaTest instead. This type-checks the ainfer-index files with -Ainfer=ajava to generate ajava files.' + description 'Internal task. Users should run ainferResourceLeakAjavaTest instead. This type-checks the ainfer-index files with -Ainfer=ajava to generate ajava files.' - dependsOn(compileTestJava) - doFirst { - delete('tests/ainfer-resourceleak/annotated') - delete("${buildDir}/ainfer-resourceleak/") - } + dependsOn(compileTestJava) + doFirst { + delete('tests/ainfer-resourceleak/annotated') + delete("${buildDir}/ainfer-resourceleak/") + } + outputs.upToDateWhen { false } + include '**/AinferResourceLeakAjavaTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferResourceLeakAjavaTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-resourceleak') - } + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-resourceleak') + } } task ainferResourceLeakValidateAjava(type: Test) { - description 'Internal task. Users should run ainferResourceLeakAjavaTest instead. This re-type-checks the ainfer-resourceleak files using the ajava files generated by ainferResourceLeakGenerateAjava' + description 'Internal task. Users should run ainferResourceLeakAjavaTest instead. This re-type-checks the ainfer-resourceleak files using the ajava files generated by ainferResourceLeakGenerateAjava' - dependsOn(ainferResourceLeakGenerateAjava) + dependsOn(ainferResourceLeakGenerateAjava) + outputs.upToDateWhen { false } + include '**/AinferResourceLeakAjavaValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferResourceLeakAjavaValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and the expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } task ainferResourceLeakAjavaTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using ajava files and the Resource Leak Checker' - dependsOn(ainferResourceLeakValidateAjava) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using ajava files and the Resource Leak Checker' + dependsOn(ainferResourceLeakValidateAjava) + outputs.upToDateWhen { false } } task ainferNullnessGenerateJaifs(type: Test) { - description 'Internal task. Users should run ainferNullnessJaifTest instead. This type-checks the ainfer-nullness files with -Ainfer=jaifs to generate .jaif files' + description 'Internal task. Users should run ainferNullnessJaifTest instead. This type-checks the ainfer-nullness files with -Ainfer=jaifs to generate .jaif files' - dependsOn(compileTestJava) - doFirst { - delete('tests/ainfer-nullness/annotated') - } + dependsOn(compileTestJava) + doFirst { + delete('tests/ainfer-nullness/annotated') + } + outputs.upToDateWhen { false } + include '**/AinferNullnessJaifsTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferNullnessJaifsTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } - doLast { - copyNonannotatedToAnnotatedDirectory('ainfer-nullness') - - // JAIF-based WPI fails these tests, which was added for stub-based WPI. - // See issue here: https://github.com/typetools/checker-framework/issues/3009 - delete('tests/ainfer-nullness/annotated/ConflictingAnnotationsTest.java') - delete('tests/ainfer-nullness/annotated/MultiDimensionalArrays.java') - - // Inserting annotations from .jaif files in-place. - String jaifsDir = 'tests/ainfer-nullness/inference-output'; - List jaifs = fileTree(jaifsDir).matching { - include '*.jaif' - }.asList() - if (jaifs.isEmpty()) { - throw new GradleException("no .jaif files found in ${jaifsDir}") - } - String javasDir = 'tests/ainfer-nullness/annotated/'; - List javas = fileTree(javasDir).matching { - include '*.java' - }.asList() - if (javas.isEmpty()) { - throw new GradleException("no .java files found in ${javasDir}") - } - exec { - executable "${afu}/scripts/insert-annotations-to-source" - // Script argument -cp must precede Java program argument -i. - // Note that "/" works on Windows as well as on Linux. - args = ['-cp', "${sourceSets.test.output.asPath}:${project(':checker-qual').tasks.jar.archivePath}:" + file('tests/build/testclasses')] - args += ['-i'] - for (File jaif : jaifs) { - args += [jaif.toString()] - } - for (File javaFile : javas) { - args += [javaFile.toString()] - } - } + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } + + doLast { + copyNonannotatedToAnnotatedDirectory('ainfer-nullness') + + // JAIF-based WPI fails these tests, which was added for stub-based WPI. + // See issue here: https://github.com/typetools/checker-framework/issues/3009 + delete('tests/ainfer-nullness/annotated/ConflictingAnnotationsTest.java') + delete('tests/ainfer-nullness/annotated/MultiDimensionalArrays.java') + + // Inserting annotations from .jaif files in-place. + String jaifsDir = 'tests/ainfer-nullness/inference-output'; + List jaifs = fileTree(jaifsDir).matching { + include '*.jaif' + }.asList() + if (jaifs.isEmpty()) { + throw new GradleException("no .jaif files found in ${jaifsDir}") + } + String javasDir = 'tests/ainfer-nullness/annotated/'; + List javas = fileTree(javasDir).matching { + include '*.java' + }.asList() + if (javas.isEmpty()) { + throw new GradleException("no .java files found in ${javasDir}") + } + exec { + executable "${afu}/scripts/insert-annotations-to-source" + // Script argument -cp must precede Java program argument -i. + // Note that "/" works on Windows as well as on Linux. + args = [ + '-cp', + "${sourceSets.test.output.asPath}:${project(':checker-qual').tasks.jar.archivePath}:" + file('tests/build/testclasses') + ] + args += ['-i'] + for (File jaif : jaifs) { + args += [jaif.toString()] + } + for (File javaFile : javas) { + args += [javaFile.toString()] + } } + } } task ainferNullnessValidateJaifs(type: Test) { - description 'Internal task. Users should run ainferNullnessJaifTest instead. This re-type-checks the ainfer-nullness files using the .jaif files generated by ainferNullnessGenerateJaifs' + description 'Internal task. Users should run ainferNullnessJaifTest instead. This re-type-checks the ainfer-nullness files using the .jaif files generated by ainferNullnessGenerateJaifs' - dependsOn(ainferNullnessGenerateJaifs) + dependsOn(ainferNullnessGenerateJaifs) + outputs.upToDateWhen { false } + include '**/AinferNullnessJaifsValidationTest.class' + testLogging { + // Always run the tests outputs.upToDateWhen { false } - include '**/AinferNullnessJaifsValidationTest.class' - testLogging { - // Always run the tests - outputs.upToDateWhen { false } - - // Show the found unexpected diagnostics and expected diagnostics not found. - exceptionFormat 'full' - events 'passed', 'skipped', 'failed' - } + + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat 'full' + events 'passed', 'skipped', 'failed' + } } task ainferNullnessJaifTest(dependsOn: 'shadowJar', group: 'Verification') { - description 'Run tests for whole-program inference using .jaif files' - dependsOn(ainferNullnessValidateJaifs) - outputs.upToDateWhen { false } + description 'Run tests for whole-program inference using .jaif files' + dependsOn(ainferNullnessValidateJaifs) + outputs.upToDateWhen { false } } // Empty task that just runs both the jaif and stub WPI tests. // It is run as part of the inferenceTests task. task ainferTest(group: 'Verification') { - description 'Run tests for all whole program inference modes.' - dependsOn('ainferTestCheckerJaifTest') - dependsOn('ainferTestCheckerStubTest') - dependsOn('ainferTestCheckerAjavaTest') - dependsOn('ainferNullnessJaifTest') - dependsOn('ainferNullnessAjavaTest') - dependsOn('ainferIndexAjavaTest') - dependsOn('ainferResourceLeakAjavaTest') + description 'Run tests for all whole program inference modes.' + dependsOn('ainferTestCheckerJaifTest') + dependsOn('ainferTestCheckerStubTest') + dependsOn('ainferTestCheckerAjavaTest') + dependsOn('ainferNullnessJaifTest') + dependsOn('ainferNullnessAjavaTest') + dependsOn('ainferIndexAjavaTest') + dependsOn('ainferResourceLeakAjavaTest') } // This is run as part of the inferenceTests task. task wpiManyTest(group: 'Verification') { - description 'Tests the wpi-many.sh script (and indirectly the wpi.sh script). Requires an Internet connection.' - dependsOn(copyJarsToDist) - // This test must always be re-run when requested. - outputs.upToDateWhen { false } + description 'Tests the wpi-many.sh script (and indirectly the wpi.sh script). Requires an Internet connection.' + dependsOn(copyJarsToDist) + // This test must always be re-run when requested. + outputs.upToDateWhen { false } + + doFirst { + delete("${project.projectDir}/build/wpi-many-tests-results/") + // wpi-many.sh is run in skip mode so that logs are preserved, but + // we don't actually want to skip previously-failing tests when we + // re-run the tests locally. + delete fileTree("${project.projectDir}/build/wpi-many-tests") { + include '**/.cannot-run-wpi' + } + } - doFirst { - delete("${project.projectDir}/build/wpi-many-tests-results/") - // wpi-many.sh is run in skip mode so that logs are preserved, but - // we don't actually want to skip previously-failing tests when we - // re-run the tests locally. - delete fileTree("${project.projectDir}/build/wpi-many-tests") { - include '**/.cannot-run-wpi' + doLast { + // Run wpi-many.sh + def typecheckFilesDir = "${project.projectDir}/build/wpi-many-tests-results/" + try { + exec { + environment CHECKERFRAMEWORK: "${projectDir}/.." + commandLine 'bin/wpi-many.sh', + '-i', "${project.projectDir}/tests/wpi-many/testin.txt", + '-o', "${project.projectDir}/build/wpi-many-tests", + '-s', + '--', '--checker', 'nullness,interning,lock,regex,signature,calledmethods,resourceleak' + } + } catch (Exception e) { + println('Failure: Running wpi-many.sh failed with a non-zero exit code.') + File wpiOut = new File("${typecheckFilesDir}/wpi-out") + if (wpiOut.exists()) { + println("========= Output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") + exec { + commandLine 'cat', "${typecheckFilesDir}/wpi-out" } + println("========= End of output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") + throw e + } + } + // collect the logs from running WPI + def typecheckFiles = fileTree(typecheckFilesDir).matching { + include '**/*-typecheck.out' + } + def testinLines = file("${project.projectDir}/tests/wpi-many/testin.txt").text.readLines() + testinLines.removeIf { it.startsWith('#') } + def expectedTypecheckFileCount = testinLines.size() + def actualTypecheckFileCount = typecheckFiles.size() + if (actualTypecheckFileCount != expectedTypecheckFileCount) { + println("Failure: Too few *-typecheck.out files in ${typecheckFilesDir}: " + + "found ${actualTypecheckFileCount} but expected ${expectedTypecheckFileCount}.") + println("========= Found in ${typecheckFilesDir} ========") + exec { + commandLine 'ls', '-al', "${typecheckFilesDir}" + } + println("========= Expected in ${typecheckFilesDir} ========") + exec { + commandLine 'cat', "${project.projectDir}/tests/wpi-many/testin.txt" + } + println("========= Output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") + exec { + commandLine 'cat', "${typecheckFilesDir}/wpi-out" + } + println("========= End of output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") + def logFiles = fileTree(typecheckFilesDir).matching { + include '**/*.log' + } + logFiles.visit { FileVisitDetails details -> + def filename = "${typecheckFilesDir}" + details.getName() + println("======== printing contents of ${filename} ========") + details.getFile().eachLine { line -> println(line) } + println("======== end of contents of ${filename} ========") + } + // If any of these files are present, their contents should be an error + // message that might indicate what went wrong. Even their presenence, + // however, is intereseting (even if they are empty). + def cannotRunWpiFiles = fileTree(typecheckFilesDir).matching { + include '**/.cannot-run-wpi' + } + cannotRunWpiFiles.visit { FileVisitDetails details -> + def filename = "${typecheckFilesDir}" + details.getName() + println("======== printing contents of ${filename} ========") + details.getFile().eachLine { line -> println(line) } + println("======== end of contents of ${filename} ========") + } + throw new GradleException("Failure: Too few *-typecheck.out files in ${typecheckFilesDir}: " + + "found ${actualTypecheckFileCount} but expected ${expectedTypecheckFileCount}.") } - doLast { - // Run wpi-many.sh - def typecheckFilesDir = "${project.projectDir}/build/wpi-many-tests-results/" - try { - exec { - environment CHECKERFRAMEWORK: "${projectDir}/.." - commandLine 'bin/wpi-many.sh', - '-i', "${project.projectDir}/tests/wpi-many/testin.txt", - '-o', "${project.projectDir}/build/wpi-many-tests", - '-s', - '--', '--checker', 'nullness,interning,lock,regex,signature,calledmethods,resourceleak' - } - } catch (Exception e) { - println('Failure: Running wpi-many.sh failed with a non-zero exit code.') - File wpiOut = new File("${typecheckFilesDir}/wpi-out") - if (wpiOut.exists()) { - println("========= Output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") - exec { - commandLine 'cat', "${typecheckFilesDir}/wpi-out" - } - println("========= End of output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") - throw e - } - } - // collect the logs from running WPI - def typecheckFiles = fileTree(typecheckFilesDir).matching { - include '**/*-typecheck.out' - } - def testinLines = file("${project.projectDir}/tests/wpi-many/testin.txt").text.readLines() - testinLines.removeIf { it.startsWith('#') } - def expectedTypecheckFileCount = testinLines.size() - def actualTypecheckFileCount = typecheckFiles.size() - if (actualTypecheckFileCount != expectedTypecheckFileCount) { - println("Failure: Too few *-typecheck.out files in ${typecheckFilesDir}: " + - "found ${actualTypecheckFileCount} but expected ${expectedTypecheckFileCount}.") - println("========= Found in ${typecheckFilesDir} ========") - exec { - commandLine 'ls', '-al', "${typecheckFilesDir}" - } - println("========= Expected in ${typecheckFilesDir} ========") - exec { - commandLine 'cat', "${project.projectDir}/tests/wpi-many/testin.txt" - } - println("========= Output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") - exec { - commandLine 'cat', "${typecheckFilesDir}/wpi-out" - } - println("========= End of output from last run of wpi.sh (${typecheckFilesDir}/wpi-out): ========") - def logFiles = fileTree(typecheckFilesDir).matching { - include '**/*.log' - } - logFiles.visit { FileVisitDetails details -> - def filename = "${typecheckFilesDir}" + details.getName() - println("======== printing contents of ${filename} ========") - details.getFile().eachLine { line -> println(line) } - println("======== end of contents of ${filename} ========") - } - // If any of these files are present, their contents should be an error - // message that might indicate what went wrong. Even their presenence, - // however, is intereseting (even if they are empty). - def cannotRunWpiFiles = fileTree(typecheckFilesDir).matching { - include '**/.cannot-run-wpi' - } - cannotRunWpiFiles.visit { FileVisitDetails details -> - def filename = "${typecheckFilesDir}" + details.getName() - println("======== printing contents of ${filename} ========") - details.getFile().eachLine { line -> println(line) } - println("======== end of contents of ${filename} ========") - } - throw new GradleException("Failure: Too few *-typecheck.out files in ${typecheckFilesDir}: " + - "found ${actualTypecheckFileCount} but expected ${expectedTypecheckFileCount}.") + // check that WPI causes the expected builds to succeed + typecheckFiles.visit { FileVisitDetails details -> + def filename = "${project.projectDir}/build/wpi-many-tests-results/" + details.getName() + def file = details.getFile() + if (file.length() == 0) { + throw new GradleException('Failure: WPI produced empty typecheck file ' + filename) + } + file.eachLine { line -> + if ( + // Ignore the line that WPI echoes with the javac command being run. + line.startsWith('Running ') + // Warnings about bad path elements aren't related to WPI and are ignored. + || line.startsWith('warning: [path]') + // Ignore bootstrap classpath warning: + || line.startsWith('warning: [options] bootstrap') + // Ignore warnings about illegal access: + || line.contains('Option --illegal-access is deprecated') + // Ignore the warnings about --add-opens arguments to the JVM + || line.contains('warning: [options] --add-opens has no effect at compile time') + // Ignore the summary line that reports the total number of warnings (which can be single or plural). + || line.endsWith(' warning') + || line.endsWith(' warnings') + || line.startsWith('warning: No processor claimed any of these annotations: ')) { + return; } - - // check that WPI causes the expected builds to succeed - typecheckFiles.visit { FileVisitDetails details -> - def filename = "${project.projectDir}/build/wpi-many-tests-results/" + details.getName() - def file = details.getFile() - if (file.length() == 0) { - throw new GradleException('Failure: WPI produced empty typecheck file ' + filename) - } - file.eachLine { line -> - if ( - // Ignore the line that WPI echoes with the javac command being run. - line.startsWith('Running ') - // Warnings about bad path elements aren't related to WPI and are ignored. - || line.startsWith('warning: [path]') - // Ignore bootstrap classpath warning: - || line.startsWith('warning: [options] bootstrap') - // Ignore warnings about illegal access: - || line.contains('Option --illegal-access is deprecated') - // Ignore the warnings about --add-opens arguments to the JVM - || line.contains('warning: [options] --add-opens has no effect at compile time') - // Ignore the summary line that reports the total number of warnings (which can be single or plural). - || line.endsWith(' warning') - || line.endsWith(' warnings') - || line.startsWith('warning: No processor claimed any of these annotations: ')) { - return; - } - if (!line.trim().equals('')) { - println("======== printing contents of ${filename} ========") - details.getFile().eachLine { l -> println(l) } - println("======== end of contents of ${filename} ========") - throw new GradleException('Failure: WPI scripts produced an unexpected output in ' + filename + '. ' + - 'Failing line is the following: ' + line) - } - } + if (!line.trim().equals('')) { + println("======== printing contents of ${filename} ========") + details.getFile().eachLine { l -> println(l) } + println("======== end of contents of ${filename} ========") + throw new GradleException('Failure: WPI scripts produced an unexpected output in ' + filename + '. ' + + 'Failing line is the following: ' + line) } + } } + } } // This is run as part of the inferenceTests task. task wpiPlumeLibTest(group: 'Verification') { - description 'Tests whole-program inference on the plume-lib projects. Requires an Internet connection.' - dependsOn(copyJarsToDist) + description 'Tests whole-program inference on the plume-lib projects. Requires an Internet connection.' + dependsOn(copyJarsToDist) - // This test must always be re-run when requested. - outputs.upToDateWhen { false } + // This test must always be re-run when requested. + outputs.upToDateWhen { false } - doLast { - exec { - commandLine 'bin-devel/wpi-plumelib/test-wpi-plumelib.sh' - ignoreExitValue = false - } + doLast { + exec { + commandLine 'bin-devel/wpi-plumelib/test-wpi-plumelib.sh' + ignoreExitValue = false } + } } apply from: rootProject.file('gradle-mvn-push.gradle') /** Adds information to the publication for uploading to Maven repositories. */ final checkerPom(publication) { - sharedPublicationConfiguration(publication) - // Don't use publication.from components.java which would publish the skinny jar as checker.jar. - publication.pom { - name = 'Checker Framework' - description = 'The Checker Framework enhances Java\'s type system to\n' + - 'make it more powerful and useful. This lets software developers\n' + - 'detect and prevent errors in their Java programs.\n' + - 'The Checker Framework includes compiler plug-ins ("checkers")\n' + - 'that find bugs or verify their absence. It also permits you to\n' + - 'write your own compiler plug-ins.' - licenses { - license { - name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' - url = 'http://www.gnu.org/software/classpath/license.html' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + // Don't use publication.from components.java which would publish the skinny jar as checker.jar. + publication.pom { + name = 'Checker Framework' + description = 'The Checker Framework enhances Java\'s type system to\n' + + 'make it more powerful and useful. This lets software developers\n' + + 'detect and prevent errors in their Java programs.\n' + + 'The Checker Framework includes compiler plug-ins ("checkers")\n' + + 'that find bugs or verify their absence. It also permits you to\n' + + 'write your own compiler plug-ins.' + licenses { + license { + name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' + url = 'http://www.gnu.org/software/classpath/license.html' + distribution = 'repo' + } } + } } publishing { - publications { - checker(MavenPublication) { - project.shadow.component it - checkerPom it - artifact checkerJar - artifact allSourcesJar - artifact allJavadocJar - } + publications { + checker(MavenPublication) { + project.shadow.component it + checkerPom it + artifact checkerJar + artifact allSourcesJar + artifact allJavadocJar } + } } signing { - sign publishing.publications.checker + sign publishing.publications.checker } diff --git a/dataflow/build.gradle b/dataflow/build.gradle index cff1916fd52..d629a2dd72f 100644 --- a/dataflow/build.gradle +++ b/dataflow/build.gradle @@ -1,18 +1,18 @@ plugins { - id 'java-library' + id 'java-library' } dependencies { - api project(':javacutil') - api project(':checker-qual') + api project(':javacutil') + api project(':checker-qual') - // Node implements org.plumelib.util.UniqueId, so this dependency must be "api". - api "org.plumelib:plume-util:${plumeUtilVersion}" + // Node implements org.plumelib.util.UniqueId, so this dependency must be "api". + api "org.plumelib:plume-util:${plumeUtilVersion}" - // External dependencies: - // If you add an external dependency, you must shadow its packages both in the dataflow-shaded - // artifact (see shadowJar block below) and also in checker.jar (see the comment in - // ../build.gradle in the shadowJar block). + // External dependencies: + // If you add an external dependency, you must shadow its packages both in the dataflow-shaded + // artifact (see shadowJar block below) and also in checker.jar (see the comment in + // ../build.gradle in the shadowJar block). } // Shadowing Test Sources and Dependencies @@ -25,27 +25,27 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar * @return */ def createDataflowShaded(shadedPkgName) { - tasks.create(name: "dataflow${shadedPkgName}Jar", type: ShadowJar, dependsOn: compileJava, group: 'Build') { - description "Builds dataflow-${shadedPkgName}.jar." - includeEmptyDirs = false - archivesBaseName = "dataflow-${shadedPkgName}" - // Without this line, the Maven artifact will have the classifier "all". - archiveClassifier.set('') + tasks.create(name: "dataflow${shadedPkgName}Jar", type: ShadowJar, dependsOn: compileJava, group: 'Build') { + description "Builds dataflow-${shadedPkgName}.jar." + includeEmptyDirs = false + archivesBaseName = "dataflow-${shadedPkgName}" + // Without this line, the Maven artifact will have the classifier "all". + archiveClassifier.set('') - from shadowJar.source - configurations = shadowJar.configurations + from shadowJar.source + configurations = shadowJar.configurations - destinationDirectory = file("${buildDir}/shadow/dataflow${shadedPkgName}") + destinationDirectory = file("${buildDir}/shadow/dataflow${shadedPkgName}") - relocate('org.checkerframework', "org.checkerframework.${shadedPkgName}") { - // Shade all Checker Framework packages, except for the dataflow qualifiers. - exclude 'org.checkerframework.dataflow.qual.*' - } - - // Relocate external dependencies - relocate 'org.plume', "org.checkerframework.${shadedPkgName}.org.plume" + relocate('org.checkerframework', "org.checkerframework.${shadedPkgName}") { + // Shade all Checker Framework packages, except for the dataflow qualifiers. + exclude 'org.checkerframework.dataflow.qual.*' } + + // Relocate external dependencies + relocate 'org.plume', "org.checkerframework.${shadedPkgName}.org.plume" + } } // Creates a new shaded dataflow artifact. To add a new one, add a new method call below, and add @@ -55,132 +55,161 @@ createDataflowShaded('nullaway') createDataflowShaded('errorprone') task liveVariableTest(dependsOn: [assemble, compileTestJava], group: 'Verification') { - description 'Test the live variable analysis test for dataflow framework.' - inputs.file('tests/live-variable/Expected.txt') - inputs.file('tests/live-variable/Test.java') - - outputs.file('tests/live-variable/Out.txt') - outputs.file('tests/live-variable/Test.class') - - delete('tests/live-variable/Out.txt') - delete('tests/live-variable/Test.class') - doLast { - javaexec { - workingDir = 'tests/live-variable' - if (!JavaVersion.current().java9Compatible) { - jvmArgs += "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() - } - else if (JavaVersion.current() > JavaVersion.VERSION_11) { - jvmArgs += [ - '--add-opens', 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - ] - } - - classpath = sourceSets.test.runtimeClasspath - classpath += sourceSets.test.output - mainClass = 'livevar.LiveVariable' - } - exec { - workingDir = 'tests/live-variable' - executable 'diff' - args = ['-u', 'Expected.txt', 'Out.txt'] - } + description 'Test the live variable analysis test for dataflow framework.' + inputs.file('tests/live-variable/Expected.txt') + inputs.file('tests/live-variable/Test.java') + + outputs.file('tests/live-variable/Out.txt') + outputs.file('tests/live-variable/Test.class') + + delete('tests/live-variable/Out.txt') + delete('tests/live-variable/Test.class') + doLast { + javaexec { + workingDir = 'tests/live-variable' + if (!JavaVersion.current().java9Compatible) { + jvmArgs += "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() + } + else if (JavaVersion.current() > JavaVersion.VERSION_11) { + jvmArgs += [ + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + ] + } + + classpath = sourceSets.test.runtimeClasspath + classpath += sourceSets.test.output + mainClass = 'livevar.LiveVariable' } + exec { + workingDir = 'tests/live-variable' + executable 'diff' + args = [ + '-u', + 'Expected.txt', + 'Out.txt' + ] + } + } } task issue3447Test(dependsOn: [assemble, compileTestJava], group: 'Verification') { - description 'Test issue 3447 test case for backward analysis.' - inputs.file('tests/issue3447/Test.java') - delete('tests/issue3447/Out.txt') - delete('tests/issue3447/Test.class') - doLast { - javaexec { - workingDir = 'tests/issue3447' - if (!JavaVersion.current().java9Compatible) { - jvmArgs += "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() - } - else if (JavaVersion.current() > JavaVersion.VERSION_11) { - jvmArgs += [ - '--add-opens', 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - ] - } - classpath = sourceSets.test.runtimeClasspath - classpath += sourceSets.test.output - - mainClass = 'livevar.LiveVariable' - } + description 'Test issue 3447 test case for backward analysis.' + inputs.file('tests/issue3447/Test.java') + delete('tests/issue3447/Out.txt') + delete('tests/issue3447/Test.class') + doLast { + javaexec { + workingDir = 'tests/issue3447' + if (!JavaVersion.current().java9Compatible) { + jvmArgs += "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() + } + else if (JavaVersion.current() > JavaVersion.VERSION_11) { + jvmArgs += [ + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + ] + } + classpath = sourceSets.test.runtimeClasspath + classpath += sourceSets.test.output + + mainClass = 'livevar.LiveVariable' } + } } task constantPropagationTest(dependsOn: [assemble, compileTestJava], group: 'Verification') { - description 'Test the constant propagation analysis of the dataflow framework.' - inputs.file('tests/constant-propagation/Expected.txt') - inputs.file('tests/constant-propagation/Test.java') - - outputs.file('tests/constant-propagation/Out.txt') - outputs.file('tests/constant-propagation/Test.class') - - delete('tests/constant-propagation/Out.txt') - delete('tests/constant-propagation/Test.class') - doLast { - javaexec { - workingDir = 'tests/constant-propagation' - if (!JavaVersion.current().java9Compatible) { - jvmArgs += "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() - } - else if (JavaVersion.current() > JavaVersion.VERSION_11) { - jvmArgs += [ - '--add-opens', 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - '--add-opens', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - ] - } - classpath = sourceSets.test.runtimeClasspath - classpath += sourceSets.test.output - mainClass = 'constantpropagation.ConstantPropagation' - } - exec { - workingDir = 'tests/constant-propagation' - executable 'diff' - args = ['-u', 'Expected.txt', 'Out.txt'] - } + description 'Test the constant propagation analysis of the dataflow framework.' + inputs.file('tests/constant-propagation/Expected.txt') + inputs.file('tests/constant-propagation/Test.java') + + outputs.file('tests/constant-propagation/Out.txt') + outputs.file('tests/constant-propagation/Test.class') + + delete('tests/constant-propagation/Out.txt') + delete('tests/constant-propagation/Test.class') + doLast { + javaexec { + workingDir = 'tests/constant-propagation' + if (!JavaVersion.current().java9Compatible) { + jvmArgs += "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString() + } + else if (JavaVersion.current() > JavaVersion.VERSION_11) { + jvmArgs += [ + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-opens', + 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + ] + } + classpath = sourceSets.test.runtimeClasspath + classpath += sourceSets.test.output + mainClass = 'constantpropagation.ConstantPropagation' + } + exec { + workingDir = 'tests/constant-propagation' + executable 'diff' + args = [ + '-u', + 'Expected.txt', + 'Out.txt' + ] } + } } apply from: rootProject.file('gradle-mvn-push.gradle') /** Adds information to the publication for uploading the dataflow artifacts to Maven repositories. */ final dataflowPom(publication) { - sharedPublicationConfiguration(publication) - publication.from components.java - // Information that is in all pom files is configured in checker-framework/gradle-mvn-push.gradle. - publication.pom { - name = 'Dataflow' - description = 'Dataflow is a dataflow framework based on the javac compiler.' - licenses { - license { - name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' - url = 'http://www.gnu.org/software/classpath/license.html' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + publication.from components.java + // Information that is in all pom files is configured in checker-framework/gradle-mvn-push.gradle. + publication.pom { + name = 'Dataflow' + description = 'Dataflow is a dataflow framework based on the javac compiler.' + licenses { + license { + name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' + url = 'http://www.gnu.org/software/classpath/license.html' + distribution = 'repo' + } } + } } /** @@ -188,61 +217,61 @@ final dataflowPom(publication) { * @param shadedPkgName the name of the shaded package to use; also used as part of the artifact name: "dataflow-${shadePkgName}" */ final dataflowShadedPom(MavenPublication publication, String shadedPkgName) { - sharedPublicationConfiguration(publication) - - publication.artifactId = "dataflow-${shadedPkgName}" - publication.pom { - name = "Dataflow (${shadedPkgName})" - description = "dataflow-${shadedPkgName} is a dataflow framework based on the javac compiler.\n" + - '\n' + - 'It differs from the org.checkerframework:dataflow artifact in two ways.\n' + - "First, the packages in this artifact have been renamed to org.checkerframework.${shadedPkgName}.*.\n" + - 'Second, unlike the dataflow artifact, this artifact contains the dependencies it requires.' - licenses { - license { - name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' - url = 'http://www.gnu.org/software/classpath/license.html' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + + publication.artifactId = "dataflow-${shadedPkgName}" + publication.pom { + name = "Dataflow (${shadedPkgName})" + description = "dataflow-${shadedPkgName} is a dataflow framework based on the javac compiler.\n" + + '\n' + + 'It differs from the org.checkerframework:dataflow artifact in two ways.\n' + + "First, the packages in this artifact have been renamed to org.checkerframework.${shadedPkgName}.*.\n" + + 'Second, unlike the dataflow artifact, this artifact contains the dependencies it requires.' + licenses { + license { + name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' + url = 'http://www.gnu.org/software/classpath/license.html' + distribution = 'repo' + } } + } } publishing { - publications { - dataflow(MavenPublication) { - dataflowPom it - } - - dataflowShaded(MavenPublication) { - dataflowShadedPom(it, 'shaded') - - artifact getTasksByName('dataflowshadedJar',false).iterator().next() - artifact sourcesJar - artifact javadocJar - } - - dataflowShadednullaway(MavenPublication) { - dataflowShadedPom(it, 'nullaway') - - artifact getTasksByName('dataflownullawayJar',false).iterator().next() - artifact sourcesJar - artifact javadocJar - } - - dataflowShadederrorprone(MavenPublication) { - dataflowShadedPom(it, 'errorprone') - - artifact getTasksByName('dataflowerrorproneJar',false).iterator().next() - artifact sourcesJar - artifact javadocJar - } + publications { + dataflow(MavenPublication) { + dataflowPom it + } + + dataflowShaded(MavenPublication) { + dataflowShadedPom(it, 'shaded') + + artifact getTasksByName('dataflowshadedJar',false).iterator().next() + artifact sourcesJar + artifact javadocJar + } + + dataflowShadednullaway(MavenPublication) { + dataflowShadedPom(it, 'nullaway') + + artifact getTasksByName('dataflownullawayJar',false).iterator().next() + artifact sourcesJar + artifact javadocJar + } + + dataflowShadederrorprone(MavenPublication) { + dataflowShadedPom(it, 'errorprone') + + artifact getTasksByName('dataflowerrorproneJar',false).iterator().next() + artifact sourcesJar + artifact javadocJar } + } } signing { - sign publishing.publications.dataflow - sign publishing.publications.dataflowShaded - sign publishing.publications.dataflowShadednullaway - sign publishing.publications.dataflowShadederrorprone + sign publishing.publications.dataflow + sign publishing.publications.dataflowShaded + sign publishing.publications.dataflowShadednullaway + sign publishing.publications.dataflowShadederrorprone } diff --git a/docs/examples/errorprone/build.gradle b/docs/examples/errorprone/build.gradle index 75244f7ea32..a454c588bad 100644 --- a/docs/examples/errorprone/build.gradle +++ b/docs/examples/errorprone/build.gradle @@ -3,36 +3,36 @@ /// plugins { - id 'java' - id 'net.ltgt.errorprone' version '2.0.2' - // Checker Framework pluggable type-checking - id 'org.checkerframework' version '0.6.21' + id 'java' + id 'net.ltgt.errorprone' version '2.0.2' + // Checker Framework pluggable type-checking + id 'org.checkerframework' version '0.6.21' } apply plugin: 'org.checkerframework' dependencies { - // Must use at least version 2.4.0 of Error Prone. - if (JavaVersion.current() == JavaVersion.VERSION_1_8) { - errorprone 'com.google.errorprone:error_prone_core:2.10.0' - } else { - errorprone 'com.google.errorprone:error_prone_core:2.12.0' - } + // Must use at least version 2.4.0 of Error Prone. + if (JavaVersion.current() == JavaVersion.VERSION_1_8) { + errorprone 'com.google.errorprone:error_prone_core:2.10.0' + } else { + errorprone 'com.google.errorprone:error_prone_core:2.12.0' + } } repositories { - mavenCentral() + mavenCentral() } checkerFramework { - checkers = [ - 'org.checkerframework.checker.nullness.NullnessChecker', - ] + checkers = [ + 'org.checkerframework.checker.nullness.NullnessChecker', + ] } compileJava { - // A checker will only run if Error Prone does not issue any warnings. So - // convert the expected error to a warning to test that both Error Prone - // and the Nullness Checker run. - options.errorprone.warn('CollectionIncompatibleType') + // A checker will only run if Error Prone does not issue any warnings. So + // convert the expected error to a warning to test that both Error Prone + // and the Nullness Checker run. + options.errorprone.warn('CollectionIncompatibleType') } diff --git a/docs/examples/lombok/build.gradle b/docs/examples/lombok/build.gradle index 24dc54311e9..94003f6b3f7 100644 --- a/docs/examples/lombok/build.gradle +++ b/docs/examples/lombok/build.gradle @@ -3,27 +3,27 @@ /// plugins { - id 'java' - id 'io.freefair.lombok' version '5.3.3.3' - // Checker Framework pluggable type-checking - id 'org.checkerframework' version '0.6.21' + id 'java' + id 'io.freefair.lombok' version '5.3.3.3' + // Checker Framework pluggable type-checking + id 'org.checkerframework' version '0.6.21' } apply plugin: 'org.checkerframework' def cfHome = "${projectDir}/../../.." dependencies { - compileOnly files(cfHome + '/checker/dist/checker-qual.jar') - testCompileOnly files(cfHome + '/checker/dist/checker-qual.jar') - checkerFramework files(cfHome + '/checker/dist/checker.jar') + compileOnly files(cfHome + '/checker/dist/checker-qual.jar') + testCompileOnly files(cfHome + '/checker/dist/checker-qual.jar') + checkerFramework files(cfHome + '/checker/dist/checker.jar') } repositories { - mavenCentral() + mavenCentral() } checkerFramework { - checkers = [ - 'org.checkerframework.checker.nullness.NullnessChecker', - ] + checkers = [ + 'org.checkerframework.checker.nullness.NullnessChecker', + ] } diff --git a/framework-test/build.gradle b/framework-test/build.gradle index e41819fbbab..3f1dc5f75c7 100644 --- a/framework-test/build.gradle +++ b/framework-test/build.gradle @@ -1,20 +1,20 @@ import org.gradle.internal.jvm.Jvm sourceSets { - taglet - tagletJdk8 + taglet + tagletJdk8 } dependencies { - implementation group: 'junit', name: 'junit', version: '4.13.2' - implementation project(':javacutil') - implementation project(':checker-qual') + implementation group: 'junit', name: 'junit', version: '4.13.2' + implementation project(':javacutil') + implementation project(':checker-qual') - implementation "org.plumelib:plume-util:${plumeUtilVersion}" + implementation "org.plumelib:plume-util:${plumeUtilVersion}" - if (Jvm.current().toolsJar) { - tagletJdk8Implementation files(Jvm.current().toolsJar) - } + if (Jvm.current().toolsJar) { + tagletJdk8Implementation files(Jvm.current().toolsJar) + } } jar.archiveBaseName = 'framework-test' @@ -23,28 +23,28 @@ apply from: rootProject.file('gradle-mvn-push.gradle') /** Adds information to the publication for uploading to Maven repositories. */ final frameworkTest(publication) { - sharedPublicationConfiguration(publication) - publication.from components.java - publication.pom { - name = 'Checker Framework Testing Library' - description = 'framework-test contains utility classes for testing type-checkers\n' + - 'that are built on the Checker Framework.' - licenses { - license { - name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' - url = 'http://www.gnu.org/software/classpath/license.html' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + publication.from components.java + publication.pom { + name = 'Checker Framework Testing Library' + description = 'framework-test contains utility classes for testing type-checkers\n' + + 'that are built on the Checker Framework.' + licenses { + license { + name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' + url = 'http://www.gnu.org/software/classpath/license.html' + distribution = 'repo' + } } + } } publishing { - publications { - frameworkTest(MavenPublication) { - frameworkTest it - } + publications { + frameworkTest(MavenPublication) { + frameworkTest it } + } } signing { - sign publishing.publications.frameworkTest + sign publishing.publications.frameworkTest } diff --git a/framework/build.gradle b/framework/build.gradle index 35b409e612e..6d23954bb8b 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -1,28 +1,31 @@ plugins { - id 'java-library' + id 'java-library' } ext { - annotatedJdkHome = '../../jdk' + annotatedJdkHome = '../../jdk' } sourceSets { - main { - resources { - // Stub files, message.properties, etc. - srcDirs += ['src/main/java', "${buildDir}/generated/resources"] - } + main { + resources { + // Stub files, message.properties, etc. + srcDirs += [ + 'src/main/java', + "${buildDir}/generated/resources" + ] } - testannotations + } + testannotations } sourcesJar { - // The resources duplicate content from the src directory. - duplicatesStrategy = DuplicatesStrategy.EXCLUDE + // The resources duplicate content from the src directory. + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } def versions = [ - autoValue : '1.7.4', - lombok : '1.18.24', + autoValue : '1.7.4', + lombok : '1.18.24', ] configurations { @@ -30,198 +33,209 @@ configurations { } 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:${plumeUtilVersion}" - implementation "org.plumelib:reflection-util:${reflectionUtilVersion}" - implementation 'io.github.classgraph:classgraph:4.8.149' - - 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}" + 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:${plumeUtilVersion}" + implementation "org.plumelib:reflection-util:${reflectionUtilVersion}" + implementation 'io.github.classgraph:classgraph:4.8.149' + + 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'] - } - } + 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 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) - } + 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 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; + } } - javaexec { - classpath = sourceSets.main.runtimeClasspath + } + } + 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 - mainClass = 'org.checkerframework.framework.stub.JavaStubifier' - args outputDir - } + mainClass = 'org.checkerframework.framework.stub.JavaStubifier' + args outputDir } + } } sourcesJar.dependsOn(copyAndMinimizeAnnotatedJdkFiles) processResources.dependsOn(copyAndMinimizeAnnotatedJdkFiles) task checkDependencies(dependsOn: ':maybeCloneAndBuildDependencies') { - doLast { - if (!file(stubparserJar).exists()) { - throw new GradleException("${stubparserJar} does not exist. Try running './gradlew cloneAndBuildDependencies'") - } + 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) + 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 - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - destinationDirectory = file("${projectDir}/dist") - archiveFileName = 'framework-javadoc.jar' - from (project(':framework').tasks.javadoc.destinationDir, - project(':dataflow').tasks.javadoc.destinationDir, - project(':javacutil').tasks.javadoc.destinationDir) + description 'Creates javadoc jar include Javadoc for all of the framework' + dependsOn rootProject.tasks.allJavadoc + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + 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') - } + 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 - ] + 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'] - } + 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') + delete('tests/returnsreceiverdelomboked') + delete('dist') } task delombok { - description 'Delomboks the source code tree in tests/returnsreceiverlombok' + description 'Delomboks the source code tree in tests/returnsreceiverlombok' - def srcDelomboked = 'tests/returnsreceiverdelomboked' - def srcJava = 'tests/returnsreceiverlombok' + def srcDelomboked = 'tests/returnsreceiverdelomboked' + def srcJava = 'tests/returnsreceiverlombok' - inputs.files file(srcJava) - outputs.dir file(srcDelomboked) + 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 + // 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 { - if(!skipDelombok) { - 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) - } + doLast { + if(!skipDelombok) { + 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) } + } } if (skipDelombok) { - delombok.enabled = false - test { - exclude '**/ReturnsReceiverLombokTest.java' - } + delombok.enabled = false + test { + exclude '**/ReturnsReceiverLombokTest.java' + } } else { - tasks.test.dependsOn('delombok') + tasks.test.dependsOn('delombok') } diff --git a/gradle-mvn-push.gradle b/gradle-mvn-push.gradle index 8d4616b12c3..af33054759e 100644 --- a/gradle-mvn-push.gradle +++ b/gradle-mvn-push.gradle @@ -4,37 +4,37 @@ apply plugin: 'signing' final isSnapshot = version.contains('SNAPSHOT') // https://github.com/johnrengelman/shadow/issues/586#issuecomment-708375599 components.java.withVariantsFromConfiguration(configurations.shadowRuntimeElements) { - skip() + skip() } publishing { - repositories { - maven { - url = (isSnapshot - ? project.properties.getOrDefault('SNAPSHOT_REPOSITORY_URL', 'https://oss.sonatype.org/content/repositories/snapshots/') - : project.properties.getOrDefault('RELEASE_REPOSITORY_URL', 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') - ) - credentials { - username = project.properties.get('SONATYPE_NEXUS_USERNAME') - password = project.properties.get('SONATYPE_NEXUS_PASSWORD') - } - } + repositories { + maven { + url = (isSnapshot + ? project.properties.getOrDefault('SNAPSHOT_REPOSITORY_URL', 'https://oss.sonatype.org/content/repositories/snapshots/') + : project.properties.getOrDefault('RELEASE_REPOSITORY_URL', 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') + ) + credentials { + username = project.properties.get('SONATYPE_NEXUS_USERNAME') + password = project.properties.get('SONATYPE_NEXUS_PASSWORD') + } } + } } signing { - // Use external gpg cmd. This makes it easy to use gpg-agent, - // to avoid being prompted for a password once per artifact. - useGpgCmd() + // Use external gpg cmd. This makes it easy to use gpg-agent, + // to avoid being prompted for a password once per artifact. + useGpgCmd() - // If anything about signing is misconfigured, fail loudly rather than quietly continuing with - // unsigned artifacts. - required = true + // If anything about signing is misconfigured, fail loudly rather than quietly continuing with + // unsigned artifacts. + required = true } // Only sign releases; snapshots are unsigned. tasks.withType(Sign).configureEach { - onlyIf { - release - } + onlyIf { + release + } } diff --git a/javacutil/build.gradle b/javacutil/build.gradle index daef10b85ac..8a42ccf59b2 100644 --- a/javacutil/build.gradle +++ b/javacutil/build.gradle @@ -1,52 +1,52 @@ plugins { - id 'java-library' + id 'java-library' } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation project(':checker-qual') + implementation project(':checker-qual') - // This is used by org.checkerframework.javacutil.TypesUtils.isImmutableTypeInJdk. - // https://mvnrepository.com/artifact/org.plumelib/plume-util - implementation "org.plumelib:plume-util:${plumeUtilVersion}" + // This is used by org.checkerframework.javacutil.TypesUtils.isImmutableTypeInJdk. + // https://mvnrepository.com/artifact/org.plumelib/plume-util + implementation "org.plumelib:plume-util:${plumeUtilVersion}" - // External dependencies: - // If you add an external dependency, you must shadow its packages both in checker.jar and - // and dataflow-shaded.jar. - // See the comment in ../build.gradle in the shadowJar block and ../dataflow/build.gradle in - // shadowJar block. + // External dependencies: + // If you add an external dependency, you must shadow its packages both in checker.jar and + // and dataflow-shaded.jar. + // See the comment in ../build.gradle in the shadowJar block and ../dataflow/build.gradle in + // shadowJar block. } apply from: rootProject.file('gradle-mvn-push.gradle') final javacUtilPom(publication) { - sharedPublicationConfiguration(publication) - publication.from components.java - - publication.pom { - name = 'Javacutil' - description = 'javacutil contains utility classes for the javac compiler.' - licenses { - license { - name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' - url = 'http://www.gnu.org/software/classpath/license.html' - distribution = 'repo' - } - } + sharedPublicationConfiguration(publication) + publication.from components.java + + publication.pom { + name = 'Javacutil' + description = 'javacutil contains utility classes for the javac compiler.' + licenses { + license { + name = 'GNU General Public License, version 2 (GPL2), with the classpath exception' + url = 'http://www.gnu.org/software/classpath/license.html' + distribution = 'repo' + } } + } } publishing { - publications { - javacUtil(MavenPublication) { - javacUtilPom it - } + publications { + javacUtil(MavenPublication) { + javacUtilPom it } + } } signing { - sign publishing.publications.javacUtil + sign publishing.publications.javacUtil } diff --git a/settings.gradle b/settings.gradle index 9f5adcc37e3..410ba608de5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,9 +8,9 @@ include 'checker-qual-android' include 'checker-util' include 'framework-test' includeBuild ('../annotation-tools/annotation-file-utilities') { - if (!file('../annotation-tools/annotation-file-utilities').exists()) { - exec { - executable 'checker/bin-devel/build.sh' - } + if (!file('../annotation-tools/annotation-file-utilities').exists()) { + exec { + executable 'checker/bin-devel/build.sh' } + } }