Skip to content

Commit

Permalink
enable jspecify mode in nullaway for stricter null checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-manes committed Nov 23, 2024
1 parent 5282cc2 commit 6e3ff70
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2095,10 +2095,10 @@ public void clear() {
@SuppressWarnings("GuardedByChecker")
void removeNode(Node<K, V> node, long now) {
K key = node.getKey();
@SuppressWarnings("unchecked")
var value = (V[]) new Object[1];
var cause = new RemovalCause[1];
var keyReference = node.getKeyReference();
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] value = (V[]) new Object[1];

data.computeIfPresent(keyReference, (k, n) -> {
if (n != node) {
Expand Down Expand Up @@ -2437,8 +2437,8 @@ public void putAll(Map<? extends K, ? extends V> map) {
var castKey = (K) key;
@SuppressWarnings({"rawtypes", "unchecked"})
Node<K, V>[] node = new Node[1];
@SuppressWarnings("unchecked")
var oldValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
RemovalCause[] cause = new RemovalCause[1];
Object lookupKey = nodeFactory.newLookupKey(key);

Expand Down Expand Up @@ -2479,10 +2479,10 @@ public boolean remove(Object key, Object value) {

@SuppressWarnings({"rawtypes", "unchecked"})
Node<K, V>[] removed = new Node[1];
@SuppressWarnings("unchecked")
var oldKey = (K[]) new Object[1];
@SuppressWarnings("unchecked")
var oldValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable K[] oldKey = (K[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
RemovalCause[] cause = new RemovalCause[1];
Object lookupKey = nodeFactory.newLookupKey(key);

Expand Down Expand Up @@ -2526,10 +2526,10 @@ public boolean remove(Object key, Object value) {

long[] now = new long[1];
var oldWeight = new int[1];
@SuppressWarnings("unchecked")
var nodeKey = (K[]) new Object[1];
@SuppressWarnings("unchecked")
var oldValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable K[] nodeKey = (K[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
int weight = weigher.weigh(key, value);
Node<K, V> node = data.computeIfPresent(nodeFactory.newLookupKey(key), (k, n) -> {
synchronized (n) {
Expand All @@ -2555,7 +2555,7 @@ public boolean remove(Object key, Object value) {
}
});

if (oldValue[0] == null) {
if ((nodeKey[0] == null) || (oldValue[0] == null)) {
return null;
}

Expand All @@ -2582,11 +2582,10 @@ public boolean replace(K key, V oldValue, V newValue, boolean shouldDiscardRefre
requireNonNull(newValue);

int weight = weigher.weigh(key, newValue);
boolean[] replaced = new boolean[1];
@SuppressWarnings("unchecked")
var nodeKey = (K[]) new Object[1];
@SuppressWarnings("unchecked")
var prevValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable K[] nodeKey = (K[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] prevValue = (V[]) new Object[1];
int[] oldWeight = new int[1];
long[] now = new long[1];
Node<K, V> node = data.computeIfPresent(nodeFactory.newLookupKey(key), (k, n) -> {
Expand All @@ -2597,6 +2596,7 @@ public boolean replace(K key, V oldValue, V newValue, boolean shouldDiscardRefre
oldWeight[0] = n.getWeight();
if ((nodeKey[0] == null) || (prevValue[0] == null) || !n.containsValue(oldValue)
|| hasExpired(n, now[0] = expirationTicker().read())) {
prevValue[0] = null;
return n;
}

Expand All @@ -2607,7 +2607,6 @@ public boolean replace(K key, V oldValue, V newValue, boolean shouldDiscardRefre
setVariableTime(n, varTime);
setAccessTime(n, now[0]);
setWriteTime(n, now[0]);
replaced[0] = true;

if (shouldDiscardRefresh) {
discardRefresh(k);
Expand All @@ -2616,7 +2615,7 @@ public boolean replace(K key, V oldValue, V newValue, boolean shouldDiscardRefre
return n;
});

if (!replaced[0]) {
if ((nodeKey[0] == null) || (prevValue[0] == null)) {
return false;
}

Expand Down Expand Up @@ -2673,13 +2672,14 @@ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {

/** Returns the current value from a computeIfAbsent invocation. */
@Nullable V doComputeIfAbsent(K key, Object keyRef,
Function<? super K, ? extends V> mappingFunction, long[/* 1 */] now, boolean recordStats) {
@SuppressWarnings("unchecked")
var oldValue = (V[]) new Object[1];
@SuppressWarnings("unchecked")
var newValue = (V[]) new Object[1];
@SuppressWarnings("unchecked")
var nodeKey = (K[]) new Object[1];
Function<? super K, ? extends @Nullable V> mappingFunction, long[/* 1 */] now,
boolean recordStats) {
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] newValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable K[] nodeKey = (K[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked"})
Node<K, V>[] removed = new Node[1];

Expand Down Expand Up @@ -2838,14 +2838,14 @@ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
*/
@SuppressWarnings("PMD.EmptyControlStatement")
@Nullable V remap(K key, Object keyRef,
BiFunction<? super K, ? super V, ? extends V> remappingFunction,
BiFunction<? super K, ? super V, ? extends @Nullable V> remappingFunction,
Expiry<? super K, ? super V> expiry, long[/* 1 */] now, boolean computeIfAbsent) {
@SuppressWarnings("unchecked")
var nodeKey = (K[]) new Object[1];
@SuppressWarnings("unchecked")
var oldValue = (V[]) new Object[1];
@SuppressWarnings("unchecked")
var newValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable K[] nodeKey = (K[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] newValue = (V[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked"})
Node<K, V>[] removed = new Node[1];

Expand Down Expand Up @@ -2929,6 +2929,7 @@ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {

if (cause[0] != null) {
if (cause[0] == RemovalCause.REPLACED) {
requireNonNull(newValue[0]);
notifyOnReplace(key, oldValue[0], newValue[0]);
} else {
if (cause[0].wasEvicted()) {
Expand Down Expand Up @@ -3186,7 +3187,8 @@ <T> T snapshot(Iterable<Node<K, V>> iterable, Function<V, V> transformer,
}

/** Returns an entry for the given node if it can be used externally, else null. */
@Nullable CacheEntry<K, V> nodeToCacheEntry(Node<K, V> node, Function<V, V> transformer) {
@Nullable CacheEntry<K, V> nodeToCacheEntry(
Node<K, V> node, Function<@Nullable V, @Nullable V> transformer) {
V value = transformer.apply(node.getValue());
K key = node.getKey();
long now;
Expand Down Expand Up @@ -3980,8 +3982,8 @@ private Object writeReplace() {

@SuppressWarnings({"NullableOptional", "OptionalAssignedToNull"})
static final class BoundedPolicy<K, V> implements Policy<K, V> {
final Function<@Nullable V, @Nullable V> transformer;
final BoundedLocalCache<K, V> cache;
final Function<V, V> transformer;
final boolean isWeighted;

@Nullable Optional<Eviction<K, V>> eviction;
Expand All @@ -3990,7 +3992,8 @@ static final class BoundedPolicy<K, V> implements Policy<K, V> {
@Nullable Optional<FixedExpiration<K, V>> afterAccess;
@Nullable Optional<VarExpiration<K, V>> variable;

BoundedPolicy(BoundedLocalCache<K, V> cache, Function<V, V> transformer, boolean isWeighted) {
BoundedPolicy(BoundedLocalCache<K, V> cache,
Function<@Nullable V, @Nullable V> transformer, boolean isWeighted) {
this.transformer = transformer;
this.isWeighted = isWeighted;
this.cache = cache;
Expand Down Expand Up @@ -4523,7 +4526,7 @@ public Policy<K, V> policy() {
if (policy == null) {
@SuppressWarnings("unchecked")
var castCache = (BoundedLocalCache<K, V>) cache;
Function<CompletableFuture<V>, V> transformer = Async::getIfReady;
Function<CompletableFuture<V>, @Nullable V> transformer = Async::getIfReady;
@SuppressWarnings("unchecked")
var castTransformer = (Function<V, V>) transformer;
policy = new BoundedPolicy<>(castCache, castTransformer, isWeighted);
Expand Down Expand Up @@ -4575,7 +4578,7 @@ public Policy<K, V> policy() {
if (policy == null) {
@SuppressWarnings("unchecked")
var castCache = (BoundedLocalCache<K, V>) cache;
Function<CompletableFuture<V>, V> transformer = Async::getIfReady;
Function<CompletableFuture<V>, @Nullable V> transformer = Async::getIfReady;
@SuppressWarnings("unchecked")
var castTransformer = (Function<V, V>) transformer;
policy = new BoundedPolicy<>(castCache, castTransformer, isWeighted);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,12 @@ public boolean replace(K key, CompletableFuture<V> oldValue, CompletableFuture<V
}
return future;
}
@Override public CompletableFuture<V> computeIfPresent(K key, BiFunction<? super K,
@Override public @Nullable CompletableFuture<V> computeIfPresent(K key, BiFunction<? super K,
? super CompletableFuture<V>, ? extends CompletableFuture<V>> remappingFunction) {
requireNonNull(remappingFunction);

@SuppressWarnings({"rawtypes", "unchecked"})
CompletableFuture<V>[] result = new CompletableFuture[1];
@Nullable CompletableFuture<V>[] result = new CompletableFuture[1];
long startTime = asyncCache.cache().statsTicker().read();
asyncCache.cache().compute(key, (k, oldValue) -> {
result[0] = (oldValue == null) ? null : remappingFunction.apply(k, oldValue);
Expand Down Expand Up @@ -796,8 +796,8 @@ public boolean remove(Object key, Object value) {
public @Nullable V replace(K key, V value) {
requireNonNull(value);

@SuppressWarnings({"rawtypes", "unchecked"})
var oldValue = (V[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
boolean[] done = { false };
for (;;) {
CompletableFuture<V> future = delegate.getIfPresentQuietly(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ public CompletableFuture<Map<K, V>> refreshAll(Iterable<? extends K> keys) {
long[] startTime = new long[1];
boolean[] refreshed = new boolean[1];
@SuppressWarnings({"rawtypes", "unchecked"})
CompletableFuture<V>[] oldValueFuture = new CompletableFuture[1];
@Nullable CompletableFuture<V>[] oldValueFuture = new CompletableFuture[1];
var future = asyncCache.cache().refreshes().computeIfAbsent(keyReference, k -> {
oldValueFuture[0] = asyncCache.cache().getIfPresentQuietly(key);
V oldValue = Async.getIfReady(oldValueFuture[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ default void invalidateAll(Iterable<?> keys) {

/** Notify the removal listener of a replacement if the value reference was changed. */
@SuppressWarnings("FutureReturnValueIgnored")
default void notifyOnReplace(K key, V oldValue, V newValue) {
default void notifyOnReplace(K key, @Nullable V oldValue, V newValue) {
if ((oldValue == null) || (oldValue == newValue)) {
return;
} else if (isAsync()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ default CompletableFuture<V> refresh(K key) {
requireNonNull(key);

long[] startTime = new long[1];
@SuppressWarnings("unchecked")
var oldValue = (V[]) new Object[1];
@SuppressWarnings({"unchecked", "Varifier"})
@Nullable V[] oldValue = (V[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked"})
CompletableFuture<? extends V>[] reloading = new CompletableFuture[1];
Object keyReference = cache().referenceKey(key);
Expand Down Expand Up @@ -179,7 +179,7 @@ default CompletableFuture<Map<K, V>> refreshAll(Iterable<? extends K> keys) {
}

/** Returns a mapping function that adapts to {@link CacheLoader#load}. */
static <K, V> Function<K, V> newMappingFunction(CacheLoader<? super K, V> cacheLoader) {
static <K, V> Function<K, @Nullable V> newMappingFunction(CacheLoader<? super K, V> cacheLoader) {
return key -> {
try {
return cacheLoader.load(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
requireNonNull(function);

// ensures that the removal notification is processed after the removal has completed
@SuppressWarnings({"rawtypes", "unchecked"})
var notificationKey = (K[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked"})
var notificationValue = (V[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked", "Varifier"})
@Nullable K[] notificationKey = (K[]) new Object[1];
@SuppressWarnings({"rawtypes", "unchecked", "Varifier"})
@Nullable V[] notificationValue = (V[]) new Object[1];
data.replaceAll((key, value) -> {
if (notificationKey[0] != null) {
notifyRemoval(notificationKey[0], notificationValue[0], RemovalCause.REPLACED);
Expand Down Expand Up @@ -1060,10 +1060,11 @@ Object writeReplace() {

/** An eviction policy that supports no bounding. */
static final class UnboundedPolicy<K, V> implements Policy<K, V> {
final Function<@Nullable V, @Nullable V> transformer;
final UnboundedLocalCache<K, V> cache;
final Function<V, V> transformer;

UnboundedPolicy(UnboundedLocalCache<K, V> cache, Function<V, V> transformer) {
UnboundedPolicy(UnboundedLocalCache<K, V> cache,
Function<@Nullable V, @Nullable V> transformer) {
this.transformer = transformer;
this.cache = cache;
}
Expand Down Expand Up @@ -1187,7 +1188,7 @@ public Cache<K, V> synchronous() {
public Policy<K, V> policy() {
@SuppressWarnings("unchecked")
var castCache = (UnboundedLocalCache<K, V>) cache;
Function<CompletableFuture<V>, V> transformer = Async::getIfReady;
Function<CompletableFuture<V>, @Nullable V> transformer = Async::getIfReady;
@SuppressWarnings("unchecked")
var castTransformer = (Function<V, V>) transformer;
return (policy == null)
Expand Down Expand Up @@ -1240,7 +1241,7 @@ public ConcurrentMap<K, CompletableFuture<V>> asMap() {
public Policy<K, V> policy() {
@SuppressWarnings("unchecked")
var castCache = (UnboundedLocalCache<K, V>) cache;
Function<CompletableFuture<V>, V> transformer = Async::getIfReady;
Function<CompletableFuture<V>, @Nullable V> transformer = Async::getIfReady;
@SuppressWarnings("unchecked")
var castTransformer = (Function<V, V>) transformer;
return (policy == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ tasks.withType<JavaCompile>().configureEach {
checkOptionalEmptiness = true
suggestSuppressions = true
checkContracts = true
isJSpecifyMode = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,10 @@ private boolean isReadThrough() {

/** Creates a cache that does not read through on a cache miss. */
private CacheProxy<K, V> newCacheProxy() {
Optional<CacheLoader<K, V>> cacheLoader =
Optional.ofNullable(config.getCacheLoaderFactory()).map(Factory::create);
var cacheLoaderFactory = config.getCacheLoaderFactory();
var cacheLoader = (cacheLoaderFactory == null) ? null : cacheLoaderFactory.create();
return new CacheProxy<>(cacheName, executor, cacheManager, config, caffeine.build(),
dispatcher, cacheLoader, expiryPolicy, ticker, statistics);
dispatcher, Optional.ofNullable(cacheLoader), expiryPolicy, ticker, statistics);
}

/** Creates a cache that reads through on a cache miss. */
Expand Down

0 comments on commit 6e3ff70

Please sign in to comment.