Skip to content

Commit

Permalink
Annotate TypeToInstanceMap classes for nullness.
Browse files Browse the repository at this point in the history
I believe these are the only user-facing classes that I missed (aside from some annotations, which don't need nullness annotations). I must have intended to pick them up after `ClassToInstanceMap`, but I completely forgot. I noticed only when I tried to remove our checker-compat-qual dependency.

After this, I may send another CL to change some checker-compat-qual annotations into checker-qual and jsr305 annotations so that we can at least remove that dependency.

RELNOTES=n/a
PiperOrigin-RevId: 399322975
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed Sep 28, 2021
1 parent 5d57f75 commit 7a603a9
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 32 deletions.
Expand Up @@ -20,6 +20,7 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotCall;
import java.util.Map;
import javax.annotation.CheckForNull;

/**
* A type-to-instance map backed by an {@link ImmutableMap}. See also {@link
Expand All @@ -29,6 +30,7 @@
* @since 13.0
*/
@Beta
@ElementTypesAreNonnullByDefault
public final class ImmutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
implements TypeToInstanceMap<B> {

Expand Down Expand Up @@ -102,11 +104,13 @@ private ImmutableTypeToInstanceMap(ImmutableMap<TypeToken<? extends B>, B> deleg
}

@Override
@CheckForNull
public <T extends B> T getInstance(TypeToken<T> type) {
return trustedGet(type.rejectTypeVariables());
}

@Override
@CheckForNull
public <T extends B> T getInstance(Class<T> type) {
return trustedGet(TypeToken.of(type));
}
Expand All @@ -121,6 +125,7 @@ public <T extends B> T getInstance(Class<T> type) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public <T extends B> T putInstance(TypeToken<T> type, T value) {
throw new UnsupportedOperationException();
}
Expand All @@ -135,6 +140,7 @@ public <T extends B> T putInstance(TypeToken<T> type, T value) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public <T extends B> T putInstance(Class<T> type, T value) {
throw new UnsupportedOperationException();
}
Expand All @@ -149,6 +155,7 @@ public <T extends B> T putInstance(Class<T> type, T value) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public B put(TypeToken<? extends B> key, B value) {
throw new UnsupportedOperationException();
}
Expand All @@ -172,6 +179,7 @@ protected Map<TypeToken<? extends B>, B> delegate() {
}

@SuppressWarnings("unchecked") // value could not get in if not a T
@CheckForNull
private <T extends B> T trustedGet(TypeToken<T> type) {
return (T) delegate.get(type);
}
Expand Down
Expand Up @@ -28,43 +28,48 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* A mutable type-to-instance map. See also {@link ImmutableTypeToInstanceMap}.
*
* <p>This implementation <i>does</i> support null values, despite how it is annotated; see
* discussion at {@link TypeToInstanceMap}.
*
* @author Ben Yu
* @since 13.0
*/
@Beta
@ElementTypesAreNonnullByDefault
public final class MutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
implements TypeToInstanceMap<B> {

private final Map<TypeToken<? extends B>, B> backingMap = Maps.newHashMap();

@Override
@NullableDecl
@CheckForNull
public <T extends B> T getInstance(Class<T> type) {
return trustedGet(TypeToken.of(type));
}

@Override
@NullableDecl
@CheckForNull
public <T extends B> T getInstance(TypeToken<T> type) {
return trustedGet(type.rejectTypeVariables());
}

@Override
@CanIgnoreReturnValue
@NullableDecl
public <T extends B> T putInstance(Class<T> type, @NullableDecl T value) {
@CheckForNull
public <T extends B> T putInstance(Class<T> type, T value) {
return trustedPut(TypeToken.of(type), value);
}

@Override
@CanIgnoreReturnValue
@NullableDecl
public <T extends B> T putInstance(TypeToken<T> type, @NullableDecl T value) {
@CheckForNull
public <T extends B> T putInstance(TypeToken<T> type, T value) {
return trustedPut(type.rejectTypeVariables(), value);
}

Expand All @@ -78,6 +83,7 @@ public <T extends B> T putInstance(TypeToken<T> type, @NullableDecl T value) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public B put(TypeToken<? extends B> key, B value) {
throw new UnsupportedOperationException("Please use putInstance() instead.");
}
Expand Down Expand Up @@ -106,13 +112,13 @@ protected Map<TypeToken<? extends B>, B> delegate() {
}

@SuppressWarnings("unchecked") // value could not get in if not a T
@NullableDecl
private <T extends B> T trustedPut(TypeToken<T> type, @NullableDecl T value) {
@CheckForNull
private <T extends B> T trustedPut(TypeToken<T> type, T value) {
return (T) backingMap.put(type, value);
}

@SuppressWarnings("unchecked") // value could not get in if not a T
@NullableDecl
@CheckForNull
private <T extends B> T trustedGet(TypeToken<T> type) {
return (T) backingMap.get(type);
}
Expand All @@ -135,11 +141,20 @@ public Iterator<Entry<K, V>> iterator() {

@Override
public Object[] toArray() {
return standardToArray();
/*
* standardToArray returns `@Nullable Object[]` rather than `Object[]` but only because it
* can be used with collections that may contain null. This collection is a collection of
* non-null Entry objects (Entry objects that might contain null values but are not
* themselves null), so we can treat it as a plain `Object[]`.
*/
@SuppressWarnings("nullness")
Object[] result = standardToArray();
return result;
}

@Override
public <T> T[] toArray(T[] array) {
@SuppressWarnings("nullness") // b/192354773 in our checker affects toArray declarations
public <T extends @Nullable Object> T[] toArray(T[] array) {
return standardToArray(array);
}
};
Expand Down
18 changes: 11 additions & 7 deletions android/guava/src/com/google/common/reflect/TypeToInstanceMap.java
Expand Up @@ -18,7 +18,7 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotMock;
import java.util.Map;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import javax.annotation.CheckForNull;

/**
* A map, each entry of which maps a {@link TypeToken} to an instance of that type. In addition to
Expand All @@ -35,12 +35,16 @@
* <p>Like any other {@code Map<Class, Object>}, this map may contain entries for primitive types,
* and a primitive type and its corresponding wrapper type may map to different values.
*
* <p>This class's support for {@code null} requires some explanation. For details, see {@link
* ClassToInstanceMap}. Its explanation applies equally well to {@code TypeToInstanceMap}.
*
* @param <B> the common supertype that all entries must share; often this is simply {@link Object}
* @author Ben Yu
* @since 13.0
*/
@Beta
@DoNotMock("Use ImmutableTypeToInstanceMap or MutableTypeToInstanceMap")
@ElementTypesAreNonnullByDefault
public interface TypeToInstanceMap<B> extends Map<TypeToken<? extends B>, B> {

/**
Expand All @@ -51,15 +55,15 @@ public interface TypeToInstanceMap<B> extends Map<TypeToken<? extends B>, B> {
* <p>{@code getInstance(Foo.class)} is equivalent to {@code
* getInstance(TypeToken.of(Foo.class))}.
*/
@NullableDecl
@CheckForNull
<T extends B> T getInstance(Class<T> type);

/**
* Returns the value the specified type is mapped to, or {@code null} if no entry for this type is
* present. This will only return a value that was bound to this specific type, not a value that
* may have been bound to a subtype.
*/
@NullableDecl
@CheckForNull
<T extends B> T getInstance(TypeToken<T> type);

/**
Expand All @@ -73,8 +77,8 @@ public interface TypeToInstanceMap<B> extends Map<TypeToken<? extends B>, B> {
* null} if there was no previous entry.
*/
@CanIgnoreReturnValue
@NullableDecl
<T extends B> T putInstance(Class<T> type, @NullableDecl T value);
@CheckForNull
<T extends B> T putInstance(Class<T> type, T value);

/**
* Maps the specified type to the specified value. Does <i>not</i> associate this value with any
Expand All @@ -84,6 +88,6 @@ public interface TypeToInstanceMap<B> extends Map<TypeToken<? extends B>, B> {
* if there was no previous entry.
*/
@CanIgnoreReturnValue
@NullableDecl
<T extends B> T putInstance(TypeToken<T> type, @NullableDecl T value);
@CheckForNull
<T extends B> T putInstance(TypeToken<T> type, T value);
}
Expand Up @@ -20,6 +20,7 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotCall;
import java.util.Map;
import javax.annotation.CheckForNull;

/**
* A type-to-instance map backed by an {@link ImmutableMap}. See also {@link
Expand All @@ -29,6 +30,7 @@
* @since 13.0
*/
@Beta
@ElementTypesAreNonnullByDefault
public final class ImmutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
implements TypeToInstanceMap<B> {

Expand Down Expand Up @@ -102,11 +104,13 @@ private ImmutableTypeToInstanceMap(ImmutableMap<TypeToken<? extends B>, B> deleg
}

@Override
@CheckForNull
public <T extends B> T getInstance(TypeToken<T> type) {
return trustedGet(type.rejectTypeVariables());
}

@Override
@CheckForNull
public <T extends B> T getInstance(Class<T> type) {
return trustedGet(TypeToken.of(type));
}
Expand All @@ -121,6 +125,7 @@ public <T extends B> T getInstance(Class<T> type) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public <T extends B> T putInstance(TypeToken<T> type, T value) {
throw new UnsupportedOperationException();
}
Expand All @@ -135,6 +140,7 @@ public <T extends B> T putInstance(TypeToken<T> type, T value) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public <T extends B> T putInstance(Class<T> type, T value) {
throw new UnsupportedOperationException();
}
Expand All @@ -149,6 +155,7 @@ public <T extends B> T putInstance(Class<T> type, T value) {
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public B put(TypeToken<? extends B> key, B value) {
throw new UnsupportedOperationException();
}
Expand All @@ -172,6 +179,7 @@ protected Map<TypeToken<? extends B>, B> delegate() {
}

@SuppressWarnings("unchecked") // value could not get in if not a T
@CheckForNull
private <T extends B> T trustedGet(TypeToken<T> type) {
return (T) delegate.get(type);
}
Expand Down
37 changes: 29 additions & 8 deletions guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
Expand Up @@ -28,39 +28,48 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* A mutable type-to-instance map. See also {@link ImmutableTypeToInstanceMap}.
*
* <p>This implementation <i>does</i> support null values, despite how it is annotated; see
* discussion at {@link TypeToInstanceMap}.
*
* @author Ben Yu
* @since 13.0
*/
@Beta
@ElementTypesAreNonnullByDefault
public final class MutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
implements TypeToInstanceMap<B> {

private final Map<TypeToken<? extends B>, B> backingMap = Maps.newHashMap();

@Override
public <T extends B> @Nullable T getInstance(Class<T> type) {
@CheckForNull
public <T extends B> T getInstance(Class<T> type) {
return trustedGet(TypeToken.of(type));
}

@Override
public <T extends B> @Nullable T getInstance(TypeToken<T> type) {
@CheckForNull
public <T extends B> T getInstance(TypeToken<T> type) {
return trustedGet(type.rejectTypeVariables());
}

@Override
@CanIgnoreReturnValue
public <T extends B> @Nullable T putInstance(Class<T> type, @Nullable T value) {
@CheckForNull
public <T extends B> T putInstance(Class<T> type, T value) {
return trustedPut(TypeToken.of(type), value);
}

@Override
@CanIgnoreReturnValue
public <T extends B> @Nullable T putInstance(TypeToken<T> type, @Nullable T value) {
@CheckForNull
public <T extends B> T putInstance(TypeToken<T> type, T value) {
return trustedPut(type.rejectTypeVariables(), value);
}

Expand All @@ -74,6 +83,7 @@ public final class MutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<?
@Deprecated
@Override
@DoNotCall("Always throws UnsupportedOperationException")
@CheckForNull
public B put(TypeToken<? extends B> key, B value) {
throw new UnsupportedOperationException("Please use putInstance() instead.");
}
Expand Down Expand Up @@ -102,12 +112,14 @@ protected Map<TypeToken<? extends B>, B> delegate() {
}

@SuppressWarnings("unchecked") // value could not get in if not a T
private <T extends B> @Nullable T trustedPut(TypeToken<T> type, @Nullable T value) {
@CheckForNull
private <T extends B> T trustedPut(TypeToken<T> type, T value) {
return (T) backingMap.put(type, value);
}

@SuppressWarnings("unchecked") // value could not get in if not a T
private <T extends B> @Nullable T trustedGet(TypeToken<T> type) {
@CheckForNull
private <T extends B> T trustedGet(TypeToken<T> type) {
return (T) backingMap.get(type);
}

Expand All @@ -129,11 +141,20 @@ public Iterator<Entry<K, V>> iterator() {

@Override
public Object[] toArray() {
return standardToArray();
/*
* standardToArray returns `@Nullable Object[]` rather than `Object[]` but only because it
* can be used with collections that may contain null. This collection is a collection of
* non-null Entry objects (Entry objects that might contain null values but are not
* themselves null), so we can treat it as a plain `Object[]`.
*/
@SuppressWarnings("nullness")
Object[] result = standardToArray();
return result;
}

@Override
public <T> T[] toArray(T[] array) {
@SuppressWarnings("nullness") // b/192354773 in our checker affects toArray declarations
public <T extends @Nullable Object> T[] toArray(T[] array) {
return standardToArray(array);
}
};
Expand Down

0 comments on commit 7a603a9

Please sign in to comment.