From 2754c4547d3afcdef5633b69a57bb60ef86b42e7 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sun, 22 Dec 2024 13:22:17 -0500 Subject: [PATCH] Report error for @Nullable synchronized block expression (#1106) --- .../jmh/BenchmarkCompilationTest.java | 2 ++ .../main/java/com/uber/nullaway/NullAway.java | 25 ++++++++++++++++++- .../java/com/uber/nullaway/CoreTests.java | 19 ++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java b/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java index d9adff9e46..02596d8e5f 100644 --- a/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java +++ b/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; +import org.junit.Ignore; import org.junit.Test; /** Tests that all our JMH benchmarks compile successfully */ @@ -14,6 +15,7 @@ public void testAutodispose() throws IOException { } @Test + @Ignore("Need to update caffeine version; https://github.com/uber/NullAway/issues/1108") public void testCaffeine() throws IOException { assertTrue(new CaffeineCompiler().compile()); } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index d381e11909..8611cade8c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -82,6 +82,7 @@ import com.sun.source.tree.ReturnTree; import com.sun.source.tree.StatementTree; import com.sun.source.tree.SwitchTree; +import com.sun.source.tree.SynchronizedTree; import com.sun.source.tree.Tree; import com.sun.source.tree.TryTree; import com.sun.source.tree.TypeCastTree; @@ -186,7 +187,8 @@ public class NullAway extends BugChecker BugChecker.CompoundAssignmentTreeMatcher, BugChecker.SwitchTreeMatcher, BugChecker.TypeCastTreeMatcher, - BugChecker.ParameterizedTypeTreeMatcher { + BugChecker.ParameterizedTypeTreeMatcher, + BugChecker.SynchronizedTreeMatcher { static final String INITIALIZATION_CHECK_NAME = "NullAway.Init"; static final String OPTIONAL_CHECK_NAME = "NullAway.Optional"; @@ -1768,6 +1770,27 @@ public Description matchEnhancedForLoop(EnhancedForLoopTree tree, VisitorState s return Description.NO_MATCH; } + @Override + public Description matchSynchronized(SynchronizedTree tree, VisitorState state) { + ExpressionTree lockExpr = tree.getExpression(); + // For a synchronized block `synchronized (e) { ... }`, javac returns `(e)` as the expression. + // We strip the outermost parentheses for a nicer-looking error message. + if (lockExpr instanceof ParenthesizedTree) { + lockExpr = ((ParenthesizedTree) lockExpr).getExpression(); + } + if (mayBeNullExpr(state, lockExpr)) { + ErrorMessage errorMessage = + new ErrorMessage( + MessageTypes.DEREFERENCE_NULLABLE, + "synchronized block expression \"" + + state.getSourceForNode(lockExpr) + + "\" is @Nullable"); + return errorBuilder.createErrorDescription( + errorMessage, buildDescription(lockExpr), state, null); + } + return Description.NO_MATCH; + } + /** * Checks that all given expressions cannot be null, and for those that are {@code @Nullable}, * reports an unboxing error. diff --git a/nullaway/src/test/java/com/uber/nullaway/CoreTests.java b/nullaway/src/test/java/com/uber/nullaway/CoreTests.java index 0cf3237dd9..f475b37128 100644 --- a/nullaway/src/test/java/com/uber/nullaway/CoreTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/CoreTests.java @@ -1071,4 +1071,23 @@ public void ternaryBothCasesNull() { "}") .doTest(); } + + @Test + public void synchronizedDeref() { + defaultCompilationHelper + .addSourceLines( + "TestCase.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "public class TestCase {", + " public static void testPositive(@Nullable Object lock) {", + " // BUG: Diagnostic contains: synchronized block expression \"lock\" is @Nullable", + " synchronized (lock) {}", + " }", + " public static void testNegative(Object lock) {", + " synchronized (lock) {}", + " }", + "}") + .doTest(); + } }