Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import net.ltgt.gradle.errorprone.errorprone

plugins {
`java-library`
id("dd-trace-java.conventions.nullaway")
}

val jspecify = versionCatalogs.named("libs").findLibrary("jspecify").get()
sourceSets.matching { name != SourceSet.MAIN_SOURCE_SET_NAME && name != SourceSet.TEST_SOURCE_SET_NAME }.configureEach {
dependencies.add(compileOnlyConfigurationName, jspecify)
}
dependencies {
api(jspecify)
}

tasks.withType<JavaCompile>().configureEach {
options.errorprone.checkOptions.set(
mapOf(
"NullAway:OnlyNullMarked" to "true",
"NullAway:JSpecifyMode" to "true",
"NullAway:TreatGeneratedAsUnannotated" to "true"
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ plugins {
id("com.github.spotbugs")
}

val libs = versionCatalogs.named("libs")

spotbugs {
toolVersion = libs.findVersion("spotbugs").get().requiredVersion
ignoreFailures = false
// Exclude known types and packages
excludeFilter = rootDir.resolve("gradle/spotbugFilters/exclude.xml")
Expand Down Expand Up @@ -64,7 +67,6 @@ tasks.withType<SpotBugsTask>().configureEach {
}
}

val libs = versionCatalogs.named("libs")
dependencies {
compileOnly(libs.findLibrary("spotbugs-annotations").get())
testImplementation(libs.findLibrary("jsr305").get())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class NullAwayConventionsPluginTest : GradleFixture() {
[libraries]
errorprone = { module = "com.google.errorprone:error_prone_core", version = "2.50.0" }
nullaway = { module = "com.uber.nullaway:nullaway", version = "0.14.2" }
jspecify = { module = "org.jspecify:jspecify", version = "1.0.1" }
"""
)
writeRootProject(
Expand Down Expand Up @@ -115,6 +116,143 @@ class NullAwayConventionsPluginTest : GradleFixture() {
assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(SUCCESS)
}

@Test
fun `JSpecify mode checks nullable type arguments`() {
useJSpecify()
writeJavaSource(
"datadog.example.GenericContract",
"""
package datadog.example;
import java.util.List;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class GenericContract {
public List<String> values(List<@Nullable String> values) { return values; }
}
"""
)

val result = run("compileJava", expectFailure = true)

assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(FAILED)
assertThat(result.output).contains("[NullAway]")
}

@ParameterizedTest
@ValueSource(strings = ["@Nullable String[]", "@Nullable String..."])
fun `JSpecify checks nullable array and varargs elements`(parameterType: String) {
useJSpecify()
writeJavaSource(
"datadog.example.ArrayContract",
"""
package datadog.example;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class ArrayContract {
public int length($parameterType values) { return values[0].length(); }
}
"""
)

val result = run("compileJava", expectFailure = true)

assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(FAILED)
assertThat(result.output).contains("[NullAway]")
}

@Test
fun `JSpecify permits guarded nullable values and leaves unmarked code unchecked`() {
useJSpecify()
writeJavaSource(
"datadog.example.ArrayContract",
"""
package datadog.example;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class ArrayContract {
public int length(@Nullable String @Nullable ... values) {
if (values == null) return 0;
int length = 0;
for (String value : values) {
if (value != null) length += value.length();
}
return length;
}
}
"""
)
writeViolation("main_java17")
writeRootProject("""sourceSets.create("main_java17")""", append = true)

val result = run("compileJava", "compileMain_java17Java")

assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(SUCCESS)
assertThat(result.task(":compileMain_java17Java")?.outcome).describedAs(result.output).isEqualTo(SUCCESS)
}

@Test
fun `JSpecify reaches consumers for compilation and Java 8 reflection`() {
useJSpecify()
writeGradleProperties("org.gradle.java.installations.fromEnv=JAVA_8_HOME")
writeJavaSource(
"datadog.example.Producer",
"""
package datadog.example;
import org.jspecify.annotations.Nullable;
public class Producer {
public @Nullable String value() { return null; }
}
"""
)
addSubproject(
"consumer",
"""
plugins { application }
repositories { mavenCentral() }
dependencies { implementation(project(":")) }
application { mainClass.set("datadog.example.Consumer") }
tasks.withType<JavaCompile>().configureEach { options.release = 8 }
tasks.named<JavaExec>("run") {
javaLauncher.set(javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) })
}
"""
)
writeJavaSource(
"datadog.example.Consumer",
"""
package datadog.example;
import org.jspecify.annotations.Nullable;
public class Consumer {
public static void main(String[] args) throws ReflectiveOperationException {
if (Producer.class.getMethod("value").getAnnotatedReturnType()
.getAnnotation(Nullable.class) == null) {
throw new AssertionError("Missing nullable return annotation");
}
}
}
""",
projectPath = "consumer"
)

val result = run(":consumer:run")

assertThat(result.task(":consumer:compileJava")?.outcome).describedAs(result.output).isEqualTo(SUCCESS)
assertThat(result.task(":consumer:run")?.outcome).describedAs(result.output).isEqualTo(SUCCESS)
}

private fun useJSpecify() {
writeRootProject(
"""
plugins { id("dd-trace-java.conventions.jspecify") }
repositories { mavenCentral() }
tasks.withType<JavaCompile>().configureEach { options.release = 8 }
"""
)
}

private fun writeViolation(sourceSet: String) {
writeJavaSource(
"datadog.example.Violation",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ class SpotBugsConventionsPluginTest : GradleFixture() {
writeFile(
"gradle/libs.versions.toml",
"""
[versions]
spotbugs = "4.10.5"

[libraries]
spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version = "4.10.4" }
spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version.ref = "spotbugs" }
jsr305 = { module = "com.google.code.findbugs:jsr305", version = "3.0.2" }
"""
)
Expand All @@ -34,6 +37,38 @@ class SpotBugsConventionsPluginTest : GradleFixture() {
)
}

@Test
fun `JSpecify overrides cannot tighten nullable parameters`() {
writeRootProject(
"""dependencies { compileOnly("org.jspecify:jspecify:1.0.1") }""",
append = true
)
writeJavaSource(
"example.NullableContract",
"""
package example;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

public interface NullableContract {
void accept(@Nullable String value);
}

class TightenedContract implements NullableContract {
@Override
public void accept(@NonNull String value) {}
}
"""
)

val result = run("spotbugsMain", expectFailure = true)

assertThat(result.task(":spotbugsMain")?.outcome).describedAs(result.output).isEqualTo(FAILED)
assertThat(buildFile("reports/spotbugs/spotbugsMain.html"))
.exists().content().contains("NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION", "TightenedContract")
}

@ParameterizedTest
@ValueSource(strings = ["main", "main_java6", "main_java11", "main_java17", "main_java21", "main_java25"])
fun `production violations fail check and appear in the HTML report`(sourceSet: String) {
Expand Down
26 changes: 15 additions & 11 deletions communication/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ com.github.jnr:jnr-ffi:2.2.19=runtimeClasspath,testRuntimeClasspath
com.github.jnr:jnr-posix:3.1.22=runtimeClasspath,testRuntimeClasspath
com.github.jnr:jnr-unixsocket:0.38.25=runtimeClasspath,testRuntimeClasspath
com.github.jnr:jnr-x86asm:1.0.2=runtimeClasspath,testRuntimeClasspath
com.github.spotbugs:spotbugs-annotations:4.10.4=compileClasspath,spotbugs
com.github.spotbugs:spotbugs:4.10.4=spotbugs
com.github.spotbugs:spotbugs-annotations:4.10.5=compileClasspath,spotbugs
com.github.spotbugs:spotbugs:4.10.5=spotbugs
com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.14.0=spotbugs
Expand All @@ -37,7 +37,7 @@ com.squareup.okio:okio:1.17.5=compileClasspath,runtimeClasspath,testCompileClass
com.thoughtworks.qdox:qdox:1.12.1=codenarc
commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.21.0=spotbugs
commons-io:commons-io:2.22.0=spotbugs
de.thetaphi:forbiddenapis:3.11=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
jaxen:jaxen:2.0.6=spotbugs
Expand All @@ -47,8 +47,8 @@ net.bytebuddy:byte-buddy:1.18.12=testCompileClasspath,testRuntimeClasspath
net.sf.saxon:Saxon-HE:12.10=spotbugs
org.apache.ant:ant-antlr:1.10.14=codenarc
org.apache.ant:ant-junit:1.10.14=codenarc
org.apache.bcel:bcel:6.12.0=spotbugs
org.apache.commons:commons-lang3:3.20.0=spotbugs
org.apache.bcel:bcel:6.13.0=spotbugs
org.apache.commons:commons-lang3:3.21.0=spotbugs
org.apache.commons:commons-text:1.15.0=spotbugs
org.apache.logging.log4j:log4j-api:2.26.1=spotbugs
org.apache.logging.log4j:log4j-core:2.26.1=spotbugs
Expand All @@ -71,6 +71,7 @@ org.jacoco:org.jacoco.agent:0.8.15=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.15=jacocoAnt
org.jacoco:org.jacoco.core:0.8.15=jacocoAnt
org.jacoco:org.jacoco.report:0.8.15=jacocoAnt
org.jspecify:jspecify:1.0.1=compileClasspath,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath
Expand All @@ -84,23 +85,26 @@ org.msgpack:jackson-dataformat-msgpack:0.8.20=testCompileClasspath,testRuntimeCl
org.msgpack:msgpack-core:0.8.20=testCompileClasspath,testRuntimeClasspath
org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:9.10.1=spotbugs
org.ow2.asm:asm-analysis:9.11=spotbugs
org.ow2.asm:asm-analysis:9.7.1=runtimeClasspath,testRuntimeClasspath
org.ow2.asm:asm-commons:9.10.1=jacocoAnt,spotbugs
org.ow2.asm:asm-commons:9.10.1=jacocoAnt
org.ow2.asm:asm-commons:9.11=spotbugs
org.ow2.asm:asm-commons:9.7.1=runtimeClasspath,testRuntimeClasspath
org.ow2.asm:asm-tree:9.10.1=jacocoAnt,spotbugs
org.ow2.asm:asm-tree:9.10.1=jacocoAnt
org.ow2.asm:asm-tree:9.11=spotbugs
org.ow2.asm:asm-tree:9.7.1=runtimeClasspath,testRuntimeClasspath
org.ow2.asm:asm-util:9.10.1=spotbugs
org.ow2.asm:asm-util:9.11=spotbugs
org.ow2.asm:asm-util:9.7.1=runtimeClasspath,testRuntimeClasspath
org.ow2.asm:asm:9.10.1=jacocoAnt,spotbugs
org.ow2.asm:asm:9.10.1=jacocoAnt
org.ow2.asm:asm:9.11=spotbugs
org.ow2.asm:asm:9.7.1=runtimeClasspath,testRuntimeClasspath
org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.30=compileClasspath,runtimeClasspath
org.slf4j:slf4j-api:1.7.32=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.17=spotbugsSlf4j
org.slf4j:slf4j-api:2.0.18=spotbugs
org.slf4j:slf4j-api:2.0.20=spotbugs
org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j
org.snakeyaml:snakeyaml-engine:2.9=runtimeClasspath,testRuntimeClasspath
org.spockframework:spock-bom:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
Expand Down
26 changes: 15 additions & 11 deletions components/annotations/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
ch.qos.logback:logback-classic:1.2.13=testCompileClasspath,testRuntimeClasspath
ch.qos.logback:logback-core:1.2.13=testCompileClasspath,testRuntimeClasspath
com.github.javaparser:javaparser-core:3.25.6=codenarc
com.github.spotbugs:spotbugs-annotations:4.10.4=compileClasspath,spotbugs
com.github.spotbugs:spotbugs:4.10.4=spotbugs
com.github.spotbugs:spotbugs-annotations:4.10.5=compileClasspath,spotbugs
com.github.spotbugs:spotbugs:4.10.5=spotbugs
com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.14.0=spotbugs
com.google.errorprone:error_prone_annotations:2.48.0=spotbugs
com.thoughtworks.qdox:qdox:1.12.1=codenarc
commons-io:commons-io:2.21.0=spotbugs
commons-io:commons-io:2.22.0=spotbugs
de.thetaphi:forbiddenapis:3.11=compileClasspath
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
jaxen:jaxen:2.0.6=spotbugs
Expand All @@ -21,8 +21,8 @@ net.bytebuddy:byte-buddy:1.12.8=testRuntimeClasspath
net.sf.saxon:Saxon-HE:12.10=spotbugs
org.apache.ant:ant-antlr:1.10.14=codenarc
org.apache.ant:ant-junit:1.10.14=codenarc
org.apache.bcel:bcel:6.12.0=spotbugs
org.apache.commons:commons-lang3:3.20.0=spotbugs
org.apache.bcel:bcel:6.13.0=spotbugs
org.apache.commons:commons-lang3:3.21.0=spotbugs
org.apache.commons:commons-text:1.15.0=spotbugs
org.apache.logging.log4j:log4j-api:2.26.1=spotbugs
org.apache.logging.log4j:log4j-core:2.26.1=spotbugs
Expand All @@ -44,6 +44,7 @@ org.jacoco:org.jacoco.agent:0.8.15=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.15=jacocoAnt
org.jacoco:org.jacoco.core:0.8.15=jacocoAnt
org.jacoco:org.jacoco.report:0.8.15=jacocoAnt
org.jspecify:jspecify:1.0.1=spotbugs
org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath
Expand All @@ -55,17 +56,20 @@ org.junit:junit-bom:5.14.1=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:4.4.0=testRuntimeClasspath
org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:9.10.1=spotbugs
org.ow2.asm:asm-commons:9.10.1=jacocoAnt,spotbugs
org.ow2.asm:asm-tree:9.10.1=jacocoAnt,spotbugs
org.ow2.asm:asm-util:9.10.1=spotbugs
org.ow2.asm:asm:9.10.1=jacocoAnt,spotbugs
org.ow2.asm:asm-analysis:9.11=spotbugs
org.ow2.asm:asm-commons:9.10.1=jacocoAnt
org.ow2.asm:asm-commons:9.11=spotbugs
org.ow2.asm:asm-tree:9.10.1=jacocoAnt
org.ow2.asm:asm-tree:9.11=spotbugs
org.ow2.asm:asm-util:9.11=spotbugs
org.ow2.asm:asm:9.10.1=jacocoAnt
org.ow2.asm:asm:9.11=spotbugs
org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.32=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.17=spotbugsSlf4j
org.slf4j:slf4j-api:2.0.18=spotbugs
org.slf4j:slf4j-api:2.0.20=spotbugs
org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j
org.spockframework:spock-bom:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
org.spockframework:spock-core:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
Expand Down
2 changes: 1 addition & 1 deletion components/context/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id("dd-trace-java.module.platform-component")
id("dd-trace-java.conventions.nullaway")
id("dd-trace-java.conventions.jspecify")
}

dependencies {
Expand Down
Loading
Loading