diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 9964550754..9e27d42c0a 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -485,6 +485,11 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { if (lhsType != null && lhsType.isPrimitive()) { doUnboxingCheck(state, tree.getExpression()); } + Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); + if (assigned != null && codeAnnotationInfo.isSymbolUnannotated(assigned, config, handler)) { + // assigning to symbol that is unannotated + return Description.NO_MATCH; + } // generics check if (lhsType != null && config.isJSpecifyMode()) { GenericsChecks.checkTypeParameterNullnessForAssignability(tree, this, state); @@ -508,7 +513,6 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { } } - Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); if (assigned == null || assigned.getKind() != ElementKind.FIELD) { // not a field of nullable type return Description.NO_MATCH; diff --git a/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericsTests.java index 7585c85657..ac749a7afc 100644 --- a/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericsTests.java @@ -2045,6 +2045,30 @@ public void issue1093() { .doTest(); } + @Test + public void nullUnmarkedGenericField() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.unannotated;", + "import org.jspecify.annotations.*;", + "import java.util.function.Function;", + "public class Test {", + " static Function<@Nullable String, @Nullable String> foo;", + " @NullMarked", + " static class Inner {", + " static @Nullable Function<@Nullable String, @Nullable String> bar;", + " void bar(Function f) {", + " // no error since foo is in @NullUnmarked code", + " foo = f;", + " // BUG: Diagnostic contains: Cannot assign from type Function", + " bar = f;", + " }", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( diff --git a/nullaway/src/test/java/com/uber/nullaway/jspecify/NullMarkednessTests.java b/nullaway/src/test/java/com/uber/nullaway/jspecify/NullMarkednessTests.java index 705aa8180d..34feb6f7e5 100644 --- a/nullaway/src/test/java/com/uber/nullaway/jspecify/NullMarkednessTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/jspecify/NullMarkednessTests.java @@ -1173,4 +1173,25 @@ public void nullUnmarkedOnConstructorSuppressesInitializerWarnings() { "}") .doTest(); } + + @Test + public void writeToNullUnmarkedField() { + defaultCompilationHelper + .addSourceLines( + "Test.java", + "package com.unannotated;", + "import org.jspecify.annotations.NullMarked;", + "public class Test {", + " static Object foo;", + " @NullMarked", + " static class Inner {", + " String bar() {", + " // expecting no errors since foo is in @NullUnmarked code", + " foo = null;", + " return foo.toString();", + " }", + " }", + "}") + .doTest(); + } }