From ad8f5adecbda1b9b662742799dca38a6cfc31663 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Fri, 15 Dec 2023 10:46:50 -0800 Subject: [PATCH] Make our nullness checking work with an Android bootclasspath. This involves accommodating a bug and a shortcoming in our checker and a bug and a design decision in Android's nullness annotations. RELNOTES=n/a PiperOrigin-RevId: 591300398 --- .../guava/src/com/google/common/base/Joiner.java | 13 ++++++++++--- .../src/com/google/common/escape/Platform.java | 5 ++++- .../src/com/google/common/eventbus/Dispatcher.java | 4 +++- .../src/com/google/common/net/InetAddresses.java | 4 +++- .../util/concurrent/CycleDetectingLockFactory.java | 6 ++++-- guava/src/com/google/common/base/Joiner.java | 13 ++++++++++--- guava/src/com/google/common/escape/Platform.java | 5 ++++- .../src/com/google/common/eventbus/Dispatcher.java | 4 +++- guava/src/com/google/common/net/InetAddresses.java | 4 +++- .../util/concurrent/CycleDetectingLockFactory.java | 6 ++++-- 10 files changed, 48 insertions(+), 16 deletions(-) diff --git a/android/guava/src/com/google/common/base/Joiner.java b/android/guava/src/com/google/common/base/Joiner.java index fe1b40a5e073e..acb7d8d12fc87 100644 --- a/android/guava/src/com/google/common/base/Joiner.java +++ b/android/guava/src/com/google/common/base/Joiner.java @@ -23,6 +23,7 @@ import java.util.AbstractList; import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.annotation.CheckForNull; @@ -129,7 +130,9 @@ public A appendTo(A appendable, Iterator A appendTo(A appendable, @Nullable Object[] parts) throws IOException { - return appendTo(appendable, Arrays.asList(parts)); + @SuppressWarnings("nullness") // TODO: b/316358623 - Remove suppression after fixing checker + List partsList = Arrays.<@Nullable Object>asList(parts); + return appendTo(appendable, partsList); } /** Appends to {@code appendable} the string representation of each of the remaining arguments. */ @@ -179,7 +182,9 @@ public final StringBuilder appendTo( */ @CanIgnoreReturnValue public final StringBuilder appendTo(StringBuilder builder, @Nullable Object[] parts) { - return appendTo(builder, Arrays.asList(parts)); + @SuppressWarnings("nullness") // TODO: b/316358623 - Remove suppression after fixing checker + List partsList = Arrays.<@Nullable Object>asList(parts); + return appendTo(builder, partsList); } /** @@ -219,7 +224,9 @@ public final String join(Iterator parts) { * previously configured separator between each. */ public final String join(@Nullable Object[] parts) { - return join(Arrays.asList(parts)); + @SuppressWarnings("nullness") // TODO: b/316358623 - Remove suppression after fixing checker + List partsList = Arrays.<@Nullable Object>asList(parts); + return join(partsList); } /** diff --git a/android/guava/src/com/google/common/escape/Platform.java b/android/guava/src/com/google/common/escape/Platform.java index dc6610c041bbd..67efe4551e5fe 100644 --- a/android/guava/src/com/google/common/escape/Platform.java +++ b/android/guava/src/com/google/common/escape/Platform.java @@ -14,6 +14,8 @@ package com.google.common.escape; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.GwtCompatible; /** @@ -28,7 +30,8 @@ private Platform() {} /** Returns a thread-local 1024-char array. */ static char[] charBufferFromThreadLocal() { - return DEST_TL.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + return requireNonNull(DEST_TL.get()); } /** diff --git a/android/guava/src/com/google/common/eventbus/Dispatcher.java b/android/guava/src/com/google/common/eventbus/Dispatcher.java index 412bb789eceab..44f7c46ba0cd4 100644 --- a/android/guava/src/com/google/common/eventbus/Dispatcher.java +++ b/android/guava/src/com/google/common/eventbus/Dispatcher.java @@ -15,6 +15,7 @@ package com.google.common.eventbus; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.collect.Queues; import java.util.Iterator; @@ -97,7 +98,8 @@ protected Boolean initialValue() { void dispatch(Object event, Iterator subscribers) { checkNotNull(event); checkNotNull(subscribers); - Queue queueForThread = queue.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + Queue queueForThread = requireNonNull(queue.get()); queueForThread.offer(new Event(event, subscribers)); if (!dispatching.get()) { diff --git a/android/guava/src/com/google/common/net/InetAddresses.java b/android/guava/src/com/google/common/net/InetAddresses.java index 6d83093812d91..540a21986a6f0 100644 --- a/android/guava/src/com/google/common/net/InetAddresses.java +++ b/android/guava/src/com/google/common/net/InetAddresses.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.J2ktIncompatible; @@ -409,7 +410,8 @@ public static String toAddrString(InetAddress ip) { checkNotNull(ip); if (ip instanceof Inet4Address) { // For IPv4, Java's formatting is good enough. - return ip.getHostAddress(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on getHostAddress + return requireNonNull(ip.getHostAddress()); } checkArgument(ip instanceof Inet6Address); byte[] bytes = ip.getAddress(); diff --git a/android/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/android/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java index 331913b170bb6..6e2ae47a3c735 100644 --- a/android/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java +++ b/android/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java @@ -710,7 +710,8 @@ private ExampleStackTrace findPathTo(LockGraphNode node, Set seen */ private void aboutToAcquire(CycleDetectingLock lock) { if (!lock.isAcquiredByCurrentThread()) { - ArrayList acquiredLockList = acquiredLocks.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + ArrayList acquiredLockList = requireNonNull(acquiredLocks.get()); LockGraphNode node = lock.getLockGraphNode(); node.checkAcquiredLocks(policy, acquiredLockList); acquiredLockList.add(node); @@ -724,7 +725,8 @@ private void aboutToAcquire(CycleDetectingLock lock) { */ private static void lockStateChanged(CycleDetectingLock lock) { if (!lock.isAcquiredByCurrentThread()) { - ArrayList acquiredLockList = acquiredLocks.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + ArrayList acquiredLockList = requireNonNull(acquiredLocks.get()); LockGraphNode node = lock.getLockGraphNode(); // Iterate in reverse because locks are usually locked/unlocked in a // LIFO order. diff --git a/guava/src/com/google/common/base/Joiner.java b/guava/src/com/google/common/base/Joiner.java index fe1b40a5e073e..acb7d8d12fc87 100644 --- a/guava/src/com/google/common/base/Joiner.java +++ b/guava/src/com/google/common/base/Joiner.java @@ -23,6 +23,7 @@ import java.util.AbstractList; import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.annotation.CheckForNull; @@ -129,7 +130,9 @@ public A appendTo(A appendable, Iterator A appendTo(A appendable, @Nullable Object[] parts) throws IOException { - return appendTo(appendable, Arrays.asList(parts)); + @SuppressWarnings("nullness") // TODO: b/316358623 - Remove suppression after fixing checker + List partsList = Arrays.<@Nullable Object>asList(parts); + return appendTo(appendable, partsList); } /** Appends to {@code appendable} the string representation of each of the remaining arguments. */ @@ -179,7 +182,9 @@ public final StringBuilder appendTo( */ @CanIgnoreReturnValue public final StringBuilder appendTo(StringBuilder builder, @Nullable Object[] parts) { - return appendTo(builder, Arrays.asList(parts)); + @SuppressWarnings("nullness") // TODO: b/316358623 - Remove suppression after fixing checker + List partsList = Arrays.<@Nullable Object>asList(parts); + return appendTo(builder, partsList); } /** @@ -219,7 +224,9 @@ public final String join(Iterator parts) { * previously configured separator between each. */ public final String join(@Nullable Object[] parts) { - return join(Arrays.asList(parts)); + @SuppressWarnings("nullness") // TODO: b/316358623 - Remove suppression after fixing checker + List partsList = Arrays.<@Nullable Object>asList(parts); + return join(partsList); } /** diff --git a/guava/src/com/google/common/escape/Platform.java b/guava/src/com/google/common/escape/Platform.java index dc6610c041bbd..67efe4551e5fe 100644 --- a/guava/src/com/google/common/escape/Platform.java +++ b/guava/src/com/google/common/escape/Platform.java @@ -14,6 +14,8 @@ package com.google.common.escape; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.GwtCompatible; /** @@ -28,7 +30,8 @@ private Platform() {} /** Returns a thread-local 1024-char array. */ static char[] charBufferFromThreadLocal() { - return DEST_TL.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + return requireNonNull(DEST_TL.get()); } /** diff --git a/guava/src/com/google/common/eventbus/Dispatcher.java b/guava/src/com/google/common/eventbus/Dispatcher.java index 412bb789eceab..44f7c46ba0cd4 100644 --- a/guava/src/com/google/common/eventbus/Dispatcher.java +++ b/guava/src/com/google/common/eventbus/Dispatcher.java @@ -15,6 +15,7 @@ package com.google.common.eventbus; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.collect.Queues; import java.util.Iterator; @@ -97,7 +98,8 @@ protected Boolean initialValue() { void dispatch(Object event, Iterator subscribers) { checkNotNull(event); checkNotNull(subscribers); - Queue queueForThread = queue.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + Queue queueForThread = requireNonNull(queue.get()); queueForThread.offer(new Event(event, subscribers)); if (!dispatching.get()) { diff --git a/guava/src/com/google/common/net/InetAddresses.java b/guava/src/com/google/common/net/InetAddresses.java index 6d83093812d91..540a21986a6f0 100644 --- a/guava/src/com/google/common/net/InetAddresses.java +++ b/guava/src/com/google/common/net/InetAddresses.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.J2ktIncompatible; @@ -409,7 +410,8 @@ public static String toAddrString(InetAddress ip) { checkNotNull(ip); if (ip instanceof Inet4Address) { // For IPv4, Java's formatting is good enough. - return ip.getHostAddress(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on getHostAddress + return requireNonNull(ip.getHostAddress()); } checkArgument(ip instanceof Inet6Address); byte[] bytes = ip.getAddress(); diff --git a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java index 331913b170bb6..6e2ae47a3c735 100644 --- a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java +++ b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java @@ -710,7 +710,8 @@ private ExampleStackTrace findPathTo(LockGraphNode node, Set seen */ private void aboutToAcquire(CycleDetectingLock lock) { if (!lock.isAcquiredByCurrentThread()) { - ArrayList acquiredLockList = acquiredLocks.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + ArrayList acquiredLockList = requireNonNull(acquiredLocks.get()); LockGraphNode node = lock.getLockGraphNode(); node.checkAcquiredLocks(policy, acquiredLockList); acquiredLockList.add(node); @@ -724,7 +725,8 @@ private void aboutToAcquire(CycleDetectingLock lock) { */ private static void lockStateChanged(CycleDetectingLock lock) { if (!lock.isAcquiredByCurrentThread()) { - ArrayList acquiredLockList = acquiredLocks.get(); + // requireNonNull accommodates Android's @RecentlyNullable annotation on ThreadLocal.get + ArrayList acquiredLockList = requireNonNull(acquiredLocks.get()); LockGraphNode node = lock.getLockGraphNode(); // Iterate in reverse because locks are usually locked/unlocked in a // LIFO order.