diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index cbe8a27763..acd63b7f65 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -21,7 +21,12 @@ jobs: steps: - name: Check out NullAway sources uses: actions/checkout@v6 - - name: 'Set up JDKs' + - name: 'Set up JDK 27 EA from jdk.java.net' + uses: oracle-actions/setup-java@v1 + with: + website: jdk.java.net + release: 27 + - name: 'Set up Default JDK' uses: actions/setup-java@v5 with: java-version: 25 diff --git a/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle b/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle index eb12c4f6d5..f67b5d5b23 100644 --- a/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle +++ b/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle @@ -78,7 +78,7 @@ test { } // Tasks for testing on other JDK versions; see https://jakewharton.com/build-on-latest-java-test-through-lowest-java/ -[21, 26].each { majorVersion -> +[21, 26, 27].each { majorVersion -> def jdkTest = tasks.register("testJdk$majorVersion", Test) { javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(majorVersion) diff --git a/jar-infer/jar-infer-lib/build.gradle b/jar-infer/jar-infer-lib/build.gradle index 9a821d032b..7e67345e8b 100644 --- a/jar-infer/jar-infer-lib/build.gradle +++ b/jar-infer/jar-infer-lib/build.gradle @@ -50,4 +50,8 @@ tasks.withType(JavaCompile).configureEach { options.compilerArgs += "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED" } +tasks.getByName('testJdk27').configure { + // Won't work until WALA supports JDK 27 + onlyIf { false } +} apply plugin: 'com.vanniktech.maven.publish' diff --git a/nullaway/src/main/java/com/uber/nullaway/dataflow/CoreNullnessStoreInitializer.java b/nullaway/src/main/java/com/uber/nullaway/dataflow/CoreNullnessStoreInitializer.java index 08655c1b5d..fa7355c4bd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/dataflow/CoreNullnessStoreInitializer.java +++ b/nullaway/src/main/java/com/uber/nullaway/dataflow/CoreNullnessStoreInitializer.java @@ -162,8 +162,14 @@ private NullnessStore lambdaInitialStore( Element element = param.getElement(); Nullness assumed; // we treat lambda parameters differently; they "inherit" the nullability of the - // corresponding functional interface parameter, unless they are explicitly annotated - if (Nullness.hasNullableAnnotation((Symbol) element, config)) { + // corresponding functional interface parameter, unless they are explicitly annotated. + // + // We look for explicit @Nullable annotations on the symbol. In JDK 27+, sometimes + // javac will add a @Nullable annotation to the Type of element based on its own generic + // inference. We don't want to consider that here (it is handled in the type stored in + // fiArgumentNullness), so we only look at the annotations directly on element + if (Nullness.hasNullableAnnotation( + ((Symbol) element).getAnnotationMirrors().stream(), config)) { assumed = NULLABLE; } else if (!NullabilityUtil.lambdaParamIsImplicitlyTyped(variableTree)) { // the parameter has a declared type with no @Nullable annotation