diff --git a/guava/pom.xml b/guava/pom.xml index 71931b991395..a1ef66da4a92 100644 --- a/guava/pom.xml +++ b/guava/pom.xml @@ -90,6 +90,26 @@ maven-compiler-plugin + 3.11.0 + + true + + + org.checkerframework + checker + 3.0.1 + + + + org.checkerframework.checker.nullness.NullnessChecker + + + -Xmaxerrs + 10000 + -Xmaxwarns + 10000 + + maven-source-plugin @@ -248,5 +268,77 @@ + + + checkerframework-jdk8 + + 1.8 + + + + 9+181-r4173-1 + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + copy + + process-sources + + com.google.errorprone:javac:${javac.version}:jar + ${project.build.directory}/javac + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -J-Xbootclasspath/p:${project.build.directory}/javac/javac-${javac.version}.jar + + + + + + + + + checkerframework-jdk9orlater + + [9,) + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED + + + + + + + diff --git a/guava/src/com/google/common/annotations/Beta.java b/guava/src/com/google/common/annotations/Beta.java index 47dafe84efca..f71dc9427578 100644 --- a/guava/src/com/google/common/annotations/Beta.java +++ b/guava/src/com/google/common/annotations/Beta.java @@ -31,7 +31,6 @@ * work during upgrades. However it is generally inadvisable for libraries (which get * included on users' CLASSPATHs, outside the library developers' control) to do so. * - * * @author Kevin Bourrillion */ @Retention(RetentionPolicy.CLASS) diff --git a/guava/src/com/google/common/annotations/GwtCompatible.java b/guava/src/com/google/common/annotations/GwtCompatible.java index 139172816467..4bf6efbb7e97 100644 --- a/guava/src/com/google/common/annotations/GwtCompatible.java +++ b/guava/src/com/google/common/annotations/GwtCompatible.java @@ -54,7 +54,6 @@ * *

Note that a {@code GwtCompatible} type may have some {@link GwtIncompatible} methods. * - * * @author Charles Fry * @author Hayward Chan */ diff --git a/guava/src/com/google/common/annotations/VisibleForTesting.java b/guava/src/com/google/common/annotations/VisibleForTesting.java index 4540cfd76dfa..ba8b6f81b434 100644 --- a/guava/src/com/google/common/annotations/VisibleForTesting.java +++ b/guava/src/com/google/common/annotations/VisibleForTesting.java @@ -21,5 +21,4 @@ * @author Johannes Henkel */ @GwtCompatible -public @interface VisibleForTesting { -} +public @interface VisibleForTesting {} diff --git a/guava/src/com/google/common/base/Absent.java b/guava/src/com/google/common/base/Absent.java index 4223b39e6c24..dfaa04d61982 100644 --- a/guava/src/com/google/common/base/Absent.java +++ b/guava/src/com/google/common/base/Absent.java @@ -19,15 +19,16 @@ import com.google.common.annotations.GwtCompatible; import java.util.Collections; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** Implementation of an {@link Optional} not containing a reference. */ @GwtCompatible -final class Absent extends Optional { +final class Absent extends Optional { static final Absent INSTANCE = new Absent<>(); @SuppressWarnings("unchecked") // implementation is "fully variant" - static Optional withType() { + static Optional withType() { return (Optional) INSTANCE; } @@ -71,7 +72,7 @@ public Set asSet() { } @Override - public Optional transform(Function function) { + public Optional transform(Function function) { checkNotNull(function); return Optional.absent(); } diff --git a/guava/src/com/google/common/base/AbstractIterator.java b/guava/src/com/google/common/base/AbstractIterator.java index 57d8167bcc02..a6647b1d91aa 100644 --- a/guava/src/com/google/common/base/AbstractIterator.java +++ b/guava/src/com/google/common/base/AbstractIterator.java @@ -44,8 +44,14 @@ private enum State { protected abstract T computeNext(); @CanIgnoreReturnValue - protected final @Nullable T endOfData() { + protected final T endOfData() { state = State.DONE; + // endOfData's return type is a lie. For discussion, see collect.AbstractIterator. + return unsafeNull(); + } + + @SuppressWarnings("nullness") + private static T unsafeNull() { return null; } @@ -78,7 +84,8 @@ public final T next() { throw new NoSuchElementException(); } state = State.NOT_READY; - T result = next; + // Guaranteed to be safe by the hasNext() check: + T result = uncheckedCastNullableTToT(next); next = null; return result; } @@ -87,4 +94,15 @@ public final T next() { public final void remove() { throw new UnsupportedOperationException(); } + + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T next) { + /* + * We can't use requireNonNull because `next` might be null. Specifically, it can be null + * because the iterator might contain a null element to be returned to the user. This is in + * contrast to the other way for `next` to be null, which is for the iterator not to have a next + * value computed yet. + */ + return next; + } } diff --git a/guava/src/com/google/common/base/Ascii.java b/guava/src/com/google/common/base/Ascii.java index 0a8ec5075f16..3a9558016de4 100644 --- a/guava/src/com/google/common/base/Ascii.java +++ b/guava/src/com/google/common/base/Ascii.java @@ -542,7 +542,6 @@ public static boolean isUpperCase(char c) { *
  • it is safe to use non-ASCII characters in the truncation indicator * * - * * @throws IllegalArgumentException if {@code maxLength} is less than the length of {@code * truncationIndicator} * @since 16.0 diff --git a/guava/src/com/google/common/base/CaseFormat.java b/guava/src/com/google/common/base/CaseFormat.java index 188d0d0fe79c..a525e61e8ade 100644 --- a/guava/src/com/google/common/base/CaseFormat.java +++ b/guava/src/com/google/common/base/CaseFormat.java @@ -127,6 +127,7 @@ public final String to(CaseFormat format, String str) { } /** Enum values can override for performance reasons. */ + @SuppressWarnings("nullness") // Lazy init of `out` is too clever for CF to understand. String convert(CaseFormat format, String s) { // deal with camel conversion StringBuilder out = null; diff --git a/guava/src/com/google/common/base/Charsets.java b/guava/src/com/google/common/base/Charsets.java index 2c9563d769c8..95d5419a5ef9 100644 --- a/guava/src/com/google/common/base/Charsets.java +++ b/guava/src/com/google/common/base/Charsets.java @@ -39,7 +39,6 @@ private Charsets() {} * *

    Note for Java 7 and later: this constant should be treated as deprecated; use {@link * java.nio.charset.StandardCharsets#US_ASCII} instead. - * */ @GwtIncompatible // Charset not supported by GWT public static final Charset US_ASCII = Charset.forName("US-ASCII"); @@ -49,7 +48,6 @@ private Charsets() {} * *

    Note for Java 7 and later: this constant should be treated as deprecated; use {@link * java.nio.charset.StandardCharsets#ISO_8859_1} instead. - * */ public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); @@ -58,7 +56,6 @@ private Charsets() {} * *

    Note for Java 7 and later: this constant should be treated as deprecated; use {@link * java.nio.charset.StandardCharsets#UTF_8} instead. - * */ public static final Charset UTF_8 = Charset.forName("UTF-8"); @@ -67,7 +64,6 @@ private Charsets() {} * *

    Note for Java 7 and later: this constant should be treated as deprecated; use {@link * java.nio.charset.StandardCharsets#UTF_16BE} instead. - * */ @GwtIncompatible // Charset not supported by GWT public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); @@ -77,7 +73,6 @@ private Charsets() {} * *

    Note for Java 7 and later: this constant should be treated as deprecated; use {@link * java.nio.charset.StandardCharsets#UTF_16LE} instead. - * */ @GwtIncompatible // Charset not supported by GWT public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); @@ -88,7 +83,6 @@ private Charsets() {} * *

    Note for Java 7 and later: this constant should be treated as deprecated; use {@link * java.nio.charset.StandardCharsets#UTF_16} instead. - * */ @GwtIncompatible // Charset not supported by GWT public static final Charset UTF_16 = Charset.forName("UTF-16"); diff --git a/guava/src/com/google/common/base/Converter.java b/guava/src/com/google/common/base/Converter.java index 602824bef128..76e17cd1692d 100644 --- a/guava/src/com/google/common/base/Converter.java +++ b/guava/src/com/google/common/base/Converter.java @@ -22,6 +22,7 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import java.io.Serializable; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -54,7 +55,6 @@ * behavior for all converters; implementations of {@link #doForward} and {@link #doBackward} are * guaranteed to never be passed {@code null}, and must never return {@code null}. * - * *

    Common ways to use

    * *

    Getting a converter: @@ -113,7 +113,8 @@ * @since 16.0 */ @GwtCompatible -public abstract class Converter implements Function { +public abstract class Converter + implements Function<@Nullable A, @Nullable B> { private final boolean handleNullAutomatically; // We lazily cache the reverse view to avoid allocating on every call to reverse(). @@ -174,7 +175,7 @@ B correctedDoForward(@Nullable A a) { // TODO(kevinb): we shouldn't be checking for a null result at runtime. Assert? return a == null ? null : checkNotNull(doForward(a)); } else { - return doForward(a); + return unsafeDoForward(a); } } @@ -184,10 +185,26 @@ A correctedDoBackward(@Nullable B b) { // TODO(kevinb): we shouldn't be checking for a null result at runtime. Assert? return b == null ? null : checkNotNull(doBackward(b)); } else { - return doBackward(b); + return unsafeDoBackward(b); } } + /* + * LegacyConverter violates the contract of Converter by allowing its doForward and doBackward + * methods to accept null. We could avoid having suppressions in Converter itself if we could cast + * to LegacyConverter, but we can't because it's an internal-only class. + */ + + @SuppressWarnings("nullness") + private @Nullable B unsafeDoForward(@Nullable A a) { + return doForward(a); + } + + @SuppressWarnings("nullness") + private @Nullable A unsafeDoBackward(@Nullable B b) { + return doBackward(b); + } + /** * Returns an iterable that applies {@code convert} to each element of {@code fromIterable}. The * conversion is done lazily. @@ -197,13 +214,13 @@ A correctedDoBackward(@Nullable B b) { * element. */ @CanIgnoreReturnValue - public Iterable convertAll(final Iterable fromIterable) { + public Iterable<@Nullable B> convertAll(final Iterable fromIterable) { checkNotNull(fromIterable, "fromIterable"); - return new Iterable() { + return new Iterable<@Nullable B>() { @Override - public Iterator iterator() { - return new Iterator() { - private final Iterator fromIterator = fromIterable.iterator(); + public Iterator<@Nullable B> iterator() { + return new Iterator<@Nullable B>() { + private final Iterator fromIterator = fromIterable.iterator(); @Override public boolean hasNext() { @@ -211,7 +228,7 @@ public boolean hasNext() { } @Override - public B next() { + public @Nullable B next() { return convert(fromIterator.next()); } @@ -238,8 +255,8 @@ public Converter reverse() { return (result == null) ? reverse = new ReverseConverter<>(this) : result; } - private static final class ReverseConverter extends Converter - implements Serializable { + private static final class ReverseConverter + extends Converter implements Serializable { final Converter original; ReverseConverter(Converter original) { @@ -309,17 +326,19 @@ public String toString() { *

    The returned converter is serializable if {@code this} converter and {@code secondConverter} * are. */ - public final Converter andThen(Converter secondConverter) { + public final Converter andThen( + Converter secondConverter) { return doAndThen(secondConverter); } /** Package-private non-final implementation of andThen() so only we can override it. */ - Converter doAndThen(Converter secondConverter) { + Converter doAndThen(Converter secondConverter) { return new ConverterComposition<>(this, checkNotNull(secondConverter)); } - private static final class ConverterComposition extends Converter - implements Serializable { + private static final class ConverterComposition< + A extends @NonNull Object, B extends @NonNull Object, C extends @NonNull Object> + extends Converter implements Serializable { final Converter first; final Converter second; @@ -421,14 +440,15 @@ public boolean equals(@Nullable Object object) { * * @since 17.0 */ - public static Converter from( + public static Converter from( Function forwardFunction, Function backwardFunction) { return new FunctionBasedConverter<>(forwardFunction, backwardFunction); } - private static final class FunctionBasedConverter extends Converter - implements Serializable { + private static final class FunctionBasedConverter< + A extends @NonNull Object, B extends @NonNull Object> + extends Converter implements Serializable { private final Function forwardFunction; private final Function backwardFunction; @@ -472,7 +492,7 @@ public String toString() { /** Returns a serializable converter that always converts or reverses an object to itself. */ @SuppressWarnings("unchecked") // implementation is "fully variant" - public static Converter identity() { + public static Converter identity() { return (IdentityConverter) IdentityConverter.INSTANCE; } @@ -480,8 +500,9 @@ public static Converter identity() { * A converter that always converts or reverses an object to itself. Note that T is now a * "pass-through type". */ - private static final class IdentityConverter extends Converter implements Serializable { - static final IdentityConverter INSTANCE = new IdentityConverter<>(); + private static final class IdentityConverter extends Converter + implements Serializable { + static final IdentityConverter INSTANCE = new IdentityConverter(); @Override protected T doForward(T t) { @@ -499,7 +520,7 @@ public IdentityConverter reverse() { } @Override - Converter doAndThen(Converter otherConverter) { + Converter doAndThen(Converter otherConverter) { return checkNotNull(otherConverter, "otherConverter"); } diff --git a/guava/src/com/google/common/base/Defaults.java b/guava/src/com/google/common/base/Defaults.java index 92958c15c7d4..f7078c6d05e9 100644 --- a/guava/src/com/google/common/base/Defaults.java +++ b/guava/src/com/google/common/base/Defaults.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtIncompatible; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -38,7 +39,7 @@ private Defaults() {} * {@code void}, {@code null} is returned. */ @SuppressWarnings("unchecked") - public static @Nullable T defaultValue(Class type) { + public static @Nullable T defaultValue(Class type) { checkNotNull(type); if (type == boolean.class) { return (T) Boolean.FALSE; diff --git a/guava/src/com/google/common/base/Equivalence.java b/guava/src/com/google/common/base/Equivalence.java index b4ac005708af..8b2a5162f33c 100644 --- a/guava/src/com/google/common/base/Equivalence.java +++ b/guava/src/com/google/common/base/Equivalence.java @@ -20,6 +20,7 @@ import com.google.errorprone.annotations.ForOverride; import java.io.Serializable; import java.util.function.BiPredicate; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -34,7 +35,8 @@ * source-compatible since 4.0) */ @GwtCompatible -public abstract class Equivalence implements BiPredicate { +public abstract class Equivalence + implements BiPredicate<@Nullable T, @Nullable T> { /** Constructor for use by subclasses. */ protected Equivalence() {} @@ -147,7 +149,9 @@ public final int hash(@Nullable T t) { * * @since 10.0 */ - public final Equivalence onResultOf(Function function) { + // TODO(cpovirk): Function to accept a Function<@Nullable F, ...>? + public final Equivalence onResultOf( + Function function) { return new FunctionalEquivalence<>(function, this); } @@ -158,8 +162,11 @@ public final Equivalence onResultOf(Function function) { * * @since 10.0 */ - public final Wrapper wrap(@Nullable S reference) { - return new Wrapper(this, reference); + public final Wrapper wrap(S reference) { + // For an explanation of this suppression, see the comments inside Wrapper. + @SuppressWarnings("unchecked") + Equivalence self = (Equivalence) this; + return new Wrapper(self, reference); } /** @@ -183,16 +190,27 @@ public final Wrapper wrap(@Nullable S reference) { * @since 10.0 */ public static final class Wrapper implements Serializable { - private final Equivalence equivalence; - private final @Nullable T reference; + /* + * The right type for this is something like Equivalence. But it's not clear that we'll support that. The simplest + * thing is for us to store an Equivalence but be sure to apply it only to T instances + * (aside from bending the rules in equals(), as described there). + * + * (Alternatively, we could add a type parameter to Wrapper, giving it a signature like the + * Equivalence.wrap method that's used to create it. Or, if we don't want to change the type + * parameters of Wrapper itself, we could make Wrapper abstract, and we create a private + * implementation with the 2 type parameters.) + */ + private final Equivalence equivalence; + private final T reference; - private Wrapper(Equivalence equivalence, @Nullable T reference) { + private Wrapper(Equivalence equivalence, T reference) { this.equivalence = checkNotNull(equivalence); this.reference = reference; } /** Returns the (possibly null) reference wrapped by this instance. */ - public @Nullable T get() { + public T get() { return reference; } @@ -207,15 +225,14 @@ public boolean equals(@Nullable Object obj) { return true; } if (obj instanceof Wrapper) { - Wrapper that = (Wrapper) obj; // note: not necessarily a Wrapper + Wrapper that = + (Wrapper) obj; // note: not necessarily a Wrapper if (this.equivalence.equals(that.equivalence)) { /* * We'll accept that as sufficient "proof" that either equivalence should be able to - * handle either reference, so it's safe to circumvent compile-time type checking. + * handle either reference, so it's safe to apply it to that.reference, too. */ - @SuppressWarnings("unchecked") - Equivalence equivalence = (Equivalence) this.equivalence; return equivalence.equivalent(this.reference, that.reference); } } @@ -252,10 +269,10 @@ public String toString() { * @since 10.0 */ @GwtCompatible(serializable = true) - public final Equivalence> pairwise() { + public final Equivalence> pairwise() { // Ideally, the returned equivalence would support Iterable. However, // the need for this is so rare that it's not worth making callers deal with the ugly wildcard. - return new PairwiseEquivalence(this); + return new PairwiseEquivalence(this); } /** @@ -264,11 +281,12 @@ public final Equivalence> pairwise() { * * @since 10.0 */ - public final Predicate equivalentTo(@Nullable T target) { + public final Predicate<@Nullable T> equivalentTo(@Nullable T target) { return new EquivalentToPredicate(this, target); } - private static final class EquivalentToPredicate implements Predicate, Serializable { + private static final class EquivalentToPredicate + implements Predicate<@Nullable T>, Serializable { private final Equivalence equivalence; private final @Nullable T target; diff --git a/guava/src/com/google/common/base/FinalizablePhantomReference.java b/guava/src/com/google/common/base/FinalizablePhantomReference.java index f92057588a30..cd98955176e8 100644 --- a/guava/src/com/google/common/base/FinalizablePhantomReference.java +++ b/guava/src/com/google/common/base/FinalizablePhantomReference.java @@ -17,6 +17,8 @@ import com.google.common.annotations.GwtIncompatible; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Phantom reference with a {@code finalizeReferent()} method which a background thread invokes @@ -29,15 +31,15 @@ * @since 2.0 */ @GwtIncompatible -public abstract class FinalizablePhantomReference extends PhantomReference - implements FinalizableReference { +public abstract class FinalizablePhantomReference + extends PhantomReference implements FinalizableReference { /** * Constructs a new finalizable phantom reference. * * @param referent to phantom reference * @param queue that should finalize the referent */ - protected FinalizablePhantomReference(T referent, FinalizableReferenceQueue queue) { + protected FinalizablePhantomReference(@Nullable T referent, FinalizableReferenceQueue queue) { super(referent, queue.queue); queue.cleanUp(); } diff --git a/guava/src/com/google/common/base/FinalizableReference.java b/guava/src/com/google/common/base/FinalizableReference.java index 848e7ee586d2..f7e5cf885115 100644 --- a/guava/src/com/google/common/base/FinalizableReference.java +++ b/guava/src/com/google/common/base/FinalizableReference.java @@ -15,7 +15,6 @@ package com.google.common.base; import com.google.common.annotations.GwtIncompatible; -import com.google.errorprone.annotations.DoNotMock; /** * Implemented by references that have code to run after garbage collection of their referents. @@ -24,7 +23,6 @@ * @author Bob Lee * @since 2.0 */ -@DoNotMock("Use an instance of one of the Finalizable*Reference classes") @GwtIncompatible public interface FinalizableReference { /** diff --git a/guava/src/com/google/common/base/FinalizableReferenceQueue.java b/guava/src/com/google/common/base/FinalizableReferenceQueue.java index 3fe706f10974..9ab2562fbdd7 100644 --- a/guava/src/com/google/common/base/FinalizableReferenceQueue.java +++ b/guava/src/com/google/common/base/FinalizableReferenceQueue.java @@ -14,6 +14,8 @@ package com.google.common.base; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.VisibleForTesting; import java.io.Closeable; @@ -152,13 +154,16 @@ public class FinalizableReferenceQueue implements Closeable { final boolean threadStarted; /** Constructs a new queue. */ + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) public FinalizableReferenceQueue() { // We could start the finalizer lazily, but I'd rather it blow up early. queue = new ReferenceQueue<>(); frqRef = new PhantomReference(this, queue); boolean threadStarted = false; try { - startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef); + // unsafeNull is safe because we're calling a static method. + startFinalizer.invoke(unsafeNull(), FinalizableReference.class, queue, frqRef); threadStarted = true; } catch (IllegalAccessException impossible) { throw new AssertionError(impossible); // startFinalizer() is public @@ -173,6 +178,11 @@ public FinalizableReferenceQueue() { this.threadStarted = threadStarted; } + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } + @Override public void close() { frqRef.enqueue(); @@ -302,7 +312,11 @@ static class DecoupledLoader implements FinalizerLoader { URL getBaseUrl() throws IOException { // Find URL pointing to Finalizer.class file. String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class"; - URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath); + /* + * requireNonNull should be safe because this class shouldn't be loaded by the bootstrap class + * loader. + */ + URL finalizerUrl = requireNonNull(getClass().getClassLoader()).getResource(finalizerPath); if (finalizerUrl == null) { throw new FileNotFoundException(finalizerPath); } diff --git a/guava/src/com/google/common/base/FinalizableSoftReference.java b/guava/src/com/google/common/base/FinalizableSoftReference.java index 45ecc656c0d4..f1dd877dc177 100644 --- a/guava/src/com/google/common/base/FinalizableSoftReference.java +++ b/guava/src/com/google/common/base/FinalizableSoftReference.java @@ -17,6 +17,8 @@ import com.google.common.annotations.GwtIncompatible; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Soft reference with a {@code finalizeReferent()} method which a background thread invokes after @@ -27,7 +29,7 @@ * @since 2.0 */ @GwtIncompatible -public abstract class FinalizableSoftReference extends SoftReference +public abstract class FinalizableSoftReference extends SoftReference implements FinalizableReference { /** * Constructs a new finalizable soft reference. @@ -35,7 +37,7 @@ public abstract class FinalizableSoftReference extends SoftReference * @param referent to softly reference * @param queue that should finalize the referent */ - protected FinalizableSoftReference(T referent, FinalizableReferenceQueue queue) { + protected FinalizableSoftReference(@Nullable T referent, FinalizableReferenceQueue queue) { super(referent, queue.queue); queue.cleanUp(); } diff --git a/guava/src/com/google/common/base/FinalizableWeakReference.java b/guava/src/com/google/common/base/FinalizableWeakReference.java index fb3b09bb7dc4..a5fac8437009 100644 --- a/guava/src/com/google/common/base/FinalizableWeakReference.java +++ b/guava/src/com/google/common/base/FinalizableWeakReference.java @@ -17,6 +17,8 @@ import com.google.common.annotations.GwtIncompatible; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Weak reference with a {@code finalizeReferent()} method which a background thread invokes after @@ -27,7 +29,7 @@ * @since 2.0 */ @GwtIncompatible -public abstract class FinalizableWeakReference extends WeakReference +public abstract class FinalizableWeakReference extends WeakReference implements FinalizableReference { /** * Constructs a new finalizable weak reference. @@ -35,7 +37,7 @@ public abstract class FinalizableWeakReference extends WeakReference * @param referent to weakly reference * @param queue that should finalize the referent */ - protected FinalizableWeakReference(T referent, FinalizableReferenceQueue queue) { + protected FinalizableWeakReference(@Nullable T referent, FinalizableReferenceQueue queue) { super(referent, queue.queue); queue.cleanUp(); } diff --git a/guava/src/com/google/common/base/Function.java b/guava/src/com/google/common/base/Function.java index 29b46c015b94..10617e51061c 100644 --- a/guava/src/com/google/common/base/Function.java +++ b/guava/src/com/google/common/base/Function.java @@ -41,11 +41,11 @@ */ @GwtCompatible @FunctionalInterface -public interface Function extends java.util.function.Function { +public interface Function + extends java.util.function.Function { @Override @CanIgnoreReturnValue // TODO(kevinb): remove this - @Nullable - T apply(@Nullable F input); + T apply(F input); /** * May return {@code true} if {@code object} is a {@code Function} that behaves identically diff --git a/guava/src/com/google/common/base/FunctionalEquivalence.java b/guava/src/com/google/common/base/FunctionalEquivalence.java index 05b6271b16c0..6bfbb1c3cc18 100644 --- a/guava/src/com/google/common/base/FunctionalEquivalence.java +++ b/guava/src/com/google/common/base/FunctionalEquivalence.java @@ -19,6 +19,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import java.io.Serializable; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -29,14 +30,17 @@ */ @Beta @GwtCompatible -final class FunctionalEquivalence extends Equivalence implements Serializable { +final class FunctionalEquivalence + extends Equivalence implements Serializable { private static final long serialVersionUID = 0; - private final Function function; + private final Function function; private final Equivalence resultEquivalence; - FunctionalEquivalence(Function function, Equivalence resultEquivalence) { + // TODO(cpovirk): See Equivalence.onResultOf for thoughts about the Function parameter type. + FunctionalEquivalence( + Function function, Equivalence resultEquivalence) { this.function = checkNotNull(function); this.resultEquivalence = checkNotNull(resultEquivalence); } diff --git a/guava/src/com/google/common/base/Functions.java b/guava/src/com/google/common/base/Functions.java index be845c6a45ff..03cc61d567a5 100644 --- a/guava/src/com/google/common/base/Functions.java +++ b/guava/src/com/google/common/base/Functions.java @@ -78,7 +78,7 @@ public String toString() { /** Returns the identity function. */ // implementation is "fully variant"; E has become a "pass-through" type - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "nullness"}) public static Function identity() { return (Function) IdentityFunction.INSTANCE; } @@ -88,7 +88,7 @@ private enum IdentityFunction implements Function { INSTANCE; @Override - public @Nullable Object apply(@Nullable Object o) { + public Object apply(Object o) { return o; } @@ -111,7 +111,8 @@ public String toString() { * key (instead of an exception being thrown), you can use the method reference {@code map::get} * instead. */ - public static Function forMap(Map map) { + public static Function forMap( + Map map) { return new FunctionForMapNoDefault<>(map); } @@ -128,11 +129,14 @@ public static Function forMap(Map map) { * @return function that returns {@code map.get(a)} when {@code a} is a key, or {@code * defaultValue} otherwise */ - public static Function forMap(Map map, @Nullable V defaultValue) { + public static Function forMap( + Map map, V defaultValue) { return new ForMapWithDefault<>(map, defaultValue); } - private static class FunctionForMapNoDefault implements Function, Serializable { + private static class FunctionForMapNoDefault< + K, V> + implements Function, Serializable { final Map map; FunctionForMapNoDefault(Map map) { @@ -140,16 +144,18 @@ private static class FunctionForMapNoDefault implements Function, Se } @Override - public V apply(@Nullable K key) { + public V apply(K key) { V result = map.get(key); checkArgument(result != null || map.containsKey(key), "Key '%s' not present in map", key); - return result; + // The unchecked cast is safe because of the containsKey check. + return uncheckedCastNullableVToV(result); } @Override public boolean equals(@Nullable Object o) { if (o instanceof FunctionForMapNoDefault) { - FunctionForMapNoDefault that = (FunctionForMapNoDefault) o; + FunctionForMapNoDefault that = + (FunctionForMapNoDefault) o; return map.equals(that.map); } return false; @@ -168,25 +174,30 @@ public String toString() { private static final long serialVersionUID = 0; } - private static class ForMapWithDefault implements Function, Serializable { + private static class ForMapWithDefault + implements Function, Serializable { final Map map; - final @Nullable V defaultValue; + final V defaultValue; - ForMapWithDefault(Map map, @Nullable V defaultValue) { + ForMapWithDefault(Map map, V defaultValue) { this.map = checkNotNull(map); this.defaultValue = defaultValue; } @Override - public V apply(@Nullable K key) { + public V apply(K key) { V result = map.get(key); - return (result != null || map.containsKey(key)) ? result : defaultValue; + // The unchecked cast is safe because of the containsKey check. + return (result != null || map.containsKey(key)) + ? uncheckedCastNullableVToV(result) + : defaultValue; } @Override public boolean equals(@Nullable Object o) { if (o instanceof ForMapWithDefault) { - ForMapWithDefault that = (ForMapWithDefault) o; + ForMapWithDefault that = + (ForMapWithDefault) o; return map.equals(that.map) && Objects.equal(defaultValue, that.defaultValue); } return false; @@ -206,6 +217,17 @@ public String toString() { private static final long serialVersionUID = 0; } + @SuppressWarnings("nullness") + private static V uncheckedCastNullableVToV(@Nullable V result) { + /* + * We can't use requireNonNull because `result` might be null. Specifically, it can be null + * because the map might contain a null value to be returned to the user. This is in contrast to + * the other way for the result of map.get to be null, which is for the map not to have a value + * associated with the given key. + */ + return result; + } + /** * Returns the composition of two functions. For {@code f: A->B} and {@code g: B->C}, composition * is defined as the function h such that {@code h(a) == g(f(a))} for each {@code a}. @@ -218,11 +240,14 @@ public String toString() { * @return the composition of {@code f} and {@code g} * @see function composition */ - public static Function compose(Function g, Function f) { - return new FunctionComposition<>(g, f); + public static + Function compose(Function g, Function f) { + return new FunctionComposition(g, f); } - private static class FunctionComposition implements Function, Serializable { + private static class FunctionComposition< + A, B, C> + implements Function, Serializable { private final Function g; private final Function f; @@ -232,14 +257,21 @@ public FunctionComposition(Function g, Function f) { } @Override - public C apply(@Nullable A a) { + public C apply(A a) { return g.apply(f.apply(a)); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof FunctionComposition) { - FunctionComposition that = (FunctionComposition) obj; + FunctionComposition< + ?, ?, ?> + that = + (FunctionComposition< + ?, + ?, + ?>) + obj; return f.equals(that.f) && g.equals(that.g); } return false; @@ -267,12 +299,14 @@ public String toString() { * *

    Java 8 users: use the method reference {@code predicate::test} instead. */ - public static Function forPredicate(Predicate predicate) { + public static Function forPredicate( + Predicate predicate) { return new PredicateFunction(predicate); } /** @see Functions#forPredicate */ - private static class PredicateFunction implements Function, Serializable { + private static class PredicateFunction + implements Function, Serializable { private final Predicate predicate; private PredicateFunction(Predicate predicate) { @@ -280,14 +314,15 @@ private PredicateFunction(Predicate predicate) { } @Override - public Boolean apply(@Nullable T t) { + public Boolean apply(T t) { return predicate.apply(t); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof PredicateFunction) { - PredicateFunction that = (PredicateFunction) obj; + PredicateFunction that = + (PredicateFunction) obj; return predicate.equals(that.predicate); } return false; @@ -314,14 +349,15 @@ public String toString() { * @param value the constant value for the function to return * @return a function that always returns {@code value} */ - public static Function constant(@Nullable E value) { + public static Function<@Nullable Object, E> constant(E value) { return new ConstantFunction(value); } - private static class ConstantFunction implements Function, Serializable { - private final @Nullable E value; + private static class ConstantFunction + implements Function<@Nullable Object, E>, Serializable { + private final E value; - public ConstantFunction(@Nullable E value) { + public ConstantFunction(E value) { this.value = value; } @@ -333,7 +369,8 @@ public E apply(@Nullable Object from) { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof ConstantFunction) { - ConstantFunction that = (ConstantFunction) obj; + ConstantFunction that = + (ConstantFunction) obj; return Objects.equal(value, that.value); } return false; @@ -359,12 +396,14 @@ public String toString() { * * @since 10.0 */ - public static Function forSupplier(Supplier supplier) { + public static Function<@Nullable Object, T> forSupplier( + Supplier supplier) { return new SupplierFunction(supplier); } /** @see Functions#forSupplier */ - private static class SupplierFunction implements Function, Serializable { + private static class SupplierFunction + implements Function<@Nullable Object, T>, Serializable { private final Supplier supplier; @@ -380,7 +419,8 @@ public T apply(@Nullable Object input) { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof SupplierFunction) { - SupplierFunction that = (SupplierFunction) obj; + SupplierFunction that = + (SupplierFunction) obj; return this.supplier.equals(that.supplier); } return false; diff --git a/guava/src/com/google/common/base/Joiner.java b/guava/src/com/google/common/base/Joiner.java index 922c1ebde172..4065c3aa2fe9 100644 --- a/guava/src/com/google/common/base/Joiner.java +++ b/guava/src/com/google/common/base/Joiner.java @@ -15,6 +15,7 @@ package com.google.common.base; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -89,7 +90,8 @@ private Joiner(Joiner prototype) { * separator between each, to {@code appendable}. */ @CanIgnoreReturnValue - public A appendTo(A appendable, Iterable parts) throws IOException { + public A appendTo(A appendable, Iterable parts) + throws IOException { return appendTo(appendable, parts.iterator()); } @@ -100,7 +102,8 @@ public A appendTo(A appendable, Iterable parts) throws * @since 11.0 */ @CanIgnoreReturnValue - public A appendTo(A appendable, Iterator parts) throws IOException { + public A appendTo(A appendable, Iterator parts) + throws IOException { checkNotNull(appendable); if (parts.hasNext()) { appendable.append(toString(parts.next())); @@ -117,14 +120,15 @@ public A appendTo(A appendable, Iterator parts) throws * separator between each, to {@code appendable}. */ @CanIgnoreReturnValue - public final A appendTo(A appendable, Object[] parts) throws IOException { + public final A appendTo(A appendable, @Nullable Object[] parts) + throws IOException { return appendTo(appendable, Arrays.asList(parts)); } /** Appends to {@code appendable} the string representation of each of the remaining arguments. */ @CanIgnoreReturnValue public final A appendTo( - A appendable, @Nullable Object first, @Nullable Object second, Object... rest) + A appendable, @Nullable Object first, @Nullable Object second, @Nullable Object... rest) throws IOException { return appendTo(appendable, iterable(first, second, rest)); } @@ -135,7 +139,8 @@ public final A appendTo( * Iterable)}, except that it does not throw {@link IOException}. */ @CanIgnoreReturnValue - public final StringBuilder appendTo(StringBuilder builder, Iterable parts) { + public final StringBuilder appendTo( + StringBuilder builder, Iterable parts) { return appendTo(builder, parts.iterator()); } @@ -147,7 +152,8 @@ public final StringBuilder appendTo(StringBuilder builder, Iterable parts) { * @since 11.0 */ @CanIgnoreReturnValue - public final StringBuilder appendTo(StringBuilder builder, Iterator parts) { + public final StringBuilder appendTo( + StringBuilder builder, Iterator parts) { try { appendTo((Appendable) builder, parts); } catch (IOException impossible) { @@ -162,7 +168,7 @@ public final StringBuilder appendTo(StringBuilder builder, Iterator parts) { * Iterable)}, except that it does not throw {@link IOException}. */ @CanIgnoreReturnValue - public final StringBuilder appendTo(StringBuilder builder, Object[] parts) { + public final StringBuilder appendTo(StringBuilder builder, @Nullable Object[] parts) { return appendTo(builder, Arrays.asList(parts)); } @@ -173,7 +179,10 @@ public final StringBuilder appendTo(StringBuilder builder, Object[] parts) { */ @CanIgnoreReturnValue public final StringBuilder appendTo( - StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) { + StringBuilder builder, + @Nullable Object first, + @Nullable Object second, + @Nullable Object... rest) { return appendTo(builder, iterable(first, second, rest)); } @@ -199,7 +208,7 @@ public final String join(Iterator parts) { * Returns a string containing the string representation of each of {@code parts}, using the * previously configured separator between each. */ - public final String join(Object[] parts) { + public final String join(@Nullable Object[] parts) { return join(Arrays.asList(parts)); } @@ -207,7 +216,8 @@ public final String join(Object[] parts) { * Returns a string containing the string representation of each argument, using the previously * configured separator between each. */ - public final String join(@Nullable Object first, @Nullable Object second, Object... rest) { + public final String join( + @Nullable Object first, @Nullable Object second, @Nullable Object... rest) { return join(iterable(first, second, rest)); } @@ -242,7 +252,8 @@ public Joiner skipNulls() { public Joiner skipNulls() { return new Joiner(this) { @Override - public A appendTo(A appendable, Iterator parts) throws IOException { + public A appendTo( + A appendable, Iterator parts) throws IOException { checkNotNull(appendable, "appendable"); checkNotNull(parts, "parts"); while (parts.hasNext()) { @@ -324,7 +335,9 @@ private MapJoiner(Joiner joiner, String keyValueSeparator) { * configured separator and key-value separator, to {@code appendable}. */ @CanIgnoreReturnValue - public A appendTo(A appendable, Map map) throws IOException { + public A appendTo( + A appendable, Map map) + throws IOException { return appendTo(appendable, map.entrySet()); } @@ -334,7 +347,8 @@ public A appendTo(A appendable, Map map) throws IOE * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}. */ @CanIgnoreReturnValue - public StringBuilder appendTo(StringBuilder builder, Map map) { + public StringBuilder appendTo( + StringBuilder builder, Map map) { return appendTo(builder, map.entrySet()); } @@ -346,7 +360,9 @@ public StringBuilder appendTo(StringBuilder builder, Map map) { */ @Beta @CanIgnoreReturnValue - public A appendTo(A appendable, Iterable> entries) + public A appendTo( + A appendable, + Iterable> entries) throws IOException { return appendTo(appendable, entries.iterator()); } @@ -359,7 +375,9 @@ public A appendTo(A appendable, Iterable A appendTo(A appendable, Iterator> parts) + public A appendTo( + A appendable, + Iterator> parts) throws IOException { checkNotNull(appendable); if (parts.hasNext()) { @@ -387,7 +405,9 @@ public A appendTo(A appendable, Iterator> entries) { + public StringBuilder appendTo( + StringBuilder builder, + Iterable> entries) { return appendTo(builder, entries.iterator()); } @@ -400,7 +420,9 @@ public StringBuilder appendTo(StringBuilder builder, Iterable> entries) { + public StringBuilder appendTo( + StringBuilder builder, + Iterator> entries) { try { appendTo((Appendable) builder, entries); } catch (IOException impossible) { @@ -424,7 +446,8 @@ public String join(Map map) { * @since 10.0 */ @Beta - public String join(Iterable> entries) { + public String join( + Iterable> entries) { return join(entries.iterator()); } @@ -435,7 +458,8 @@ public String join(Iterable> entries) { * @since 11.0 */ @Beta - public String join(Iterator> entries) { + public String join( + Iterator> entries) { return appendTo(new StringBuilder(), entries).toString(); } @@ -448,22 +472,26 @@ public MapJoiner useForNull(String nullText) { } } - CharSequence toString(Object part) { - checkNotNull(part); // checkNotNull for GWT (do not optimize). + CharSequence toString(@Nullable Object part) { + /* + * Joiner.on(...).join(...) throws for null elements. Still, we declare them as nullable because + * private subclasses of Joiner accept nulls. + */ + requireNonNull(part); // for GWT and CF return (part instanceof CharSequence) ? (CharSequence) part : part.toString(); } - private static Iterable iterable( - final Object first, final Object second, final Object[] rest) { + private static Iterable iterable( + final E first, final E second, final E[] rest) { checkNotNull(rest); - return new AbstractList() { + return new AbstractList() { @Override public int size() { return rest.length + 2; } @Override - public Object get(int index) { + public E get(int index) { switch (index) { case 0: return first; diff --git a/guava/src/com/google/common/base/MoreObjects.java b/guava/src/com/google/common/base/MoreObjects.java index cf901b5954e0..77abc23052f2 100644 --- a/guava/src/com/google/common/base/MoreObjects.java +++ b/guava/src/com/google/common/base/MoreObjects.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Arrays; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -54,7 +55,7 @@ public final class MoreObjects { * @throws NullPointerException if both {@code first} and {@code second} are null * @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}). */ - public static T firstNonNull(@Nullable T first, @Nullable T second) { + public static T firstNonNull(@Nullable T first, T second) { if (first != null) { return first; } diff --git a/guava/src/com/google/common/base/Optional.java b/guava/src/com/google/common/base/Optional.java index 51966f602139..126892db4fa5 100644 --- a/guava/src/com/google/common/base/Optional.java +++ b/guava/src/com/google/common/base/Optional.java @@ -15,13 +15,13 @@ package com.google.common.base; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.errorprone.annotations.DoNotMock; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import java.io.Serializable; import java.util.Iterator; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -80,16 +80,15 @@ * @author Kevin Bourrillion * @since 10.0 */ -@DoNotMock("Use Optional.of(value) or Optional.absent()") @GwtCompatible(serializable = true) -public abstract class Optional implements Serializable { +public abstract class Optional implements Serializable { /** * Returns an {@code Optional} instance with no contained reference. * *

    Comparison to {@code java.util.Optional}: this method is equivalent to Java 8's * {@code Optional.empty}. */ - public static Optional absent() { + public static Optional absent() { return Absent.withType(); } @@ -101,7 +100,7 @@ public static Optional absent() { * * @throws NullPointerException if {@code reference} is null */ - public static Optional of(T reference) { + public static Optional of(T reference) { return new Present(checkNotNull(reference)); } @@ -112,7 +111,8 @@ public static Optional of(T reference) { *

    Comparison to {@code java.util.Optional}: this method is equivalent to Java 8's * {@code Optional.ofNullable}. */ - public static Optional fromNullable(@Nullable T nullableReference) { + public static Optional fromNullable( + @Nullable T nullableReference) { return (nullableReference == null) ? Optional.absent() : new Present(nullableReference); } @@ -122,7 +122,7 @@ public static Optional fromNullable(@Nullable T nullableReference) { * * @since 21.0 */ - public static @Nullable Optional fromJavaUtil( + public static @Nullable Optional fromJavaUtil( java.util.@Nullable Optional javaUtilOptional) { return (javaUtilOptional == null) ? null : fromNullable(javaUtilOptional.orElse(null)); } @@ -140,7 +140,7 @@ public static Optional fromNullable(@Nullable T nullableReference) { * * @since 21.0 */ - public static java.util.@Nullable Optional toJavaUtil( + public static java.util.@Nullable Optional toJavaUtil( @Nullable Optional googleOptional) { return googleOptional == null ? null : googleOptional.toJavaUtil(); } @@ -286,7 +286,8 @@ public java.util.Optional toJavaUtil() { * @throws NullPointerException if the function returns {@code null} * @since 12.0 */ - public abstract Optional transform(Function function); + public abstract Optional transform( + Function function); /** * Returns {@code true} if {@code object} is an {@code Optional} instance, and either the @@ -330,7 +331,7 @@ public java.util.Optional toJavaUtil() { * @since 11.0 (generics widened in 13.0) */ @Beta - public static Iterable presentInstances( + public static Iterable presentInstances( final Iterable> optionals) { checkNotNull(optionals); return new Iterable() { diff --git a/guava/src/com/google/common/base/PairwiseEquivalence.java b/guava/src/com/google/common/base/PairwiseEquivalence.java index 89cb562092c0..ad22d29cbe4f 100644 --- a/guava/src/com/google/common/base/PairwiseEquivalence.java +++ b/guava/src/com/google/common/base/PairwiseEquivalence.java @@ -17,14 +17,15 @@ import com.google.common.annotations.GwtCompatible; import java.io.Serializable; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @GwtCompatible(serializable = true) -final class PairwiseEquivalence extends Equivalence> implements Serializable { +final class PairwiseEquivalence + extends Equivalence> implements Serializable { + final Equivalence elementEquivalence; - final Equivalence elementEquivalence; - - PairwiseEquivalence(Equivalence elementEquivalence) { + PairwiseEquivalence(Equivalence elementEquivalence) { this.elementEquivalence = Preconditions.checkNotNull(elementEquivalence); } @@ -54,7 +55,8 @@ protected int doHash(Iterable iterable) { @Override public boolean equals(@Nullable Object object) { if (object instanceof PairwiseEquivalence) { - PairwiseEquivalence that = (PairwiseEquivalence) object; + PairwiseEquivalence that = + (PairwiseEquivalence) object; return this.elementEquivalence.equals(that.elementEquivalence); } diff --git a/guava/src/com/google/common/base/Platform.java b/guava/src/com/google/common/base/Platform.java index 54b2dfcc861e..500dbfe563ed 100644 --- a/guava/src/com/google/common/base/Platform.java +++ b/guava/src/com/google/common/base/Platform.java @@ -14,6 +14,8 @@ package com.google.common.base; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.GwtCompatible; import java.lang.ref.WeakReference; import java.util.Locale; @@ -47,7 +49,17 @@ static CharMatcher precomputeCharMatcher(CharMatcher matcher) { static > Optional getEnumIfPresent(Class enumClass, String value) { WeakReference> ref = Enums.getEnumConstants(enumClass).get(value); - return ref == null ? Optional.absent() : Optional.of(enumClass.cast(ref.get())); + /* + * requireNonNull is probably safe: We have a strong reference to enumClass, so the class can't + * be garbage collected yet, and thus neither can its constants. But maybe it's possible for + * something weird to happen: Maybe a finalizer can resurrect the class and its constants after + * the weak references to them are cleared? Maybe the VM can avoid keeping enumClass alive + * because it can guarantee that the cast will succeed? But even if these things can happen in + * theory (and I'm not sure they can), I don't think we need to worry in practice. + */ + return ref == null + ? Optional.absent() + : Optional.of(enumClass.cast(requireNonNull(ref.get()))); } static String formatCompact4Digits(double value) { @@ -62,7 +74,7 @@ static String nullToEmpty(@Nullable String string) { return (string == null) ? "" : string; } - static String emptyToNull(@Nullable String string) { + static @Nullable String emptyToNull(@Nullable String string) { return stringIsNullOrEmpty(string) ? null : string; } @@ -114,6 +126,5 @@ static void checkGwtRpcEnabled() { + " warning because you are sending a Guava type over GWT-RPC, which will break. You" + " can identify which type by looking at the class name in the attached stack trace.", new Throwable()); - } } diff --git a/guava/src/com/google/common/base/Preconditions.java b/guava/src/com/google/common/base/Preconditions.java index 30cc374d21d2..3b8af12ff288 100644 --- a/guava/src/com/google/common/base/Preconditions.java +++ b/guava/src/com/google/common/base/Preconditions.java @@ -873,6 +873,7 @@ public static void checkState( * @see Verify#verifyNotNull Verify.verifyNotNull() */ @CanIgnoreReturnValue + // TODO(cpovirk): Users are likely to want the parameter type to be `@Nullable T`. public static T checkNotNull(T reference) { if (reference == null) { throw new NullPointerException(); @@ -1339,7 +1340,7 @@ public static int checkElementIndex(int index, int size) { * @throws IllegalArgumentException if {@code size} is negative */ @CanIgnoreReturnValue - public static int checkElementIndex(int index, int size, @Nullable String desc) { + public static int checkElementIndex(int index, int size, String desc) { // Carefully optimized for execution by hotspot (explanatory comment above) if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); @@ -1347,7 +1348,7 @@ public static int checkElementIndex(int index, int size, @Nullable String desc) return index; } - private static String badElementIndex(int index, int size, @Nullable String desc) { + private static String badElementIndex(int index, int size, String desc) { if (index < 0) { return lenientFormat("%s (%s) must not be negative", desc, index); } else if (size < 0) { @@ -1384,7 +1385,7 @@ public static int checkPositionIndex(int index, int size) { * @throws IllegalArgumentException if {@code size} is negative */ @CanIgnoreReturnValue - public static int checkPositionIndex(int index, int size, @Nullable String desc) { + public static int checkPositionIndex(int index, int size, String desc) { // Carefully optimized for execution by hotspot (explanatory comment above) if (index < 0 || index > size) { throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); @@ -1392,7 +1393,7 @@ public static int checkPositionIndex(int index, int size, @Nullable String desc) return index; } - private static String badPositionIndex(int index, int size, @Nullable String desc) { + private static String badPositionIndex(int index, int size, String desc) { if (index < 0) { return lenientFormat("%s (%s) must not be negative", desc, index); } else if (size < 0) { diff --git a/guava/src/com/google/common/base/Predicate.java b/guava/src/com/google/common/base/Predicate.java index a116cec20c6f..fee4eb7247b5 100644 --- a/guava/src/com/google/common/base/Predicate.java +++ b/guava/src/com/google/common/base/Predicate.java @@ -59,7 +59,7 @@ public interface Predicate extends java.util.function.Predicate { * arguments */ @CanIgnoreReturnValue - boolean apply(@Nullable T input); + boolean apply(T input); /** * Indicates whether another object is equal to this predicate. @@ -75,7 +75,7 @@ public interface Predicate extends java.util.function.Predicate { boolean equals(@Nullable Object object); @Override - default boolean test(@Nullable T input) { + default boolean test(T input) { return apply(input); } } diff --git a/guava/src/com/google/common/base/Predicates.java b/guava/src/com/google/common/base/Predicates.java index 033ab6c26c37..b69400fa4818 100644 --- a/guava/src/com/google/common/base/Predicates.java +++ b/guava/src/com/google/common/base/Predicates.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.List; import java.util.regex.Pattern; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -90,7 +91,8 @@ public static Predicate not(Predicate predicate) { * changes to it won't alter the behavior of this predicate. If {@code components} is empty, the * returned predicate will always evaluate to {@code true}. */ - public static Predicate and(Iterable> components) { + public static Predicate and( + Iterable> components) { return new AndPredicate(defensiveCopy(components)); } @@ -111,7 +113,8 @@ public static Predicate and(Predicate... components) { * true}. The components are evaluated in order, and evaluation will be "short-circuited" as soon * as a false predicate is found. */ - public static Predicate and(Predicate first, Predicate second) { + public static Predicate and( + Predicate first, Predicate second) { return new AndPredicate(Predicates.asList(checkNotNull(first), checkNotNull(second))); } @@ -122,7 +125,8 @@ public static Predicate and(Predicate first, Predicate Predicate or(Iterable> components) { + public static Predicate or( + Iterable> components) { return new OrPredicate(defensiveCopy(components)); } @@ -143,7 +147,8 @@ public static Predicate or(Predicate... components) { * {@code true}. The components are evaluated in order, and evaluation will be "short-circuited" * as soon as a true predicate is found. */ - public static Predicate or(Predicate first, Predicate second) { + public static Predicate or( + Predicate first, Predicate second) { return new OrPredicate(Predicates.asList(checkNotNull(first), checkNotNull(second))); } @@ -151,8 +156,8 @@ public static Predicate or(Predicate first, Predicate Predicate equalTo(@Nullable T target) { - return (target == null) ? Predicates.isNull() : new IsEqualToPredicate(target); + public static Predicate equalTo(T target) { + return (target == null) ? Predicates.isNull() : new IsEqualToPredicate<>(target); } /** @@ -169,7 +174,7 @@ public static Predicate equalTo(@Nullable T target) { * instances {@code Lists.newArrayList(1)} and {@code Arrays.asList(1)}. */ @GwtIncompatible // Class.isInstance - public static Predicate instanceOf(Class clazz) { + public static Predicate<@Nullable Object> instanceOf(Class clazz) { return new InstanceOfPredicate(clazz); } @@ -216,7 +221,7 @@ public static Predicate in(Collection target) { */ public static Predicate compose( Predicate predicate, Function function) { - return new CompositionPredicate<>(predicate, function); + return new CompositionPredicate(predicate, function); } /** @@ -247,7 +252,7 @@ public static Predicate contains(Pattern pattern) { // End public API, begin private implementation classes. // Package private for GWT serialization. - enum ObjectPredicate implements Predicate { + enum ObjectPredicate implements Predicate<@Nullable Object> { /** @see Predicates#alwaysTrue() */ ALWAYS_TRUE { @Override @@ -297,14 +302,15 @@ public String toString() { } }; - @SuppressWarnings("unchecked") // safe contravariant cast + @SuppressWarnings({"unchecked", "nullness"}) // safe contravariant cast Predicate withNarrowedType() { return (Predicate) this; } } /** @see Predicates#not(Predicate) */ - private static class NotPredicate implements Predicate, Serializable { + private static class NotPredicate + implements Predicate, Serializable { final Predicate predicate; NotPredicate(Predicate predicate) { @@ -312,7 +318,7 @@ private static class NotPredicate implements Predicate, Serializable { } @Override - public boolean apply(@Nullable T t) { + public boolean apply(T t) { return !predicate.apply(t); } @@ -324,7 +330,8 @@ public int hashCode() { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof NotPredicate) { - NotPredicate that = (NotPredicate) obj; + NotPredicate that = + (NotPredicate) obj; return predicate.equals(that.predicate); } return false; @@ -339,7 +346,8 @@ public String toString() { } /** @see Predicates#and(Iterable) */ - private static class AndPredicate implements Predicate, Serializable { + private static class AndPredicate + implements Predicate, Serializable { private final List> components; private AndPredicate(List> components) { @@ -347,7 +355,7 @@ private AndPredicate(List> components) { } @Override - public boolean apply(@Nullable T t) { + public boolean apply(T t) { // Avoid using the Iterator to avoid generating garbage (issue 820). for (int i = 0; i < components.size(); i++) { if (!components.get(i).apply(t)) { @@ -366,7 +374,8 @@ public int hashCode() { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof AndPredicate) { - AndPredicate that = (AndPredicate) obj; + AndPredicate that = + (AndPredicate) obj; return components.equals(that.components); } return false; @@ -381,7 +390,8 @@ public String toString() { } /** @see Predicates#or(Iterable) */ - private static class OrPredicate implements Predicate, Serializable { + private static class OrPredicate + implements Predicate, Serializable { private final List> components; private OrPredicate(List> components) { @@ -389,7 +399,7 @@ private OrPredicate(List> components) { } @Override - public boolean apply(@Nullable T t) { + public boolean apply(T t) { // Avoid using the Iterator to avoid generating garbage (issue 820). for (int i = 0; i < components.size(); i++) { if (components.get(i).apply(t)) { @@ -408,7 +418,8 @@ public int hashCode() { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof OrPredicate) { - OrPredicate that = (OrPredicate) obj; + OrPredicate that = + (OrPredicate) obj; return components.equals(that.components); } return false; @@ -436,7 +447,8 @@ private static String toStringHelper(String methodName, Iterable components) } /** @see Predicates#equalTo(Object) */ - private static class IsEqualToPredicate implements Predicate, Serializable { + private static class IsEqualToPredicate + implements Predicate, Serializable { private final T target; private IsEqualToPredicate(T target) { @@ -472,7 +484,7 @@ public String toString() { /** @see Predicates#instanceOf(Class) */ @GwtIncompatible // Class.isInstance - private static class InstanceOfPredicate implements Predicate, Serializable { + private static class InstanceOfPredicate implements Predicate<@Nullable Object>, Serializable { private final Class clazz; private InstanceOfPredicate(Class clazz) { @@ -543,7 +555,8 @@ public String toString() { } /** @see Predicates#in(Collection) */ - private static class InPredicate implements Predicate, Serializable { + private static class InPredicate + implements Predicate, Serializable { private final Collection target; private InPredicate(Collection target) { @@ -551,7 +564,7 @@ private InPredicate(Collection target) { } @Override - public boolean apply(@Nullable T t) { + public boolean apply(T t) { try { return target.contains(t); } catch (NullPointerException | ClassCastException e) { @@ -562,7 +575,8 @@ public boolean apply(@Nullable T t) { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof InPredicate) { - InPredicate that = (InPredicate) obj; + InPredicate that = + (InPredicate) obj; return target.equals(that.target); } return false; @@ -582,7 +596,8 @@ public String toString() { } /** @see Predicates#compose(Predicate, Function) */ - private static class CompositionPredicate implements Predicate, Serializable { + private static class CompositionPredicate + implements Predicate, Serializable { final Predicate p; final Function f; @@ -592,14 +607,15 @@ private CompositionPredicate(Predicate p, Function f) { } @Override - public boolean apply(@Nullable A a) { + public boolean apply(A a) { return p.apply(f.apply(a)); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof CompositionPredicate) { - CompositionPredicate that = (CompositionPredicate) obj; + CompositionPredicate that = + (CompositionPredicate) obj; return f.equals(that.f) && p.equals(that.p); } return false; @@ -689,11 +705,11 @@ private static List> asList( return Arrays.>asList(first, second); } - private static List defensiveCopy(T... array) { + private static List defensiveCopy(T... array) { return defensiveCopy(Arrays.asList(array)); } - static List defensiveCopy(Iterable iterable) { + static List defensiveCopy(Iterable iterable) { ArrayList list = new ArrayList(); for (T element : iterable) { list.add(checkNotNull(element)); diff --git a/guava/src/com/google/common/base/Present.java b/guava/src/com/google/common/base/Present.java index a25de826b89e..8b1b47e27b97 100644 --- a/guava/src/com/google/common/base/Present.java +++ b/guava/src/com/google/common/base/Present.java @@ -19,11 +19,12 @@ import com.google.common.annotations.GwtCompatible; import java.util.Collections; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** Implementation of an {@link Optional} containing a reference. */ @GwtCompatible -final class Present extends Optional { +final class Present extends Optional { private final T reference; Present(T reference) { @@ -69,7 +70,7 @@ public Set asSet() { } @Override - public Optional transform(Function function) { + public Optional transform(Function function) { return new Present( checkNotNull( function.apply(reference), diff --git a/guava/src/com/google/common/base/Stopwatch.java b/guava/src/com/google/common/base/Stopwatch.java index e4cca1ffef35..cf59b652b080 100644 --- a/guava/src/com/google/common/base/Stopwatch.java +++ b/guava/src/com/google/common/base/Stopwatch.java @@ -35,12 +35,12 @@ * An object that accurately measures elapsed time: the measured duration between two * successive readings of "now" in the same process. * - *

    In contrast, wall time is a reading of "now" as given by a method like - * {@link System#currentTimeMillis()}, best represented as an {@link Instant}. Such values - * can be subtracted to obtain a {@code Duration} (such as by {@code Duration.between}), but - * doing so does not give a reliable measurement of elapsed time, because wall time readings - * are inherently approximate, routinely affected by periodic clock corrections. Because this class - * (by default) uses {@link System#nanoTime}, it is unaffected by these changes. + *

    In contrast, wall time is a reading of "now" as given by a method like {@link + * System#currentTimeMillis()}, best represented as an {@link Instant}. Such values can be + * subtracted to obtain a {@code Duration} (such as by {@code Duration.between}), but doing so does + * not give a reliable measurement of elapsed time, because wall time readings are inherently + * approximate, routinely affected by periodic clock corrections. Because this class (by default) + * uses {@link System#nanoTime}, it is unaffected by these changes. * *

    Use this class instead of direct calls to {@link System#nanoTime} for two reasons: * diff --git a/guava/src/com/google/common/base/Supplier.java b/guava/src/com/google/common/base/Supplier.java index 0226d1d647af..62ed26081723 100644 --- a/guava/src/com/google/common/base/Supplier.java +++ b/guava/src/com/google/common/base/Supplier.java @@ -16,6 +16,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Legacy version of {@link java.util.function.Supplier java.util.function.Supplier}. Semantically, diff --git a/guava/src/com/google/common/base/Suppliers.java b/guava/src/com/google/common/base/Suppliers.java index b02b32e429d9..2a5dd42aba21 100644 --- a/guava/src/com/google/common/base/Suppliers.java +++ b/guava/src/com/google/common/base/Suppliers.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.GwtCompatible; import com.google.common.annotations.VisibleForTesting; @@ -42,11 +43,13 @@ private Suppliers() {} * and then applying {@code function} to that value. Note that the resulting supplier will not * call {@code supplier} or invoke {@code function} until it is called. */ - public static Supplier compose(Function function, Supplier supplier) { - return new SupplierComposition<>(function, supplier); + public static Supplier compose( + Function function, Supplier supplier) { + return new SupplierComposition(function, supplier); } - private static class SupplierComposition implements Supplier, Serializable { + private static class SupplierComposition + implements Supplier, Serializable { final Function function; final Supplier supplier; @@ -63,7 +66,8 @@ public T get() { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof SupplierComposition) { - SupplierComposition that = (SupplierComposition) obj; + SupplierComposition that = + (SupplierComposition) obj; return function.equals(that.function) && supplier.equals(that.supplier); } return false; @@ -133,7 +137,8 @@ public T get() { } } } - return value; + // This is safe because we check `initialized.` + return uncheckedCastNullableTToT(value); } @Override @@ -148,7 +153,7 @@ public String toString() { @VisibleForTesting static class NonSerializableMemoizingSupplier implements Supplier { - volatile Supplier delegate; + volatile @Nullable Supplier delegate; volatile boolean initialized; // "value" does not need to be volatile; visibility piggy-backs // on volatile read of "initialized". @@ -164,7 +169,8 @@ public T get() { if (!initialized) { synchronized (this) { if (!initialized) { - T t = delegate.get(); + // requireNonNull is safe because we read and write `delegate` under synchronization. + T t = requireNonNull(delegate).get(); value = t; initialized = true; // Release the delegate to GC. @@ -173,7 +179,8 @@ public T get() { } } } - return value; + // This is safe because we check `initialized.` + return uncheckedCastNullableTToT(value); } @Override @@ -214,7 +221,8 @@ public static Supplier memoizeWithExpiration( @VisibleForTesting @SuppressWarnings("GoodTime") // lots of violations - static class ExpiringMemoizingSupplier implements Supplier, Serializable { + static class ExpiringMemoizingSupplier + implements Supplier, Serializable { final Supplier delegate; final long durationNanos; transient volatile @Nullable T value; @@ -250,7 +258,8 @@ public T get() { } } } - return value; + // This is safe because we check `expirationNanos.` + return uncheckedCastNullableTToT(value); } @Override @@ -263,15 +272,27 @@ public String toString() { private static final long serialVersionUID = 0; } + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T value) { + /* + * We can't use requireNonNull because `value` might be null. Specifically, it can be null + * because the supplier might have generated the value `null` to be returned to the user. This + * is in contrast to the other way for `Supplier.value` to be null, which is for the supplier + * not to have a value computed yet. + */ + return value; + } + /** Returns a supplier that always supplies {@code instance}. */ - public static Supplier ofInstance(@Nullable T instance) { + public static Supplier ofInstance(T instance) { return new SupplierOfInstance(instance); } - private static class SupplierOfInstance implements Supplier, Serializable { - final @Nullable T instance; + private static class SupplierOfInstance + implements Supplier, Serializable { + final T instance; - SupplierOfInstance(@Nullable T instance) { + SupplierOfInstance(T instance) { this.instance = instance; } @@ -283,7 +304,8 @@ public T get() { @Override public boolean equals(@Nullable Object obj) { if (obj instanceof SupplierOfInstance) { - SupplierOfInstance that = (SupplierOfInstance) obj; + SupplierOfInstance that = + (SupplierOfInstance) obj; return Objects.equal(instance, that.instance); } return false; @@ -306,11 +328,13 @@ public String toString() { * Returns a supplier whose {@code get()} method synchronizes on {@code delegate} before calling * it, making it thread-safe. */ - public static Supplier synchronizedSupplier(Supplier delegate) { + public static Supplier synchronizedSupplier( + Supplier delegate) { return new ThreadSafeSupplier(delegate); } - private static class ThreadSafeSupplier implements Supplier, Serializable { + private static class ThreadSafeSupplier + implements Supplier, Serializable { final Supplier delegate; ThreadSafeSupplier(Supplier delegate) { diff --git a/guava/src/com/google/common/base/Throwables.java b/guava/src/com/google/common/base/Throwables.java index e50a416a2060..34a295e09075 100644 --- a/guava/src/com/google/common/base/Throwables.java +++ b/guava/src/com/google/common/base/Throwables.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableList; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -265,7 +266,8 @@ public static Throwable getRootCause(Throwable throwable) { throw new IllegalArgumentException("Loop in causal chain detected.", throwable); } if (advanceSlowPointer) { - slowPointer = slowPointer.getCause(); + // requireNonNull is safe because the fast pointer already walked this far. + slowPointer = requireNonNull(slowPointer.getCause()); } advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration } @@ -308,7 +310,8 @@ public static List getCausalChain(Throwable throwable) { throw new IllegalArgumentException("Loop in causal chain detected.", throwable); } if (advanceSlowPointer) { - slowPointer = slowPointer.getCause(); + // requireNonNull is safe because the fast pointer already walked this far. + slowPointer = requireNonNull(slowPointer.getCause()); } advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration } @@ -330,7 +333,7 @@ public static List getCausalChain(Throwable throwable) { */ @Beta @GwtIncompatible // Class.cast(Object) - public static X getCauseAs( + public static @Nullable X getCauseAs( Throwable throwable, Class expectedCauseType) { try { return expectedCauseType.cast(throwable.getCause()); @@ -413,12 +416,14 @@ private static List jlaStackTrace(final Throwable t) { */ return new AbstractList() { @Override + @SuppressWarnings("nullness") // used only when lazyStackTraceIsLazy() public StackTraceElement get(int n) { return (StackTraceElement) invokeAccessibleNonThrowingMethod(getStackTraceElementMethod, jla, t, n); } @Override + @SuppressWarnings("nullness") // used only when lazyStackTraceIsLazy() public int size() { return (Integer) invokeAccessibleNonThrowingMethod(getStackTraceDepthMethod, jla, t); } @@ -429,11 +434,16 @@ public int size() { private static Object invokeAccessibleNonThrowingMethod( Method method, Object receiver, Object... params) { try { - return method.invoke(receiver, params); + // requireNonNull is safe for the specific methods that we call. + return requireNonNull(method.invoke(receiver, params)); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { - throw propagate(e.getCause()); + /* + * requireNonNull should be safe because an InvocationTargetException from reflection should + * always have a cause. + */ + throw propagate(requireNonNull(e.getCause())); } } @@ -464,7 +474,7 @@ private static Object invokeAccessibleNonThrowingMethod( */ @GwtIncompatible // java.lang.reflect private static final @Nullable Method getStackTraceDepthMethod = - (jla == null) ? null : getSizeMethod(); + (jla == null) ? null : getSizeMethod(jla); /** * Returns the JavaLangAccess class that is present in all Sun JDKs. It is not allowed in @@ -479,7 +489,10 @@ private static Object invokeAccessibleNonThrowingMethod( */ Class sharedSecrets = Class.forName(SHARED_SECRETS_CLASSNAME, false, null); Method langAccess = sharedSecrets.getMethod("getJavaLangAccess"); - return langAccess.invoke(null); + // getJavaLangAccess should be a static method, so the instance arg can be null. + @SuppressWarnings("nullness") + Object jla = langAccess.invoke(null); + return jla; } catch (ThreadDeath death) { throw death; } catch (Throwable t) { @@ -510,13 +523,13 @@ private static Object invokeAccessibleNonThrowingMethod( * UnsupportedOperationException. */ @GwtIncompatible // java.lang.reflect - private static @Nullable Method getSizeMethod() { + private static @Nullable Method getSizeMethod(Object jla) { try { Method getStackTraceDepth = getJlaMethod("getStackTraceDepth", Throwable.class); if (getStackTraceDepth == null) { return null; } - getStackTraceDepth.invoke(getJLA(), new Throwable()); + getStackTraceDepth.invoke(jla, new Throwable()); return getStackTraceDepth; } catch (UnsupportedOperationException | IllegalAccessException | InvocationTargetException e) { return null; diff --git a/guava/src/com/google/common/base/Verify.java b/guava/src/com/google/common/base/Verify.java index c2846de869a6..2836b2591984 100644 --- a/guava/src/com/google/common/base/Verify.java +++ b/guava/src/com/google/common/base/Verify.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -473,7 +474,8 @@ public static void verify( * @see Preconditions#checkNotNull Preconditions.checkNotNull() */ @CanIgnoreReturnValue - public static T verifyNotNull(@Nullable T reference) { + // TODO(cpovirk): Users are likely to want the parameter type to be `@Nullable T`. + public static T verifyNotNull(T reference) { return verifyNotNull(reference, "expected a non-null reference"); } @@ -493,8 +495,8 @@ public static T verifyNotNull(@Nullable T reference) { * @see Preconditions#checkNotNull Preconditions.checkNotNull() */ @CanIgnoreReturnValue - public static T verifyNotNull( - @Nullable T reference, + public static T verifyNotNull( + T reference, @Nullable String errorMessageTemplate, @Nullable Object @Nullable ... errorMessageArgs) { verify(reference != null, errorMessageTemplate, errorMessageArgs); diff --git a/guava/src/com/google/common/base/internal/Finalizer.java b/guava/src/com/google/common/base/internal/Finalizer.java index 75d0d72f6ec4..1a8402ca8d91 100644 --- a/guava/src/com/google/common/base/internal/Finalizer.java +++ b/guava/src/com/google/common/base/internal/Finalizer.java @@ -25,6 +25,8 @@ import java.util.logging.Logger; import org.checkerframework.checker.nullness.qual.Nullable; +// TODO(cpovirk): Does using @Nullable pose problems for class unloading? + /** * Thread that finalizes referents. All references should implement {@code * com.google.common.base.FinalizableReference}. @@ -83,7 +85,7 @@ public static void startFinalizer( boolean inheritThreadLocals = false; long defaultStackSize = 0; thread = - bigThreadConstructor.newInstance( + newThread( (ThreadGroup) null, finalizer, threadName, defaultStackSize, inheritThreadLocals); } catch (Throwable t) { logger.log( @@ -97,7 +99,8 @@ public static void startFinalizer( try { if (inheritableThreadLocals != null) { - inheritableThreadLocals.set(thread, null); + // unsafeNull is safe because java.lang.Thread handles a null inheritableThreadLocals field. + inheritableThreadLocals.set(thread, unsafeNull()); } } catch (Throwable t) { logger.log( @@ -109,6 +112,25 @@ public static void startFinalizer( thread.start(); } + // CF can't know that it's safe to pass a null arg to an arbitrary constructor. + @SuppressWarnings("nullness") + private static Thread newThread( + @Nullable ThreadGroup threadGroup, + Runnable runnable, + String threadName, + long defaultStackSize, + boolean inheritThreadLocals) + throws InstantiationException, IllegalAccessException, + java.lang.reflect.InvocationTargetException { + return bigThreadConstructor.newInstance( + threadGroup, runnable, threadName, defaultStackSize, inheritThreadLocals); + } + + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } + private final WeakReference> finalizableReferenceClassReference; private final PhantomReference frqReference; private final ReferenceQueue queue; diff --git a/guava/src/com/google/common/base/package-info.java b/guava/src/com/google/common/base/package-info.java index f2218562e82b..af9647982f2f 100644 --- a/guava/src/com/google/common/base/package-info.java +++ b/guava/src/com/google/common/base/package-info.java @@ -53,7 +53,6 @@ *
  • {@link com.google.common.base.Stopwatch} *
  • {@link com.google.common.base.Throwables} * - * */ @CheckReturnValue @ParametersAreNonnullByDefault diff --git a/guava/src/com/google/common/cache/AbstractCache.java b/guava/src/com/google/common/cache/AbstractCache.java index d8ef0323a81d..ae647ec300c3 100644 --- a/guava/src/com/google/common/cache/AbstractCache.java +++ b/guava/src/com/google/common/cache/AbstractCache.java @@ -22,6 +22,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import org.checkerframework.checker.nullness.qual.NonNull; /** * This class provides a skeletal implementation of the {@code Cache} interface to minimize the @@ -38,7 +39,8 @@ * @since 10.0 */ @GwtCompatible -public abstract class AbstractCache implements Cache { +public abstract class AbstractCache + implements Cache { /** Constructor for use by subclasses. */ protected AbstractCache() {} @@ -59,7 +61,7 @@ public V get(K key, Callable valueLoader) throws ExecutionException * @since 11.0 */ @Override - public ImmutableMap getAllPresent(Iterable keys) { + public ImmutableMap getAllPresent(Iterable keys) { Map result = Maps.newLinkedHashMap(); for (Object key : keys) { if (!result.containsKey(key)) { @@ -103,7 +105,7 @@ public void invalidate(Object key) { /** @since 11.0 */ @Override - public void invalidateAll(Iterable keys) { + public void invalidateAll(Iterable keys) { for (Object key : keys) { invalidate(key); } diff --git a/guava/src/com/google/common/cache/AbstractLoadingCache.java b/guava/src/com/google/common/cache/AbstractLoadingCache.java index 38b97747915e..f7cf9eb361c4 100644 --- a/guava/src/com/google/common/cache/AbstractLoadingCache.java +++ b/guava/src/com/google/common/cache/AbstractLoadingCache.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import org.checkerframework.checker.nullness.qual.NonNull; /** * This class provides a skeletal implementation of the {@code Cache} interface to minimize the @@ -38,8 +39,8 @@ * @since 11.0 */ @GwtIncompatible -public abstract class AbstractLoadingCache extends AbstractCache - implements LoadingCache { +public abstract class AbstractLoadingCache + extends AbstractCache implements LoadingCache { /** Constructor for use by subclasses. */ protected AbstractLoadingCache() {} diff --git a/guava/src/com/google/common/cache/Cache.java b/guava/src/com/google/common/cache/Cache.java index 4bcb30846bb8..a69a3c747209 100644 --- a/guava/src/com/google/common/cache/Cache.java +++ b/guava/src/com/google/common/cache/Cache.java @@ -19,11 +19,11 @@ import com.google.common.util.concurrent.ExecutionError; import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.errorprone.annotations.CompatibleWith; -import com.google.errorprone.annotations.DoNotMock; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -37,9 +37,8 @@ * @author Charles Fry * @since 10.0 */ -@DoNotMock("Use CacheBuilder.newBuilder().build()") @GwtCompatible -public interface Cache { +public interface Cache { /** * Returns the value associated with {@code key} in this cache, or {@code null} if there is no @@ -104,7 +103,7 @@ public interface Cache { * * @since 11.0 */ - ImmutableMap getAllPresent(Iterable keys); + ImmutableMap getAllPresent(Iterable keys); /** * Associates {@code value} with {@code key} in this cache. If the cache previously contained a @@ -135,7 +134,7 @@ public interface Cache { * * @since 11.0 */ - void invalidateAll(Iterable keys); + void invalidateAll(Iterable keys); /** Discards all entries in the cache. */ void invalidateAll(); @@ -152,7 +151,6 @@ public interface Cache { * created using {@link CacheBuilder} only does so if the {@link CacheBuilder#recordStats} method * was called. If statistics are not being recorded, a {@code CacheStats} instance with zero for * all values is returned. - * */ CacheStats stats(); diff --git a/guava/src/com/google/common/cache/CacheBuilder.java b/guava/src/com/google/common/cache/CacheBuilder.java index 944e29120c09..e76841659409 100644 --- a/guava/src/com/google/common/cache/CacheBuilder.java +++ b/guava/src/com/google/common/cache/CacheBuilder.java @@ -38,6 +38,7 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -54,7 +55,6 @@ *
  • accumulation of cache access statistics * * - * *

    These features are all optional; caches can be created using all or none of them. By default * cache instances created by {@code CacheBuilder} will not perform any type of eviction. * @@ -151,7 +151,7 @@ * @since 10.0 */ @GwtCompatible(emulated = true) -public final class CacheBuilder { +public final class CacheBuilder { private static final int DEFAULT_INITIAL_CAPACITY = 16; private static final int DEFAULT_CONCURRENCY_LEVEL = 4; diff --git a/guava/src/com/google/common/cache/CacheBuilderSpec.java b/guava/src/com/google/common/cache/CacheBuilderSpec.java index cba67213f154..b5342ceb5a26 100644 --- a/guava/src/com/google/common/cache/CacheBuilderSpec.java +++ b/guava/src/com/google/common/cache/CacheBuilderSpec.java @@ -107,19 +107,19 @@ private interface ValueParser { .put("refreshInterval", new RefreshDurationParser()) .build(); - @VisibleForTesting @Nullable Integer initialCapacity; - @VisibleForTesting @Nullable Long maximumSize; - @VisibleForTesting @Nullable Long maximumWeight; - @VisibleForTesting @Nullable Integer concurrencyLevel; - @VisibleForTesting @Nullable Strength keyStrength; - @VisibleForTesting @Nullable Strength valueStrength; - @VisibleForTesting @Nullable Boolean recordStats; + @Nullable @VisibleForTesting Integer initialCapacity; + @Nullable @VisibleForTesting Long maximumSize; + @Nullable @VisibleForTesting Long maximumWeight; + @Nullable @VisibleForTesting Integer concurrencyLevel; + @Nullable @VisibleForTesting Strength keyStrength; + @Nullable @VisibleForTesting Strength valueStrength; + @Nullable @VisibleForTesting Boolean recordStats; @VisibleForTesting long writeExpirationDuration; - @VisibleForTesting @Nullable TimeUnit writeExpirationTimeUnit; + @Nullable @VisibleForTesting TimeUnit writeExpirationTimeUnit; @VisibleForTesting long accessExpirationDuration; - @VisibleForTesting @Nullable TimeUnit accessExpirationTimeUnit; + @Nullable @VisibleForTesting TimeUnit accessExpirationTimeUnit; @VisibleForTesting long refreshDuration; - @VisibleForTesting @Nullable TimeUnit refreshTimeUnit; + @Nullable @VisibleForTesting TimeUnit refreshTimeUnit; /** Specification; used for toParseableString(). */ private final String specification; @@ -146,7 +146,9 @@ public static CacheBuilderSpec parse(String cacheBuilderSpecification) { // Find the ValueParser for the current key. String key = keyAndValue.get(0); ValueParser valueParser = VALUE_PARSERS.get(key); - checkArgument(valueParser != null, "unknown key %s", key); + if (valueParser == null) { + throw new IllegalArgumentException("unknown key " + key); + } String value = keyAndValue.size() == 1 ? null : keyAndValue.get(1); valueParser.parse(spec, key, value); @@ -287,8 +289,10 @@ abstract static class IntegerParser implements ValueParser { protected abstract void parseInteger(CacheBuilderSpec spec, int value); @Override - public void parse(CacheBuilderSpec spec, String key, String value) { - checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key); + public void parse(CacheBuilderSpec spec, String key, @Nullable String value) { + if (value == null || value.isEmpty()) { + throw new IllegalArgumentException("value of key " + key + " omitted"); + } try { parseInteger(spec, Integer.parseInt(value)); } catch (NumberFormatException e) { @@ -303,8 +307,10 @@ abstract static class LongParser implements ValueParser { protected abstract void parseLong(CacheBuilderSpec spec, long value); @Override - public void parse(CacheBuilderSpec spec, String key, String value) { - checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key); + public void parse(CacheBuilderSpec spec, String key, @Nullable String value) { + if (value == null || value.isEmpty()) { + throw new IllegalArgumentException("value of key " + key + " omitted"); + } try { parseLong(spec, Long.parseLong(value)); } catch (NumberFormatException e) { @@ -410,8 +416,10 @@ abstract static class DurationParser implements ValueParser { protected abstract void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit); @Override - public void parse(CacheBuilderSpec spec, String key, String value) { - checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key); + public void parse(CacheBuilderSpec spec, String key, @Nullable String value) { + if (value == null || value.isEmpty()) { + throw new IllegalArgumentException("value of key " + key + " omitted"); + } try { char lastChar = value.charAt(value.length() - 1); TimeUnit timeUnit; diff --git a/guava/src/com/google/common/cache/CacheLoader.java b/guava/src/com/google/common/cache/CacheLoader.java index 36639fde5eb4..b7791e84222b 100644 --- a/guava/src/com/google/common/cache/CacheLoader.java +++ b/guava/src/com/google/common/cache/CacheLoader.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Executor; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}. @@ -56,7 +57,7 @@ * @since 10.0 */ @GwtCompatible(emulated = true) -public abstract class CacheLoader { +public abstract class CacheLoader { /** Constructor for use by subclasses. */ protected CacheLoader() {} @@ -135,7 +136,8 @@ public Map loadAll(Iterable keys) throws Exception { * @param function the function to be used for loading values; must never return {@code null} * @return a cache loader that loads values by passing each key to {@code function} */ - public static CacheLoader from(Function function) { + public static CacheLoader from( + Function function) { return new FunctionToCacheLoader<>(function); } @@ -148,12 +150,13 @@ public static CacheLoader from(Function function) { * @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the * key */ - public static CacheLoader from(Supplier supplier) { + public static CacheLoader from(Supplier supplier) { return new SupplierToCacheLoader(supplier); } - private static final class FunctionToCacheLoader extends CacheLoader - implements Serializable { + private static final class FunctionToCacheLoader< + K extends @NonNull Object, V extends @NonNull Object> + extends CacheLoader implements Serializable { private final Function computingFunction; public FunctionToCacheLoader(Function computingFunction) { @@ -178,8 +181,8 @@ public V load(K key) { * @since 17.0 */ @GwtIncompatible // Executor + Futures - public static CacheLoader asyncReloading( - final CacheLoader loader, final Executor executor) { + public static + CacheLoader asyncReloading(final CacheLoader loader, final Executor executor) { checkNotNull(loader); checkNotNull(executor); return new CacheLoader() { @@ -209,8 +212,8 @@ public Map loadAll(Iterable keys) throws Exception { }; } - private static final class SupplierToCacheLoader extends CacheLoader - implements Serializable { + private static final class SupplierToCacheLoader + extends CacheLoader implements Serializable { private final Supplier computingSupplier; public SupplierToCacheLoader(Supplier computingSupplier) { diff --git a/guava/src/com/google/common/cache/ForwardingCache.java b/guava/src/com/google/common/cache/ForwardingCache.java index 81dbf7acefa4..88c1df82eded 100644 --- a/guava/src/com/google/common/cache/ForwardingCache.java +++ b/guava/src/com/google/common/cache/ForwardingCache.java @@ -22,6 +22,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -33,7 +34,8 @@ * @since 10.0 */ @GwtIncompatible -public abstract class ForwardingCache extends ForwardingObject implements Cache { +public abstract class ForwardingCache + extends ForwardingObject implements Cache { /** Constructor for use by subclasses. */ protected ForwardingCache() {} @@ -55,7 +57,7 @@ public V get(K key, Callable valueLoader) throws ExecutionException /** @since 11.0 */ @Override - public ImmutableMap getAllPresent(Iterable keys) { + public ImmutableMap getAllPresent(Iterable keys) { return delegate().getAllPresent(keys); } @@ -78,7 +80,7 @@ public void invalidate(Object key) { /** @since 11.0 */ @Override - public void invalidateAll(Iterable keys) { + public void invalidateAll(Iterable keys) { delegate().invalidateAll(keys); } @@ -113,7 +115,9 @@ public void cleanUp() { * * @since 10.0 */ - public abstract static class SimpleForwardingCache extends ForwardingCache { + public abstract static class SimpleForwardingCache< + K extends @NonNull Object, V extends @NonNull Object> + extends ForwardingCache { private final Cache delegate; protected SimpleForwardingCache(Cache delegate) { diff --git a/guava/src/com/google/common/cache/ForwardingLoadingCache.java b/guava/src/com/google/common/cache/ForwardingLoadingCache.java index ba88ded9bbc1..7befd2765e1c 100644 --- a/guava/src/com/google/common/cache/ForwardingLoadingCache.java +++ b/guava/src/com/google/common/cache/ForwardingLoadingCache.java @@ -18,6 +18,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import java.util.concurrent.ExecutionException; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A cache which forwards all its method calls to another cache. Subclasses should override one or @@ -31,8 +32,8 @@ * @since 11.0 */ @GwtIncompatible -public abstract class ForwardingLoadingCache extends ForwardingCache - implements LoadingCache { +public abstract class ForwardingLoadingCache + extends ForwardingCache implements LoadingCache { /** Constructor for use by subclasses. */ protected ForwardingLoadingCache() {} @@ -71,7 +72,8 @@ public void refresh(K key) { * * @since 10.0 */ - public abstract static class SimpleForwardingLoadingCache + public abstract static class SimpleForwardingLoadingCache< + K extends @NonNull Object, V extends @NonNull Object> extends ForwardingLoadingCache { private final LoadingCache delegate; diff --git a/guava/src/com/google/common/cache/LoadingCache.java b/guava/src/com/google/common/cache/LoadingCache.java index 6af1d3ac2a74..fc4711929141 100644 --- a/guava/src/com/google/common/cache/LoadingCache.java +++ b/guava/src/com/google/common/cache/LoadingCache.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A semi-persistent mapping from keys to values. Values are automatically loaded by the cache, and @@ -37,7 +38,8 @@ * @since 11.0 */ @GwtCompatible -public interface LoadingCache extends Cache, Function { +public interface LoadingCache + extends Cache, Function { /** * Returns the value associated with {@code key} in this cache, first loading that value if diff --git a/guava/src/com/google/common/cache/LocalCache.java b/guava/src/com/google/common/cache/LocalCache.java index cd75ef7a9587..f6273f3e593d 100644 --- a/guava/src/com/google/common/cache/LocalCache.java +++ b/guava/src/com/google/common/cache/LocalCache.java @@ -85,6 +85,7 @@ import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -97,9 +98,13 @@ * @author Bob Lee ({@code com.google.common.collect.MapMaker}) * @author Doug Lea ({@code ConcurrentHashMap}) */ -@SuppressWarnings("GoodTime") // lots of violations (nanosecond math) +@SuppressWarnings({ + "GoodTime", // lots of violations (nanosecond math) + "nullness", // too much effort for the payoff +}) @GwtCompatible(emulated = true) -class LocalCache extends AbstractMap implements ConcurrentMap { +class LocalCache extends AbstractMap + implements ConcurrentMap { /* * The basic strategy is to subdivide the table among Segments, each of which itself is a @@ -380,7 +385,7 @@ enum Strength { STRONG { @Override - ValueReference referenceValue( + ValueReference referenceValue( Segment segment, ReferenceEntry entry, V value, int weight) { return (weight == 1) ? new StrongValueReference(value) @@ -394,7 +399,7 @@ Equivalence defaultEquivalence() { }, SOFT { @Override - ValueReference referenceValue( + ValueReference referenceValue( Segment segment, ReferenceEntry entry, V value, int weight) { return (weight == 1) ? new SoftValueReference(segment.valueReferenceQueue, value, entry) @@ -409,7 +414,7 @@ Equivalence defaultEquivalence() { }, WEAK { @Override - ValueReference referenceValue( + ValueReference referenceValue( Segment segment, ReferenceEntry entry, V value, int weight) { return (weight == 1) ? new WeakValueReference(segment.valueReferenceQueue, value, entry) @@ -424,8 +429,9 @@ Equivalence defaultEquivalence() { }; /** Creates a reference for the given value according to this value strength. */ - abstract ValueReference referenceValue( - Segment segment, ReferenceEntry entry, V value, int weight); + abstract + ValueReference referenceValue( + Segment segment, ReferenceEntry entry, V value, int weight); /** * Returns the default equivalence strategy used to compare and hash keys or values referenced @@ -439,20 +445,20 @@ abstract ValueReference referenceValue( enum EntryFactory { STRONG { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new StrongEntry<>(key, hash, next); } }, STRONG_ACCESS { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new StrongAccessEntry<>(key, hash, next); } @Override - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { ReferenceEntry newEntry = super.copyEntry(segment, original, newNext); copyAccessEntry(original, newEntry); @@ -461,13 +467,13 @@ ReferenceEntry copyEntry( }, STRONG_WRITE { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new StrongWriteEntry<>(key, hash, next); } @Override - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { ReferenceEntry newEntry = super.copyEntry(segment, original, newNext); copyWriteEntry(original, newEntry); @@ -476,13 +482,13 @@ ReferenceEntry copyEntry( }, STRONG_ACCESS_WRITE { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new StrongAccessWriteEntry<>(key, hash, next); } @Override - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { ReferenceEntry newEntry = super.copyEntry(segment, original, newNext); copyAccessEntry(original, newEntry); @@ -492,20 +498,20 @@ ReferenceEntry copyEntry( }, WEAK { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new WeakEntry<>(segment.keyReferenceQueue, key, hash, next); } }, WEAK_ACCESS { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new WeakAccessEntry<>(segment.keyReferenceQueue, key, hash, next); } @Override - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { ReferenceEntry newEntry = super.copyEntry(segment, original, newNext); copyAccessEntry(original, newEntry); @@ -514,13 +520,13 @@ ReferenceEntry copyEntry( }, WEAK_WRITE { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new WeakWriteEntry<>(segment.keyReferenceQueue, key, hash, next); } @Override - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { ReferenceEntry newEntry = super.copyEntry(segment, original, newNext); copyWriteEntry(original, newEntry); @@ -529,13 +535,13 @@ ReferenceEntry copyEntry( }, WEAK_ACCESS_WRITE { @Override - ReferenceEntry newEntry( + ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next) { return new WeakAccessWriteEntry<>(segment.keyReferenceQueue, key, hash, next); } @Override - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { ReferenceEntry newEntry = super.copyEntry(segment, original, newNext); copyAccessEntry(original, newEntry); @@ -579,7 +585,7 @@ static EntryFactory getFactory( * @param hash of the key * @param next entry in the same bucket */ - abstract ReferenceEntry newEntry( + abstract ReferenceEntry newEntry( Segment segment, K key, int hash, @Nullable ReferenceEntry next); /** @@ -589,13 +595,14 @@ abstract ReferenceEntry newEntry( * @param newNext entry in the same bucket */ // Guarded By Segment.this - ReferenceEntry copyEntry( + ReferenceEntry copyEntry( Segment segment, ReferenceEntry original, ReferenceEntry newNext) { return newEntry(segment, original.getKey(), original.getHash(), newNext); } // Guarded By Segment.this - void copyAccessEntry(ReferenceEntry original, ReferenceEntry newEntry) { + void copyAccessEntry( + ReferenceEntry original, ReferenceEntry newEntry) { // TODO(fry): when we link values instead of entries this method can go // away, as can connectAccessOrder, nullifyAccessOrder. newEntry.setAccessTime(original.getAccessTime()); @@ -607,7 +614,8 @@ void copyAccessEntry(ReferenceEntry original, ReferenceEntry } // Guarded By Segment.this - void copyWriteEntry(ReferenceEntry original, ReferenceEntry newEntry) { + void copyWriteEntry( + ReferenceEntry original, ReferenceEntry newEntry) { // TODO(fry): when we link values instead of entries this method can go // away, as can connectWriteOrder, nullifyWriteOrder. newEntry.setWriteTime(original.getWriteTime()); @@ -620,7 +628,7 @@ void copyWriteEntry(ReferenceEntry original, ReferenceEntry n } /** A reference to a value. */ - interface ValueReference { + interface ValueReference { /** Returns the value. Does not block or throw exceptions. */ @Nullable V get(); @@ -632,6 +640,7 @@ interface ValueReference { * @throws ExecutionException if the loading thread throws an exception * @throws ExecutionError if the loading thread throws an error */ + @Nullable V waitForValue() throws ExecutionException; /** Returns the weight of this entry. This is assumed to be static between calls to setValue. */ @@ -649,8 +658,7 @@ interface ValueReference { * *

    {@code value} may be null only for a loading reference. */ - ValueReference copyFor( - ReferenceQueue queue, @Nullable V value, ReferenceEntry entry); + ValueReference copyFor(ReferenceQueue queue, V value, ReferenceEntry entry); /** * Notify pending loads that a new value was set. This is only relevant to loading value @@ -679,7 +687,7 @@ ValueReference copyFor( static final ValueReference UNSET = new ValueReference() { @Override - public Object get() { + public @Nullable Object get() { return null; } @@ -689,7 +697,7 @@ public int getWeight() { } @Override - public ReferenceEntry getEntry() { + public @Nullable ReferenceEntry getEntry() { return null; } @@ -712,17 +720,17 @@ public boolean isActive() { } @Override - public Object waitForValue() { + public @Nullable Object waitForValue() { return null; } @Override - public void notifyNewValue(Object newValue) {} + public void notifyNewValue(@Nullable Object newValue) {} }; /** Singleton placeholder that indicates a value is being loaded. */ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value - static ValueReference unset() { + static ValueReference unset() { return (ValueReference) UNSET; } @@ -730,7 +738,7 @@ private enum NullEntry implements ReferenceEntry { INSTANCE; @Override - public ValueReference getValueReference() { + public @Nullable ValueReference getValueReference() { return null; } @@ -738,7 +746,7 @@ public ValueReference getValueReference() { public void setValueReference(ValueReference valueReference) {} @Override - public ReferenceEntry getNext() { + public @Nullable ReferenceEntry getNext() { return null; } @@ -748,7 +756,7 @@ public int getHash() { } @Override - public Object getKey() { + public @Nullable Object getKey() { return null; } @@ -801,9 +809,10 @@ public ReferenceEntry getPreviousInWriteQueue() { public void setPreviousInWriteQueue(ReferenceEntry previous) {} } - abstract static class AbstractReferenceEntry implements ReferenceEntry { + abstract static class AbstractReferenceEntry + implements ReferenceEntry { @Override - public ValueReference getValueReference() { + public @Nullable ValueReference getValueReference() { throw new UnsupportedOperationException(); } @@ -813,7 +822,7 @@ public void setValueReference(ValueReference valueReference) { } @Override - public ReferenceEntry getNext() { + public @Nullable ReferenceEntry getNext() { throw new UnsupportedOperationException(); } @@ -823,7 +832,7 @@ public int getHash() { } @Override - public K getKey() { + public @Nullable K getKey() { throw new UnsupportedOperationException(); } @@ -889,7 +898,7 @@ public void setPreviousInWriteQueue(ReferenceEntry previous) { } @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value - static ReferenceEntry nullEntry() { + static ReferenceEntry nullEntry() { return (ReferenceEntry) NullEntry.INSTANCE; } @@ -901,12 +910,12 @@ public boolean offer(Object o) { } @Override - public Object peek() { + public @Nullable Object peek() { return null; } @Override - public Object poll() { + public @Nullable Object poll() { return null; } @@ -936,7 +945,8 @@ static Queue discardingQueue() { */ /** Used for strongly-referenced keys. */ - static class StrongEntry extends AbstractReferenceEntry { + static class StrongEntry + extends AbstractReferenceEntry { final K key; StrongEntry(K key, int hash, @Nullable ReferenceEntry next) { @@ -972,12 +982,13 @@ public int getHash() { } @Override - public ReferenceEntry getNext() { + public @Nullable ReferenceEntry getNext() { return next; } } - static final class StrongAccessEntry extends StrongEntry { + static final class StrongAccessEntry + extends StrongEntry { StrongAccessEntry(K key, int hash, @Nullable ReferenceEntry next) { super(key, hash, next); } @@ -1023,7 +1034,8 @@ public void setPreviousInAccessQueue(ReferenceEntry previous) { } } - static final class StrongWriteEntry extends StrongEntry { + static final class StrongWriteEntry + extends StrongEntry { StrongWriteEntry(K key, int hash, @Nullable ReferenceEntry next) { super(key, hash, next); } @@ -1069,7 +1081,8 @@ public void setPreviousInWriteQueue(ReferenceEntry previous) { } } - static final class StrongAccessWriteEntry extends StrongEntry { + static final class StrongAccessWriteEntry + extends StrongEntry { StrongAccessWriteEntry(K key, int hash, @Nullable ReferenceEntry next) { super(key, hash, next); } @@ -1156,7 +1169,8 @@ public void setPreviousInWriteQueue(ReferenceEntry previous) { } /** Used for weakly-referenced keys. */ - static class WeakEntry extends WeakReference implements ReferenceEntry { + static class WeakEntry + extends WeakReference implements ReferenceEntry { WeakEntry(ReferenceQueue queue, K key, int hash, @Nullable ReferenceEntry next) { super(key, queue); this.hash = hash; @@ -1164,7 +1178,7 @@ static class WeakEntry extends WeakReference implements ReferenceEntry< } @Override - public K getKey() { + public @Nullable K getKey() { return get(); } @@ -1259,12 +1273,13 @@ public int getHash() { } @Override - public ReferenceEntry getNext() { + public @Nullable ReferenceEntry getNext() { return next; } } - static final class WeakAccessEntry extends WeakEntry { + static final class WeakAccessEntry + extends WeakEntry { WeakAccessEntry(ReferenceQueue queue, K key, int hash, @Nullable ReferenceEntry next) { super(queue, key, hash, next); } @@ -1310,7 +1325,8 @@ public void setPreviousInAccessQueue(ReferenceEntry previous) { } } - static final class WeakWriteEntry extends WeakEntry { + static final class WeakWriteEntry + extends WeakEntry { WeakWriteEntry(ReferenceQueue queue, K key, int hash, @Nullable ReferenceEntry next) { super(queue, key, hash, next); } @@ -1356,7 +1372,8 @@ public void setPreviousInWriteQueue(ReferenceEntry previous) { } } - static final class WeakAccessWriteEntry extends WeakEntry { + static final class WeakAccessWriteEntry + extends WeakEntry { WeakAccessWriteEntry( ReferenceQueue queue, K key, int hash, @Nullable ReferenceEntry next) { super(queue, key, hash, next); @@ -1444,7 +1461,8 @@ public void setPreviousInWriteQueue(ReferenceEntry previous) { } /** References a weak value. */ - static class WeakValueReference extends WeakReference implements ValueReference { + static class WeakValueReference + extends WeakReference implements ValueReference { final ReferenceEntry entry; WeakValueReference(ReferenceQueue queue, V referent, ReferenceEntry entry) { @@ -1463,7 +1481,7 @@ public ReferenceEntry getEntry() { } @Override - public void notifyNewValue(V newValue) {} + public void notifyNewValue(@Nullable V newValue) {} @Override public ValueReference copyFor( @@ -1482,13 +1500,14 @@ public boolean isActive() { } @Override - public V waitForValue() { + public @Nullable V waitForValue() { return get(); } } /** References a soft value. */ - static class SoftValueReference extends SoftReference implements ValueReference { + static class SoftValueReference + extends SoftReference implements ValueReference { final ReferenceEntry entry; SoftValueReference(ReferenceQueue queue, V referent, ReferenceEntry entry) { @@ -1507,7 +1526,7 @@ public ReferenceEntry getEntry() { } @Override - public void notifyNewValue(V newValue) {} + public void notifyNewValue(@Nullable V newValue) {} @Override public ValueReference copyFor( @@ -1526,13 +1545,14 @@ public boolean isActive() { } @Override - public V waitForValue() { + public @Nullable V waitForValue() { return get(); } } /** References a strong value. */ - static class StrongValueReference implements ValueReference { + static class StrongValueReference + implements ValueReference { final V referent; StrongValueReference(V referent) { @@ -1550,7 +1570,7 @@ public int getWeight() { } @Override - public ReferenceEntry getEntry() { + public @Nullable ReferenceEntry getEntry() { return null; } @@ -1571,16 +1591,18 @@ public boolean isActive() { } @Override - public V waitForValue() { + public @Nullable V waitForValue() { return get(); } @Override - public void notifyNewValue(V newValue) {} + public void notifyNewValue(@Nullable V newValue) {} } /** References a weak value. */ - static final class WeightedWeakValueReference extends WeakValueReference { + static final class WeightedWeakValueReference< + K extends @NonNull Object, V extends @NonNull Object> + extends WeakValueReference { final int weight; WeightedWeakValueReference( @@ -1602,7 +1624,9 @@ public ValueReference copyFor( } /** References a soft value. */ - static final class WeightedSoftValueReference extends SoftValueReference { + static final class WeightedSoftValueReference< + K extends @NonNull Object, V extends @NonNull Object> + extends SoftValueReference { final int weight; WeightedSoftValueReference( @@ -1624,7 +1648,9 @@ public ValueReference copyFor( } /** References a strong value. */ - static final class WeightedStrongValueReference extends StrongValueReference { + static final class WeightedStrongValueReference< + K extends @NonNull Object, V extends @NonNull Object> + extends StrongValueReference { final int weight; WeightedStrongValueReference(V referent, int weight) { @@ -1773,26 +1799,30 @@ boolean isExpired(ReferenceEntry entry, long now) { // queues // Guarded By Segment.this - static void connectAccessOrder(ReferenceEntry previous, ReferenceEntry next) { + static void connectAccessOrder( + ReferenceEntry previous, ReferenceEntry next) { previous.setNextInAccessQueue(next); next.setPreviousInAccessQueue(previous); } // Guarded By Segment.this - static void nullifyAccessOrder(ReferenceEntry nulled) { + static void nullifyAccessOrder( + ReferenceEntry nulled) { ReferenceEntry nullEntry = nullEntry(); nulled.setNextInAccessQueue(nullEntry); nulled.setPreviousInAccessQueue(nullEntry); } // Guarded By Segment.this - static void connectWriteOrder(ReferenceEntry previous, ReferenceEntry next) { + static void connectWriteOrder( + ReferenceEntry previous, ReferenceEntry next) { previous.setNextInWriteQueue(next); next.setPreviousInWriteQueue(previous); } // Guarded By Segment.this - static void nullifyWriteOrder(ReferenceEntry nulled) { + static void nullifyWriteOrder( + ReferenceEntry nulled) { ReferenceEntry nullEntry = nullEntry(); nulled.setNextInWriteQueue(nullEntry); nulled.setPreviousInWriteQueue(nullEntry); @@ -1826,7 +1856,7 @@ final Segment[] newSegmentArray(int ssize) { * opportunistically, just to simplify some locking and avoid separate construction. */ @SuppressWarnings("serial") // This class is never serialized. - static class Segment extends ReentrantLock { + static class Segment extends ReentrantLock { /* * TODO(fry): Consider copying variables (like evictsBySize) from outer class into this class. @@ -1985,6 +2015,7 @@ ReferenceEntry newEntry(K key, int hash, @Nullable ReferenceEntry ne * or {@code null} if {@code original} was already garbage collected. */ @GuardedBy("this") + @Nullable ReferenceEntry copyEntry(ReferenceEntry original, ReferenceEntry newNext) { if (original.getKey() == null) { // key collected @@ -2185,7 +2216,8 @@ V waitForLoadingValue(ReferenceEntry e, K key, ValueReference valueR } } - V compute(K key, int hash, BiFunction function) { + @Nullable + V compute(K key, int hash, BiFunction function) { ReferenceEntry e; ValueReference valueReference = null; LoadingValueReference loadingValueReference = null; @@ -2701,6 +2733,7 @@ ReferenceEntry getLiveEntry(Object key, int hash, long now) { * Gets the value from an entry. Returns null if the entry is invalid, partially-collected, * loading, or expired. */ + @Nullable V getLiveValue(ReferenceEntry entry, long now) { if (entry.getKey() == null) { tryDrainReferenceQueues(); @@ -2741,7 +2774,7 @@ boolean containsKey(Object key, int hash) { * directly. */ @VisibleForTesting - boolean containsValue(Object value) { + boolean containsValue(@Nullable Object value) { try { if (count != 0) { // read-volatile long now = map.ticker.read(); @@ -3465,7 +3498,8 @@ void runUnlockedCleanup() { } } - static class LoadingValueReference implements ValueReference { + static class LoadingValueReference + implements ValueReference { volatile ValueReference oldValue; // TODO(fry): rename get, then extend AbstractFuture instead of containing SettableFuture @@ -3495,7 +3529,7 @@ public int getWeight() { return oldValue.getWeight(); } - public boolean set(@Nullable V newValue) { + public boolean set(V newValue) { return futureValue.set(newValue); } @@ -3554,7 +3588,7 @@ public V apply(V newValue) { } } - public V compute(K key, BiFunction function) { + public V compute(K key, BiFunction function) { stopwatch.start(); V previousValue; try { @@ -3583,22 +3617,22 @@ public V waitForValue() throws ExecutionException { } @Override - public V get() { + public @Nullable V get() { return oldValue.get(); } - public ValueReference getOldValue() { + public @Nullable ValueReference getOldValue() { return oldValue; } @Override - public ReferenceEntry getEntry() { + public @Nullable ReferenceEntry getEntry() { return null; } @Override public ValueReference copyFor( - ReferenceQueue queue, @Nullable V value, ReferenceEntry entry) { + ReferenceQueue queue, V value, ReferenceEntry entry) { return this; } } @@ -3616,7 +3650,8 @@ public ValueReference copyFor( * the queue as part of copyWriteEntry, and (2) the contains method is highly optimized for the * current model. */ - static final class WriteQueue extends AbstractQueue> { + static final class WriteQueue + extends AbstractQueue> { final ReferenceEntry head = new AbstractReferenceEntry() { @@ -3668,13 +3703,13 @@ public boolean offer(ReferenceEntry entry) { } @Override - public ReferenceEntry peek() { + public @Nullable ReferenceEntry peek() { ReferenceEntry next = head.getNextInWriteQueue(); return (next == head) ? null : next; } @Override - public ReferenceEntry poll() { + public @Nullable ReferenceEntry poll() { ReferenceEntry next = head.getNextInWriteQueue(); if (next == head) { return null; @@ -3686,7 +3721,7 @@ public ReferenceEntry poll() { @Override @SuppressWarnings("unchecked") - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { ReferenceEntry e = (ReferenceEntry) o; ReferenceEntry previous = e.getPreviousInWriteQueue(); ReferenceEntry next = e.getNextInWriteQueue(); @@ -3698,7 +3733,7 @@ public boolean remove(Object o) { @Override @SuppressWarnings("unchecked") - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { ReferenceEntry e = (ReferenceEntry) o; return e.getNextInWriteQueue() != NullEntry.INSTANCE; } @@ -3736,7 +3771,7 @@ public void clear() { public Iterator> iterator() { return new AbstractSequentialIterator>(peek()) { @Override - protected ReferenceEntry computeNext(ReferenceEntry previous) { + protected @Nullable ReferenceEntry computeNext(ReferenceEntry previous) { ReferenceEntry next = previous.getNextInWriteQueue(); return (next == head) ? null : next; } @@ -3755,7 +3790,8 @@ protected ReferenceEntry computeNext(ReferenceEntry previous) { * the queue as part of copyWriteEntry, and (2) the contains method is highly optimized for the * current model. */ - static final class AccessQueue extends AbstractQueue> { + static final class AccessQueue + extends AbstractQueue> { final ReferenceEntry head = new AbstractReferenceEntry() { @@ -3807,13 +3843,13 @@ public boolean offer(ReferenceEntry entry) { } @Override - public ReferenceEntry peek() { + public @Nullable ReferenceEntry peek() { ReferenceEntry next = head.getNextInAccessQueue(); return (next == head) ? null : next; } @Override - public ReferenceEntry poll() { + public @Nullable ReferenceEntry poll() { ReferenceEntry next = head.getNextInAccessQueue(); if (next == head) { return null; @@ -3825,7 +3861,7 @@ public ReferenceEntry poll() { @Override @SuppressWarnings("unchecked") - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { ReferenceEntry e = (ReferenceEntry) o; ReferenceEntry previous = e.getPreviousInAccessQueue(); ReferenceEntry next = e.getNextInAccessQueue(); @@ -3837,7 +3873,7 @@ public boolean remove(Object o) { @Override @SuppressWarnings("unchecked") - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { ReferenceEntry e = (ReferenceEntry) o; return e.getNextInAccessQueue() != NullEntry.INSTANCE; } @@ -3875,7 +3911,7 @@ public void clear() { public Iterator> iterator() { return new AbstractSequentialIterator>(peek()) { @Override - protected ReferenceEntry computeNext(ReferenceEntry previous) { + protected @Nullable ReferenceEntry computeNext(ReferenceEntry previous) { ReferenceEntry next = previous.getNextInAccessQueue(); return (next == head) ? null : next; } @@ -3965,7 +4001,7 @@ V get(K key, CacheLoader loader) throws ExecutionException { // Only becomes available in Java 8 when it's on the interface. // @Override @Override - public @Nullable V getOrDefault(@Nullable Object key, @Nullable V defaultValue) { + public V getOrDefault(@Nullable Object key, V defaultValue) { V result = get(key); return (result != null) ? result : defaultValue; } @@ -3974,7 +4010,7 @@ V getOrLoad(K key) throws ExecutionException { return get(key, defaultLoader); } - ImmutableMap getAllPresent(Iterable keys) { + ImmutableMap getAllPresent(Iterable keys) { int hits = 0; int misses = 0; @@ -4109,6 +4145,7 @@ Map loadAll(Set keys, CacheLoader loader) * Returns the internal entry for the specified key. The entry may be loading, expired, or * partially collected. */ + @Nullable ReferenceEntry getEntry(@Nullable Object key) { // does not impact recency ordering if (key == null) { @@ -4174,7 +4211,7 @@ public boolean containsValue(@Nullable Object value) { } @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { checkNotNull(key); checkNotNull(value); int hash = hash(key); @@ -4190,7 +4227,7 @@ public V putIfAbsent(K key, V value) { } @Override - public V compute(K key, BiFunction function) { + public V compute(K key, BiFunction function) { checkNotNull(key); checkNotNull(function); int hash = hash(key); @@ -4212,7 +4249,8 @@ public V computeIfPresent(K key, BiFunction f } @Override - public V merge(K key, V newValue, BiFunction function) { + public V merge( + K key, V newValue, BiFunction function) { checkNotNull(key); checkNotNull(newValue); checkNotNull(function); @@ -4228,7 +4266,7 @@ public void putAll(Map m) { } @Override - public V remove(@Nullable Object key) { + public @Nullable V remove(@Nullable Object key) { if (key == null) { return null; } @@ -4257,7 +4295,7 @@ public boolean replace(K key, @Nullable V oldValue, V newValue) { } @Override - public V replace(K key, V value) { + public @Nullable V replace(K key, V value) { checkNotNull(key); checkNotNull(value); int hash = hash(key); @@ -4271,7 +4309,7 @@ public void clear() { } } - void invalidateAll(Iterable keys) { + void invalidateAll(Iterable keys) { // TODO(fry): batch by segment for (Object key : keys) { remove(key); @@ -4460,7 +4498,8 @@ public V getValue() { public boolean equals(@Nullable Object object) { // Cannot use key and value equivalence if (object instanceof Entry) { - Entry that = (Entry) object; + Entry that = + (Entry) object; return key.equals(that.getKey()) && value.equals(that.getValue()); } return false; @@ -4519,11 +4558,13 @@ public void clear() { // https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508 @Override +@SuppressWarnings("nullness") public Object[] toArray() { return toArrayList(this).toArray(); } @Override +@SuppressWarnings("nullness") public E[] toArray(E[] a) { return toArrayList(this).toArray(a); } @@ -4566,12 +4607,12 @@ public Iterator iterator() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return map.containsKey(o); } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { return map.remove(o) != null; } } @@ -4611,7 +4652,7 @@ public boolean removeIf(Predicate filter) { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return map.containsValue(o); } @@ -4619,11 +4660,13 @@ public boolean contains(Object o) { // https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508 @Override +@SuppressWarnings("nullness") public Object[] toArray() { return toArrayList(this).toArray(); } @Override +@SuppressWarnings("nullness") public E[] toArray(E[] a) { return toArrayList(this).toArray(a); } @@ -4648,11 +4691,12 @@ public boolean removeIf(Predicate> filter) { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { if (!(o instanceof Entry)) { return false; } - Entry e = (Entry) o; + Entry e = + (Entry) o; Object key = e.getKey(); if (key == null) { return false; @@ -4663,11 +4707,12 @@ public boolean contains(Object o) { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (!(o instanceof Entry)) { return false; } - Entry e = (Entry) o; + Entry e = + (Entry) o; Object key = e.getKey(); return key != null && LocalCache.this.remove(key, e.getValue()); } @@ -4683,8 +4728,8 @@ public boolean remove(Object o) { *

    Unfortunately, readResolve() doesn't get called when a circular dependency is present, so * the proxy must be able to behave as the cache itself. */ - static class ManualSerializationProxy extends ForwardingCache - implements Serializable { + static class ManualSerializationProxy + extends ForwardingCache implements Serializable { private static final long serialVersionUID = 1; final Strength keyStrength; @@ -4801,8 +4846,8 @@ protected Cache delegate() { *

    Unfortunately, readResolve() doesn't get called when a circular dependency is present, so * the proxy must be able to behave as the cache itself. */ - static final class LoadingSerializationProxy extends ManualSerializationProxy - implements LoadingCache, Serializable { + static final class LoadingSerializationProxy + extends ManualSerializationProxy implements LoadingCache, Serializable { private static final long serialVersionUID = 1; transient @Nullable LoadingCache autoDelegate; @@ -4847,7 +4892,8 @@ private Object readResolve() { } } - static class LocalManualCache implements Cache, Serializable { + static class LocalManualCache + implements Cache, Serializable { final LocalCache localCache; LocalManualCache(CacheBuilder builder) { @@ -4879,7 +4925,7 @@ public V load(Object key) throws Exception { } @Override - public ImmutableMap getAllPresent(Iterable keys) { + public ImmutableMap getAllPresent(Iterable keys) { return localCache.getAllPresent(keys); } @@ -4900,7 +4946,7 @@ public void invalidate(Object key) { } @Override - public void invalidateAll(Iterable keys) { + public void invalidateAll(Iterable keys) { localCache.invalidateAll(keys); } @@ -4943,8 +4989,8 @@ Object writeReplace() { } } - static class LocalLoadingCache extends LocalManualCache - implements LoadingCache { + static class LocalLoadingCache + extends LocalManualCache implements LoadingCache { LocalLoadingCache( CacheBuilder builder, CacheLoader loader) { diff --git a/guava/src/com/google/common/cache/ReferenceEntry.java b/guava/src/com/google/common/cache/ReferenceEntry.java index 63bf2fe9f29b..8946b2b67d95 100644 --- a/guava/src/com/google/common/cache/ReferenceEntry.java +++ b/guava/src/com/google/common/cache/ReferenceEntry.java @@ -16,6 +16,7 @@ import com.google.common.annotations.GwtIncompatible; import com.google.common.cache.LocalCache.ValueReference; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,8 +40,9 @@ * */ @GwtIncompatible -interface ReferenceEntry { +interface ReferenceEntry { /** Returns the value reference from this entry. */ + @Nullable ValueReference getValueReference(); /** Sets the value reference for this entry. */ diff --git a/guava/src/com/google/common/cache/RemovalListener.java b/guava/src/com/google/common/cache/RemovalListener.java index c9a343c44d0c..ea2a9ef2cdbc 100644 --- a/guava/src/com/google/common/cache/RemovalListener.java +++ b/guava/src/com/google/common/cache/RemovalListener.java @@ -15,6 +15,7 @@ package com.google.common.cache; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * An object that can receive a notification when an entry is removed from a cache. The removal @@ -34,7 +35,7 @@ */ @GwtCompatible @FunctionalInterface -public interface RemovalListener { +public interface RemovalListener { /** * Notifies the listener that a removal occurred at some point in the past. * diff --git a/guava/src/com/google/common/cache/RemovalListeners.java b/guava/src/com/google/common/cache/RemovalListeners.java index c82b0941207f..453a00cbd259 100644 --- a/guava/src/com/google/common/cache/RemovalListeners.java +++ b/guava/src/com/google/common/cache/RemovalListeners.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtIncompatible; import java.util.concurrent.Executor; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A collection of common removal listeners. @@ -37,8 +38,9 @@ private RemovalListeners() {} * @param listener the backing listener * @param executor the executor with which removal notifications are asynchronously executed */ - public static RemovalListener asynchronous( - final RemovalListener listener, final Executor executor) { + public static + RemovalListener asynchronous( + final RemovalListener listener, final Executor executor) { checkNotNull(listener); checkNotNull(executor); return new RemovalListener() { diff --git a/guava/src/com/google/common/cache/RemovalNotification.java b/guava/src/com/google/common/cache/RemovalNotification.java index 641d18f72438..b87caece4429 100644 --- a/guava/src/com/google/common/cache/RemovalNotification.java +++ b/guava/src/com/google/common/cache/RemovalNotification.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.AbstractMap.SimpleImmutableEntry; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -32,7 +33,8 @@ * @since 10.0 */ @GwtCompatible -public final class RemovalNotification extends SimpleImmutableEntry { +public final class RemovalNotification + extends SimpleImmutableEntry<@Nullable K, @Nullable V> { private final RemovalCause cause; /** @@ -42,9 +44,9 @@ public final class RemovalNotification extends SimpleImmutableEntry * * @since 19.0 */ - public static RemovalNotification create( - @Nullable K key, @Nullable V value, RemovalCause cause) { - return new RemovalNotification(key, value, cause); + public static + RemovalNotification create(@Nullable K key, @Nullable V value, RemovalCause cause) { + return new RemovalNotification<>(key, value, cause); } private RemovalNotification(@Nullable K key, @Nullable V value, RemovalCause cause) { diff --git a/guava/src/com/google/common/cache/Striped64.java b/guava/src/com/google/common/cache/Striped64.java index 8c53158eb1d3..6bdb8bb3e0fd 100644 --- a/guava/src/com/google/common/cache/Striped64.java +++ b/guava/src/com/google/common/cache/Striped64.java @@ -125,7 +125,7 @@ final boolean cas(long cmp, long val) { * class, we use a suboptimal int[] representation to avoid introducing a new type that can impede * class-unloading when ThreadLocals are not removed. */ - static final ThreadLocal threadHashCode = new ThreadLocal<>(); + static final ThreadLocal threadHashCode = new ThreadLocal<>(); /** Generator of new random hash codes */ static final Random rng = new Random(); @@ -177,7 +177,7 @@ final boolean casBusy() { * @param hc the hash code holder * @param wasUncontended false if CAS failed before call */ - final void retryUpdate(long x, int[] hc, boolean wasUncontended) { + final void retryUpdate(long x, int @Nullable [] hc, boolean wasUncontended) { int h; if (hc == null) { threadHashCode.set(hc = new int[1]); // Initialize randomly @@ -298,7 +298,8 @@ public sun.misc.Unsafe run() throws Exception { Class k = sun.misc.Unsafe.class; for (java.lang.reflect.Field f : k.getDeclaredFields()) { f.setAccessible(true); - Object x = f.get(null); + // unsafeNull is safe because we're reading a static field. + Object x = f.get(unsafeNull()); if (k.isInstance(x)) return k.cast(x); } throw new NoSuchFieldError("the Unsafe"); @@ -308,4 +309,9 @@ public sun.misc.Unsafe run() throws Exception { throw new RuntimeException("Could not initialize intrinsics", e.getCause()); } } + + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } } diff --git a/guava/src/com/google/common/cache/Weigher.java b/guava/src/com/google/common/cache/Weigher.java index 7372a46965ce..c553941f50b3 100644 --- a/guava/src/com/google/common/cache/Weigher.java +++ b/guava/src/com/google/common/cache/Weigher.java @@ -15,6 +15,7 @@ package com.google.common.cache; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Calculates the weights of cache entries. @@ -24,7 +25,7 @@ */ @GwtCompatible @FunctionalInterface -public interface Weigher { +public interface Weigher { /** * Returns the weight of a cache entry. There is no unit for entry weights; rather they are simply diff --git a/guava/src/com/google/common/collect/AbstractBiMap.java b/guava/src/com/google/common/collect/AbstractBiMap.java index 68744c162e38..5ff04aa4529a 100644 --- a/guava/src/com/google/common/collect/AbstractBiMap.java +++ b/guava/src/com/google/common/collect/AbstractBiMap.java @@ -18,7 +18,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -47,13 +48,14 @@ * @author Mike Bostock */ @GwtCompatible(emulated = true) -abstract class AbstractBiMap extends ForwardingMap - implements BiMap, Serializable { +abstract class AbstractBiMap + extends ForwardingMap implements BiMap, Serializable { - private transient @Nullable Map delegate; - @RetainedWith transient @Nullable AbstractBiMap inverse; + private transient Map delegate; + @RetainedWith transient AbstractBiMap inverse; /** Package-private constructor for creating a map-backed bimap. */ + @SuppressWarnings("nullness") // Fields are set by setDelegates. AbstractBiMap(Map forward, Map backward) { setDelegates(forward, backward); } @@ -71,13 +73,13 @@ protected Map delegate() { /** Returns its input, or throws an exception if this is not a valid key. */ @CanIgnoreReturnValue - K checkKey(@Nullable K key) { + K checkKey(K key) { return key; } /** Returns its input, or throws an exception if this is not a valid value. */ @CanIgnoreReturnValue - V checkValue(@Nullable V value) { + V checkValue(V value) { return value; } @@ -114,17 +116,17 @@ public boolean containsValue(@Nullable Object value) { @CanIgnoreReturnValue @Override - public V put(@Nullable K key, @Nullable V value) { + public @Nullable V put(K key, V value) { return putInBothMaps(key, value, false); } @CanIgnoreReturnValue @Override - public V forcePut(@Nullable K key, @Nullable V value) { + public @Nullable V forcePut(K key, V value) { return putInBothMaps(key, value, true); } - private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) { + private @Nullable V putInBothMaps(K key, V value, boolean force) { checkKey(key); checkValue(value); boolean containedKey = containsKey(key); @@ -141,22 +143,36 @@ private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) { return oldValue; } - private void updateInverseMap(K key, boolean containedKey, V oldValue, V newValue) { + private void updateInverseMap(K key, boolean containedKey, @Nullable V oldValue, V newValue) { if (containedKey) { - removeFromInverseMap(oldValue); + // The cast is safe because of the containedKey check. + removeFromInverseMap(uncheckedCastNullableVToV(oldValue)); } inverse.delegate.put(newValue, key); } + @SuppressWarnings("nullness") + private static V uncheckedCastNullableVToV(@Nullable V oldValue) { + /* + * We can't use requireNonNull because `oldValue` might be null. Specifically, it can be null + * because the map might contain a null value to be returned to the user. This is in contrast to + * the other way for the result of map.get to be null, which is for the map not to have a value + * associated with the given key. + */ + return oldValue; + } + @CanIgnoreReturnValue @Override - public V remove(@Nullable Object key) { - return containsKey(key) ? removeFromBothMaps(key) : null; + public @Nullable V remove(@Nullable Object key) { + // The cast is safe because of the containsKey check. + return containsKey(key) ? removeFromBothMaps(uncheckedCastNullableVToV(key)) : null; } @CanIgnoreReturnValue private V removeFromBothMaps(Object key) { - V oldValue = delegate.remove(key); + // The cast is safe because the callers of this method first check that the key is present. + V oldValue = uncheckedCastNullableVToV(delegate.remove(key)); removeFromInverseMap(oldValue); return oldValue; } @@ -231,11 +247,12 @@ public void clear() { } @Override - public boolean remove(Object key) { + public boolean remove(@Nullable Object key) { if (!contains(key)) { return false; } - removeFromBothMaps(key); + // The cast is safe because of the contains check. + removeFromBothMaps(uncheckedCastNullableVToV(key)); return true; } @@ -282,11 +299,13 @@ public Iterator iterator() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { return standardToArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return standardToArray(array); } @@ -352,7 +371,9 @@ public Entry next() { @Override public void remove() { - checkRemove(entry != null); + if (entry == null) { + throw noCallsToNextSinceLastRemove(); + } V value = entry.getValue(); iterator.remove(); removeFromInverseMap(value); @@ -376,13 +397,15 @@ public void clear() { } @Override - public boolean remove(Object object) { + public boolean remove(@Nullable Object object) { if (!esDelegate.contains(object)) { return false; } // safe because esDelegate.contains(object). - Entry entry = (Entry) object; + requireNonNull(object); + Entry entry = + (Entry) object; inverse.delegate.remove(entry.getValue()); /* * Remove the mapping in inverse before removing from esDelegate because @@ -401,17 +424,19 @@ public Iterator> iterator() { // See java.util.Collections.CheckedEntrySet for details on attacks. @Override +@SuppressWarnings("nullness") public Object[] toArray() { return standardToArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return standardToArray(array); } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return Maps.containsEntryImpl(delegate(), o); } @@ -432,7 +457,8 @@ public boolean retainAll(Collection c) { } /** The inverse of any other {@code AbstractBiMap} subclass. */ - static class Inverse extends AbstractBiMap { + static class Inverse + extends AbstractBiMap { Inverse(Map backward, AbstractBiMap forward) { super(backward, forward); } diff --git a/guava/src/com/google/common/collect/AbstractIndexedListIterator.java b/guava/src/com/google/common/collect/AbstractIndexedListIterator.java index 855fb1c5fd0b..35500e941d33 100644 --- a/guava/src/com/google/common/collect/AbstractIndexedListIterator.java +++ b/guava/src/com/google/common/collect/AbstractIndexedListIterator.java @@ -21,6 +21,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.ListIterator; import java.util.NoSuchElementException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * This class provides a skeletal implementation of the {@link ListIterator} interface across a @@ -30,7 +31,8 @@ * @author Jared Levy */ @GwtCompatible -abstract class AbstractIndexedListIterator extends UnmodifiableListIterator { +abstract class AbstractIndexedListIterator + extends UnmodifiableListIterator { private final int size; private int position; diff --git a/guava/src/com/google/common/collect/AbstractIterator.java b/guava/src/com/google/common/collect/AbstractIterator.java index ff009c528ddc..105a39a47ae0 100644 --- a/guava/src/com/google/common/collect/AbstractIterator.java +++ b/guava/src/com/google/common/collect/AbstractIterator.java @@ -119,6 +119,20 @@ private enum State { @CanIgnoreReturnValue protected final T endOfData() { state = State.DONE; + /* + * endOfData's return type is a lie. It should be safe in normal usage, though: We assume that + * it will only ever be called from `computeNext()` in a statement like `return endOfData()`. In + * that case, the value returned by computeNext() is ignored because state is set to DONE. + * + * The alternative would be to declare not only endOfData() but also computeNext() as returning + * `@Nullable T`. That alternative feels more dangerous, since it lets the AbstractIterator + * output a null element when that should not be possible. + */ + return unsafeNull(); + } + + @SuppressWarnings("nullness") + private static T unsafeNull() { return null; } @@ -153,7 +167,8 @@ public final T next() { throw new NoSuchElementException(); } state = State.NOT_READY; - T result = next; + // Guaranteed to be safe by the hasNext() check: + T result = uncheckedCastNullableTToT(next); next = null; return result; } @@ -169,6 +184,18 @@ public final T peek() { if (!hasNext()) { throw new NoSuchElementException(); } + // Guaranteed to be safe by the hasNext() check: + return uncheckedCastNullableTToT(next); + } + + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T next) { + /* + * We can't use requireNonNull because `next` might be null. Specifically, it can be null + * because the iterator might contain a null element to be returned to the user. This is in + * contrast to the other way for `next` to be null, which is for the iterator not to have a next + * value computed yet. + */ return next; } } diff --git a/guava/src/com/google/common/collect/AbstractListMultimap.java b/guava/src/com/google/common/collect/AbstractListMultimap.java index d1c87c9907f3..93ca2ccaf986 100644 --- a/guava/src/com/google/common/collect/AbstractListMultimap.java +++ b/guava/src/com/google/common/collect/AbstractListMultimap.java @@ -33,8 +33,8 @@ * @since 2.0 */ @GwtCompatible -abstract class AbstractListMultimap extends AbstractMapBasedMultimap - implements ListMultimap { +abstract class AbstractListMultimap + extends AbstractMapBasedMultimap implements ListMultimap { /** * Creates a new multimap that uses the provided map. * @@ -53,7 +53,8 @@ List createUnmodifiableEmptyCollection() { } @Override - Collection unmodifiableCollectionSubclass(Collection collection) { + Collection unmodifiableCollectionSubclass( + Collection collection) { return Collections.unmodifiableList((List) collection); } @@ -72,7 +73,7 @@ Collection wrapCollection(K key, Collection collection) { * Multimap} interface. */ @Override - public List get(@Nullable K key) { + public List get(K key) { return (List) super.get(key); } @@ -98,7 +99,7 @@ public List removeAll(@Nullable Object key) { */ @CanIgnoreReturnValue @Override - public List replaceValues(@Nullable K key, Iterable values) { + public List replaceValues(K key, Iterable values) { return (List) super.replaceValues(key, values); } @@ -111,7 +112,7 @@ public List replaceValues(@Nullable K key, Iterable values) { */ @CanIgnoreReturnValue @Override - public boolean put(@Nullable K key, @Nullable V value) { + public boolean put(K key, V value) { return super.put(key, value); } diff --git a/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java b/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java index b9f46ed743cc..e487cc6061b6 100644 --- a/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java +++ b/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java @@ -18,7 +18,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.collect.Maps.ViewCachingAbstractMap; @@ -83,8 +84,8 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class AbstractMapBasedMultimap extends AbstractMultimap - implements Serializable { +abstract class AbstractMapBasedMultimap + extends AbstractMultimap implements Serializable { /* * Here's an outline of the overall design. * @@ -157,7 +158,7 @@ Collection createUnmodifiableEmptyCollection() { * @param key key to associate with values in the collection * @return an empty collection of values */ - Collection createCollection(@Nullable K key) { + Collection createCollection(K key) { return createCollection(); } @@ -180,7 +181,7 @@ public boolean containsKey(@Nullable Object key) { // Modification Operations @Override - public boolean put(@Nullable K key, @Nullable V value) { + public boolean put(K key, V value) { Collection collection = map.get(key); if (collection == null) { collection = createCollection(key); @@ -199,7 +200,7 @@ public boolean put(@Nullable K key, @Nullable V value) { } } - private Collection getOrCreateCollection(@Nullable K key) { + private Collection getOrCreateCollection(K key) { Collection collection = map.get(key); if (collection == null) { collection = createCollection(key); @@ -216,7 +217,7 @@ private Collection getOrCreateCollection(@Nullable K key) { *

    The returned collection is immutable. */ @Override - public Collection replaceValues(@Nullable K key, Iterable values) { + public Collection replaceValues(K key, Iterable values) { Iterator iterator = values.iterator(); if (!iterator.hasNext()) { return removeAll(key); @@ -260,7 +261,8 @@ public Collection removeAll(@Nullable Object key) { return unmodifiableCollectionSubclass(output); } - Collection unmodifiableCollectionSubclass(Collection collection) { + Collection unmodifiableCollectionSubclass( + Collection collection) { return Collections.unmodifiableCollection(collection); } @@ -282,7 +284,7 @@ public void clear() { *

    The returned collection is not serializable. */ @Override - public Collection get(@Nullable K key) { + public Collection get(K key) { Collection collection = map.get(key); if (collection == null) { collection = createCollection(key); @@ -294,11 +296,11 @@ public Collection get(@Nullable K key) { * Generates a decorated collection that remains consistent with the values in the multimap for * the provided key. Changes to the multimap may alter the returned collection, and vice versa. */ - Collection wrapCollection(@Nullable K key, Collection collection) { + Collection wrapCollection(K key, Collection collection) { return new WrappedCollection(key, collection, null); } - final List wrapList(@Nullable K key, List list, @Nullable WrappedCollection ancestor) { + final List wrapList(K key, List list, @Nullable WrappedCollection ancestor) { return (list instanceof RandomAccess) ? new RandomAccessWrappedList(key, list, ancestor) : new WrappedList(key, list, ancestor); @@ -321,13 +323,12 @@ final List wrapList(@Nullable K key, List list, @Nullable WrappedCollectio */ @WeakOuter class WrappedCollection extends AbstractCollection { - final @Nullable K key; + final K key; Collection delegate; final @Nullable WrappedCollection ancestor; final @Nullable Collection ancestorDelegate; - WrappedCollection( - @Nullable K key, Collection delegate, @Nullable WrappedCollection ancestor) { + WrappedCollection(K key, Collection delegate, @Nullable WrappedCollection ancestor) { this.key = key; this.delegate = delegate; this.ancestor = ancestor; @@ -490,6 +491,7 @@ public boolean add(V value) { return changed; } + @Nullable WrappedCollection getAncestor() { return ancestor; } @@ -514,7 +516,7 @@ public boolean addAll(Collection collection) { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { refreshIfEmpty(); return delegate.contains(o); } @@ -537,7 +539,7 @@ public void clear() { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { refreshIfEmpty(); boolean changed = delegate.remove(o); if (changed) { @@ -576,7 +578,8 @@ public boolean retainAll(Collection c) { } } - private static Iterator iteratorOrListIterator(Collection collection) { + private static Iterator iteratorOrListIterator( + Collection collection) { return (collection instanceof List) ? ((List) collection).listIterator() : collection.iterator(); @@ -585,7 +588,7 @@ private static Iterator iteratorOrListIterator(Collection collection) /** Set decorator that stays in sync with the multimap values for a key. */ @WeakOuter class WrappedSet extends WrappedCollection implements Set { - WrappedSet(@Nullable K key, Set delegate) { + WrappedSet(K key, Set delegate) { super(key, delegate, null); } @@ -612,7 +615,7 @@ public boolean removeAll(Collection c) { /** SortedSet decorator that stays in sync with the multimap values for a key. */ @WeakOuter class WrappedSortedSet extends WrappedCollection implements SortedSet { - WrappedSortedSet(@Nullable K key, SortedSet delegate, @Nullable WrappedCollection ancestor) { + WrappedSortedSet(K key, SortedSet delegate, @Nullable WrappedCollection ancestor) { super(key, delegate, ancestor); } @@ -621,7 +624,7 @@ SortedSet getSortedSetDelegate() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return getSortedSetDelegate().comparator(); } @@ -667,8 +670,7 @@ public SortedSet tailSet(V fromElement) { @WeakOuter class WrappedNavigableSet extends WrappedSortedSet implements NavigableSet { - WrappedNavigableSet( - @Nullable K key, NavigableSet delegate, @Nullable WrappedCollection ancestor) { + WrappedNavigableSet(K key, NavigableSet delegate, @Nullable WrappedCollection ancestor) { super(key, delegate, ancestor); } @@ -678,32 +680,32 @@ NavigableSet getSortedSetDelegate() { } @Override - public V lower(V v) { + public @Nullable V lower(V v) { return getSortedSetDelegate().lower(v); } @Override - public V floor(V v) { + public @Nullable V floor(V v) { return getSortedSetDelegate().floor(v); } @Override - public V ceiling(V v) { + public @Nullable V ceiling(V v) { return getSortedSetDelegate().ceiling(v); } @Override - public V higher(V v) { + public @Nullable V higher(V v) { return getSortedSetDelegate().higher(v); } @Override - public V pollFirst() { + public @Nullable V pollFirst() { return Iterators.pollNext(iterator()); } @Override - public V pollLast() { + public @Nullable V pollLast() { return Iterators.pollNext(descendingIterator()); } @@ -742,7 +744,7 @@ public NavigableSet tailSet(V fromElement, boolean inclusive) { /** List decorator that stays in sync with the multimap values for a key. */ @WeakOuter class WrappedList extends WrappedCollection implements List { - WrappedList(@Nullable K key, List delegate, @Nullable WrappedCollection ancestor) { + WrappedList(K key, List delegate, @Nullable WrappedCollection ancestor) { super(key, delegate, ancestor); } @@ -800,13 +802,13 @@ public V remove(int index) { } @Override - public int indexOf(Object o) { + public int indexOf(@Nullable Object o) { refreshIfEmpty(); return getListDelegate().indexOf(o); } @Override - public int lastIndexOf(Object o) { + public int lastIndexOf(@Nullable Object o) { refreshIfEmpty(); return getListDelegate().lastIndexOf(o); } @@ -886,8 +888,7 @@ public void add(V value) { * access. */ private class RandomAccessWrappedList extends WrappedList implements RandomAccess { - RandomAccessWrappedList( - @Nullable K key, List delegate, @Nullable WrappedCollection ancestor) { + RandomAccessWrappedList(K key, List delegate, @Nullable WrappedCollection ancestor) { super(key, delegate, ancestor); } } @@ -932,7 +933,9 @@ public K next() { @Override public void remove() { - checkRemove(entry != null); + if (entry == null) { + throw noCallsToNextSinceLastRemove(); + } Collection collection = entry.getValue(); entryIterator.remove(); totalSize -= collection.size(); @@ -950,7 +953,7 @@ public Spliterator spliterator() { } @Override - public boolean remove(Object key) { + public boolean remove(@Nullable Object key) { int count = 0; Collection collection = map().remove(key); if (collection != null) { @@ -994,7 +997,7 @@ SortedMap> sortedMap() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return sortedMap().comparator(); } @@ -1036,32 +1039,32 @@ NavigableMap> sortedMap() { } @Override - public K lower(K k) { + public @Nullable K lower(K k) { return sortedMap().lowerKey(k); } @Override - public K floor(K k) { + public @Nullable K floor(K k) { return sortedMap().floorKey(k); } @Override - public K ceiling(K k) { + public @Nullable K ceiling(K k) { return sortedMap().ceilingKey(k); } @Override - public K higher(K k) { + public @Nullable K higher(K k) { return sortedMap().higherKey(k); } @Override - public K pollFirst() { + public @Nullable K pollFirst() { return Iterators.pollNext(iterator()); } @Override - public K pollLast() { + public @Nullable K pollLast() { return Iterators.pollNext(descendingIterator()); } @@ -1109,7 +1112,7 @@ public NavigableSet tailSet(K fromElement, boolean inclusive) { } /** Removes all values for the provided key. */ - private void removeValuesForKey(Object key) { + private void removeValuesForKey(@Nullable Object key) { Collection collection = Maps.safeRemove(map, key); if (collection != null) { @@ -1147,19 +1150,35 @@ public T next() { collection = mapEntry.getValue(); valueIterator = collection.iterator(); } - return output(key, valueIterator.next()); + // The cast is safe because of the hasNext() check. + return output(uncheckedCastNullableKToK(key), valueIterator.next()); } @Override public void remove() { valueIterator.remove(); - if (collection.isEmpty()) { + /* + * requireNonNull is safe because we've already initialized `collection`. If we hadn't, then + * valueIterator.remove() would have failed. + */ + if (requireNonNull(collection).isEmpty()) { keyIterator.remove(); } totalSize--; } } + @SuppressWarnings("nullness") + private static K uncheckedCastNullableKToK(@Nullable K key) { + /* + * We can't use requireNonNull because `key` might be null. Specifically, it can be null because + * the multimap might contain a null key to be returned to the user. This is in contrast to the + * other way for `key` to be null, which is for the iterator not to have a next value computed + * yet. + */ + return key; + } + /** * {@inheritDoc} * @@ -1300,12 +1319,12 @@ protected Set>> createEntrySet() { // The following methods are included for performance. @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return Maps.safeContainsKey(submap, key); } @Override - public Collection get(Object key) { + public @Nullable Collection get(@Nullable Object key) { Collection collection = Maps.safeGet(submap, key); if (collection == null) { return null; @@ -1326,7 +1345,7 @@ public int size() { } @Override - public Collection remove(Object key) { + public @Nullable Collection remove(@Nullable Object key) { Collection collection = submap.remove(key); if (collection == null) { return null; @@ -1388,16 +1407,18 @@ public Spliterator>> spliterator() { // The following methods are included for performance. @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return Collections2.safeContains(submap.entrySet(), o); } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (!contains(o)) { return false; } - Entry entry = (Entry) o; + // requireNonNull is safe because of the contains check. + Entry entry = + requireNonNull((Entry) o); removeValuesForKey(entry.getKey()); return true; } @@ -1422,7 +1443,9 @@ public Entry> next() { @Override public void remove() { - checkRemove(collection != null); + if (collection == null) { + throw noCallsToNextSinceLastRemove(); + } delegateIterator.remove(); totalSize -= collection.size(); collection.clear(); @@ -1442,7 +1465,7 @@ SortedMap> sortedMap() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return sortedMap().comparator(); } @@ -1499,71 +1522,72 @@ NavigableMap> sortedMap() { } @Override - public Entry> lowerEntry(K key) { + public @Nullable Entry> lowerEntry(K key) { Entry> entry = sortedMap().lowerEntry(key); return (entry == null) ? null : wrapEntry(entry); } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return sortedMap().lowerKey(key); } @Override - public Entry> floorEntry(K key) { + public @Nullable Entry> floorEntry(K key) { Entry> entry = sortedMap().floorEntry(key); return (entry == null) ? null : wrapEntry(entry); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return sortedMap().floorKey(key); } @Override - public Entry> ceilingEntry(K key) { + public @Nullable Entry> ceilingEntry(K key) { Entry> entry = sortedMap().ceilingEntry(key); return (entry == null) ? null : wrapEntry(entry); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return sortedMap().ceilingKey(key); } @Override - public Entry> higherEntry(K key) { + public @Nullable Entry> higherEntry(K key) { Entry> entry = sortedMap().higherEntry(key); return (entry == null) ? null : wrapEntry(entry); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return sortedMap().higherKey(key); } @Override - public Entry> firstEntry() { + public @Nullable Entry> firstEntry() { Entry> entry = sortedMap().firstEntry(); return (entry == null) ? null : wrapEntry(entry); } @Override - public Entry> lastEntry() { + public @Nullable Entry> lastEntry() { Entry> entry = sortedMap().lastEntry(); return (entry == null) ? null : wrapEntry(entry); } @Override - public Entry> pollFirstEntry() { + public @Nullable Entry> pollFirstEntry() { return pollAsMapEntry(entrySet().iterator()); } @Override - public Entry> pollLastEntry() { + public @Nullable Entry> pollLastEntry() { return pollAsMapEntry(descendingMap().entrySet().iterator()); } + @Nullable Entry> pollAsMapEntry(Iterator>> entryIterator) { if (!entryIterator.hasNext()) { return null; diff --git a/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java b/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java index 2d28c1d98866..558af52605b3 100644 --- a/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java +++ b/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java @@ -20,6 +20,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -44,7 +46,8 @@ * @author Kevin Bourrillion */ @GwtCompatible(emulated = true) -abstract class AbstractMapBasedMultiset extends AbstractMultiset implements Serializable { +abstract class AbstractMapBasedMultiset extends AbstractMultiset + implements Serializable { // TODO(lowasser): consider overhauling this back to Map private transient Map backingMap; @@ -100,7 +103,9 @@ public E next() { @Override public void remove() { - checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } size -= toRemove.getValue().getAndSet(0); backingEntries.remove(); toRemove = null; @@ -145,7 +150,9 @@ public int getCount() { @Override public void remove() { - checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } size -= toRemove.getValue().getAndSet(0); backingEntries.remove(); toRemove = null; @@ -213,13 +220,15 @@ public E next() { } occurrencesLeft--; canRemove = true; - return currentEntry.getKey(); + // requireNonNull is safe because of the occurrencesLeft check. + return requireNonNull(currentEntry).getKey(); } @Override public void remove() { checkRemove(canRemove); - int frequency = currentEntry.getValue().get(); + // requireNonNull is safe because of the canRemove check. + int frequency = requireNonNull(currentEntry).getValue().get(); if (frequency <= 0) { throw new ConcurrentModificationException(); } @@ -247,7 +256,7 @@ public int count(@Nullable Object element) { */ @CanIgnoreReturnValue @Override - public int add(@Nullable E element, int occurrences) { + public int add(E element, int occurrences) { if (occurrences == 0) { return count(element); } @@ -297,7 +306,7 @@ public int remove(@Nullable Object element, int occurrences) { // Roughly a 33% performance improvement over AbstractMultiset.setCount(). @CanIgnoreReturnValue @Override - public int setCount(@Nullable E element, int count) { + public int setCount(E element, int count) { checkNonnegative(count, "count"); Count existingCounter; diff --git a/guava/src/com/google/common/collect/AbstractMapEntry.java b/guava/src/com/google/common/collect/AbstractMapEntry.java index 267897db6210..bfb8ee79de3d 100644 --- a/guava/src/com/google/common/collect/AbstractMapEntry.java +++ b/guava/src/com/google/common/collect/AbstractMapEntry.java @@ -28,7 +28,8 @@ * @author Jared Levy */ @GwtCompatible -abstract class AbstractMapEntry implements Entry { +abstract class AbstractMapEntry + implements Entry { @Override public abstract K getKey(); @@ -44,7 +45,8 @@ public V setValue(V value) { @Override public boolean equals(@Nullable Object object) { if (object instanceof Entry) { - Entry that = (Entry) object; + Entry that = + (Entry) object; return Objects.equal(this.getKey(), that.getKey()) && Objects.equal(this.getValue(), that.getValue()); } diff --git a/guava/src/com/google/common/collect/AbstractMultimap.java b/guava/src/com/google/common/collect/AbstractMultimap.java index fedafd2bf91c..f1ec5ce2d2c1 100644 --- a/guava/src/com/google/common/collect/AbstractMultimap.java +++ b/guava/src/com/google/common/collect/AbstractMultimap.java @@ -37,7 +37,8 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class AbstractMultimap implements Multimap { +abstract class AbstractMultimap + implements Multimap { @Override public boolean isEmpty() { return size() == 0; @@ -69,13 +70,13 @@ public boolean remove(@Nullable Object key, @Nullable Object value) { @CanIgnoreReturnValue @Override - public boolean put(@Nullable K key, @Nullable V value) { + public boolean put(K key, V value) { return get(key).add(value); } @CanIgnoreReturnValue @Override - public boolean putAll(@Nullable K key, Iterable values) { + public boolean putAll(K key, Iterable values) { checkNotNull(values); // make sure we only call values.iterator() once // and we only call get(key) if values is nonempty @@ -100,7 +101,7 @@ public boolean putAll(Multimap multimap) { @CanIgnoreReturnValue @Override - public Collection replaceValues(@Nullable K key, Iterable values) { + public Collection replaceValues(K key, Iterable values) { checkNotNull(values); Collection result = removeAll(key); putAll(key, values); diff --git a/guava/src/com/google/common/collect/AbstractMultiset.java b/guava/src/com/google/common/collect/AbstractMultiset.java index 1bf372148018..68751b6b0499 100644 --- a/guava/src/com/google/common/collect/AbstractMultiset.java +++ b/guava/src/com/google/common/collect/AbstractMultiset.java @@ -42,7 +42,8 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class AbstractMultiset extends AbstractCollection implements Multiset { +abstract class AbstractMultiset extends AbstractCollection + implements Multiset { // Query Operations @Override @@ -58,14 +59,14 @@ public boolean contains(@Nullable Object element) { // Modification Operations @CanIgnoreReturnValue @Override - public final boolean add(@Nullable E element) { + public final boolean add(E element) { add(element, 1); return true; } @CanIgnoreReturnValue @Override - public int add(@Nullable E element, int occurrences) { + public int add(E element, int occurrences) { throw new UnsupportedOperationException(); } @@ -83,13 +84,13 @@ public int remove(@Nullable Object element, int occurrences) { @CanIgnoreReturnValue @Override - public int setCount(@Nullable E element, int count) { + public int setCount(E element, int count) { return setCountImpl(this, element, count); } @CanIgnoreReturnValue @Override - public boolean setCount(@Nullable E element, int oldCount, int newCount) { + public boolean setCount(E element, int oldCount, int newCount) { return setCountImpl(this, element, oldCount, newCount); } diff --git a/guava/src/com/google/common/collect/AbstractNavigableMap.java b/guava/src/com/google/common/collect/AbstractNavigableMap.java index b0200d7245b0..c92a82bf20be 100644 --- a/guava/src/com/google/common/collect/AbstractNavigableMap.java +++ b/guava/src/com/google/common/collect/AbstractNavigableMap.java @@ -32,8 +32,8 @@ * @author Louis Wasserman */ @GwtIncompatible -abstract class AbstractNavigableMap extends IteratorBasedAbstractMap - implements NavigableMap { +abstract class AbstractNavigableMap + extends IteratorBasedAbstractMap implements NavigableMap { @Override public abstract @Nullable V get(@Nullable Object key); @@ -99,22 +99,22 @@ public K lastKey() { } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return Maps.keyOrNull(lowerEntry(key)); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return Maps.keyOrNull(floorEntry(key)); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return Maps.keyOrNull(ceilingEntry(key)); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return Maps.keyOrNull(higherEntry(key)); } diff --git a/guava/src/com/google/common/collect/AbstractRangeSet.java b/guava/src/com/google/common/collect/AbstractRangeSet.java index 1c454cdfc318..e78caac1c45a 100644 --- a/guava/src/com/google/common/collect/AbstractRangeSet.java +++ b/guava/src/com/google/common/collect/AbstractRangeSet.java @@ -32,7 +32,7 @@ public boolean contains(C value) { } @Override - public abstract Range rangeContaining(C value); + public abstract @Nullable Range rangeContaining(C value); @Override public boolean isEmpty() { diff --git a/guava/src/com/google/common/collect/AbstractSequentialIterator.java b/guava/src/com/google/common/collect/AbstractSequentialIterator.java index 37540c2f00fb..c658491d03b0 100644 --- a/guava/src/com/google/common/collect/AbstractSequentialIterator.java +++ b/guava/src/com/google/common/collect/AbstractSequentialIterator.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.NoSuchElementException; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -40,7 +41,8 @@ * @since 12.0 (in Guava as {@code AbstractLinkedIterator} since 8.0) */ @GwtCompatible -public abstract class AbstractSequentialIterator extends UnmodifiableIterator { +public abstract class AbstractSequentialIterator + extends UnmodifiableIterator { private @Nullable T nextOrNull; /** @@ -65,7 +67,7 @@ public final boolean hasNext() { @Override public final T next() { - if (!hasNext()) { + if (nextOrNull == null) { throw new NoSuchElementException(); } try { diff --git a/guava/src/com/google/common/collect/AbstractSetMultimap.java b/guava/src/com/google/common/collect/AbstractSetMultimap.java index 326f99808d95..0866f4e44c1e 100644 --- a/guava/src/com/google/common/collect/AbstractSetMultimap.java +++ b/guava/src/com/google/common/collect/AbstractSetMultimap.java @@ -33,8 +33,8 @@ * @author Jared Levy */ @GwtCompatible -abstract class AbstractSetMultimap extends AbstractMapBasedMultimap - implements SetMultimap { +abstract class AbstractSetMultimap + extends AbstractMapBasedMultimap implements SetMultimap { /** * Creates a new multimap that uses the provided map. * @@ -53,11 +53,14 @@ Set createUnmodifiableEmptyCollection() { } @Override - Collection unmodifiableCollectionSubclass(Collection collection) { + Collection unmodifiableCollectionSubclass( + Collection collection) { return Collections.unmodifiableSet((Set) collection); } @Override + // https://github.com/typetools/checker-framework/issues/3022 + @SuppressWarnings("argument.type.incompatible") Collection wrapCollection(K key, Collection collection) { return new WrappedSet(key, (Set) collection); } @@ -71,7 +74,7 @@ Collection wrapCollection(K key, Collection collection) { * {@link Set}, instead of the {@link Collection} specified in the {@link Multimap} interface. */ @Override - public Set get(@Nullable K key) { + public Set get(K key) { return (Set) super.get(key); } @@ -108,7 +111,7 @@ public Set removeAll(@Nullable Object key) { */ @CanIgnoreReturnValue @Override - public Set replaceValues(@Nullable K key, Iterable values) { + public Set replaceValues(K key, Iterable values) { return (Set) super.replaceValues(key, values); } @@ -133,7 +136,7 @@ public Map> asMap() { */ @CanIgnoreReturnValue @Override - public boolean put(@Nullable K key, @Nullable V value) { + public boolean put(K key, V value) { return super.put(key, value); } diff --git a/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java b/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java index 0ee6edb1e090..a582e83b4e52 100644 --- a/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java +++ b/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Basic implementation of a {@link SortedSetMultimap} with a sorted key set. @@ -31,7 +32,9 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class AbstractSortedKeySortedSetMultimap extends AbstractSortedSetMultimap { +abstract class AbstractSortedKeySortedSetMultimap< + K, V> + extends AbstractSortedSetMultimap { AbstractSortedKeySortedSetMultimap(SortedMap> map) { super(map); diff --git a/guava/src/com/google/common/collect/AbstractSortedMultiset.java b/guava/src/com/google/common/collect/AbstractSortedMultiset.java index 67d629a40fec..37a79fe07008 100644 --- a/guava/src/com/google/common/collect/AbstractSortedMultiset.java +++ b/guava/src/com/google/common/collect/AbstractSortedMultiset.java @@ -33,7 +33,8 @@ * @author Louis Wasserman */ @GwtCompatible(emulated = true) -abstract class AbstractSortedMultiset extends AbstractMultiset implements SortedMultiset { +abstract class AbstractSortedMultiset extends AbstractMultiset + implements SortedMultiset { @GwtTransient final Comparator comparator; // needed for serialization @@ -62,19 +63,19 @@ public Comparator comparator() { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { Iterator> entryIterator = entryIterator(); return entryIterator.hasNext() ? entryIterator.next() : null; } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { Iterator> entryIterator = descendingEntryIterator(); return entryIterator.hasNext() ? entryIterator.next() : null; } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { Iterator> entryIterator = entryIterator(); if (entryIterator.hasNext()) { Entry result = entryIterator.next(); @@ -86,7 +87,7 @@ public Entry pollFirstEntry() { } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { Iterator> entryIterator = descendingEntryIterator(); if (entryIterator.hasNext()) { Entry result = entryIterator.next(); @@ -99,10 +100,7 @@ public Entry pollLastEntry() { @Override public SortedMultiset subMultiset( - @Nullable E fromElement, - BoundType fromBoundType, - @Nullable E toElement, - BoundType toBoundType) { + E fromElement, BoundType fromBoundType, E toElement, BoundType toBoundType) { // These are checked elsewhere, but NullPointerTester wants them checked eagerly. checkNotNull(fromBoundType); checkNotNull(toBoundType); diff --git a/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java b/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java index 2e4de2e63ef2..feeddee7568e 100644 --- a/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java +++ b/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java @@ -33,8 +33,8 @@ * @author Jared Levy */ @GwtCompatible -abstract class AbstractSortedSetMultimap extends AbstractSetMultimap - implements SortedSetMultimap { +abstract class AbstractSortedSetMultimap + extends AbstractSetMultimap implements SortedSetMultimap { /** * Creates a new multimap that uses the provided map. * @@ -53,7 +53,8 @@ SortedSet createUnmodifiableEmptyCollection() { } @Override - SortedSet unmodifiableCollectionSubclass(Collection collection) { + SortedSet unmodifiableCollectionSubclass( + Collection collection) { if (collection instanceof NavigableSet) { return Sets.unmodifiableNavigableSet((NavigableSet) collection); } else { @@ -62,6 +63,8 @@ SortedSet unmodifiableCollectionSubclass(Collection collection) { } @Override + // https://github.com/typetools/checker-framework/issues/3022 + @SuppressWarnings("argument.type.incompatible") Collection wrapCollection(K key, Collection collection) { if (collection instanceof NavigableSet) { return new WrappedNavigableSet(key, (NavigableSet) collection, null); @@ -83,7 +86,7 @@ Collection wrapCollection(K key, Collection collection) { * Multimap} interface. */ @Override - public SortedSet get(@Nullable K key) { + public SortedSet get(K key) { return (SortedSet) super.get(key); } @@ -112,7 +115,7 @@ public SortedSet removeAll(@Nullable Object key) { */ @CanIgnoreReturnValue @Override - public SortedSet replaceValues(@Nullable K key, Iterable values) { + public SortedSet replaceValues(K key, Iterable values) { return (SortedSet) super.replaceValues(key, values); } diff --git a/guava/src/com/google/common/collect/AbstractTable.java b/guava/src/com/google/common/collect/AbstractTable.java index 823570d787af..c35a66fff4bd 100644 --- a/guava/src/com/google/common/collect/AbstractTable.java +++ b/guava/src/com/google/common/collect/AbstractTable.java @@ -33,7 +33,9 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class AbstractTable implements Table { +abstract class AbstractTable< + R, C, V> + implements Table { @Override public boolean containsRow(@Nullable Object rowKey) { @@ -72,7 +74,7 @@ public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) { } @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { Map row = Maps.safeGet(rowMap(), rowKey); return (row == null) ? null : Maps.safeGet(row, columnKey); } @@ -89,14 +91,14 @@ public void clear() { @CanIgnoreReturnValue @Override - public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { Map row = Maps.safeGet(rowMap(), rowKey); return (row == null) ? null : Maps.safeRemove(row, columnKey); } @CanIgnoreReturnValue @Override - public V put(R rowKey, C columnKey, V value) { + public @Nullable V put(R rowKey, C columnKey, V value) { return row(rowKey).put(columnKey, value); } @@ -126,9 +128,15 @@ Set> createCellSet() { @WeakOuter class CellSet extends AbstractSet> { @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { if (o instanceof Cell) { - Cell cell = (Cell) o; + Cell + cell = + (Cell< + ?, + ?, + ?>) + o; Map row = Maps.safeGet(rowMap(), cell.getRowKey()); return row != null && Collections2.safeContains( @@ -140,7 +148,13 @@ public boolean contains(Object o) { @Override public boolean remove(@Nullable Object o) { if (o instanceof Cell) { - Cell cell = (Cell) o; + Cell + cell = + (Cell< + ?, + ?, + ?>) + o; Map row = Maps.safeGet(rowMap(), cell.getRowKey()); return row != null && Collections2.safeRemove( @@ -208,7 +222,7 @@ public Spliterator spliterator() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return containsValue(o); } diff --git a/guava/src/com/google/common/collect/AllEqualOrdering.java b/guava/src/com/google/common/collect/AllEqualOrdering.java index 357b1fcd2c0f..d77afd09be69 100644 --- a/guava/src/com/google/common/collect/AllEqualOrdering.java +++ b/guava/src/com/google/common/collect/AllEqualOrdering.java @@ -27,7 +27,7 @@ * @author Emily Soldal */ @GwtCompatible(serializable = true) -final class AllEqualOrdering extends Ordering implements Serializable { +final class AllEqualOrdering extends Ordering<@Nullable Object> implements Serializable { static final AllEqualOrdering INSTANCE = new AllEqualOrdering(); @Override @@ -41,11 +41,13 @@ public List sortedCopy(Iterable iterable) { } @Override + // Unsafe, but forced by Ordering and our choice for allEqual to accept nulls. + @SuppressWarnings("nullness") public ImmutableList immutableSortedCopy(Iterable iterable) { return ImmutableList.copyOf(iterable); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "nullness"}) @Override public Ordering reverse() { return (Ordering) this; diff --git a/guava/src/com/google/common/collect/ArrayListMultimap.java b/guava/src/com/google/common/collect/ArrayListMultimap.java index bebdae6fbdb4..d6031163eb55 100644 --- a/guava/src/com/google/common/collect/ArrayListMultimap.java +++ b/guava/src/com/google/common/collect/ArrayListMultimap.java @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Implementation of {@code Multimap} that uses an {@code ArrayList} to store the values for a given @@ -118,7 +119,8 @@ private ArrayListMultimap(Multimap multimap) { this( multimap.keySet().size(), (multimap instanceof ArrayListMultimap) - ? ((ArrayListMultimap) multimap).expectedValuesPerKey + ? ((ArrayListMultimap) multimap) + .expectedValuesPerKey : DEFAULT_VALUES_PER_KEY); putAll(multimap); } diff --git a/guava/src/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java b/guava/src/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java index 9a8cdfbdbd13..18b445587e2b 100644 --- a/guava/src/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java +++ b/guava/src/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Collection; import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A dummy superclass to support GWT serialization of the element types of an {@link @@ -30,7 +31,8 @@ *

    TODO(cpovirk): Consider applying this subclass approach to our other types. */ @GwtCompatible(emulated = true) -abstract class ArrayListMultimapGwtSerializationDependencies +abstract class ArrayListMultimapGwtSerializationDependencies< + K, V> extends AbstractListMultimap { ArrayListMultimapGwtSerializationDependencies(Map> map) { super(map); diff --git a/guava/src/com/google/common/collect/ArrayTable.java b/guava/src/com/google/common/collect/ArrayTable.java index 3c391447bfc9..391b61ae3567 100644 --- a/guava/src/com/google/common/collect/ArrayTable.java +++ b/guava/src/com/google/common/collect/ArrayTable.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkElementIndex; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Collections.emptyMap; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -31,10 +32,12 @@ import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.Spliterator; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -78,7 +81,9 @@ */ @Beta @GwtCompatible(emulated = true) -public final class ArrayTable extends AbstractTable implements Serializable { +public final class ArrayTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends AbstractTable implements Serializable { /** * Creates an {@code ArrayTable} filled with {@code null}. @@ -89,8 +94,8 @@ public final class ArrayTable extends AbstractTable implements * @throws IllegalArgumentException if {@code rowKeys} or {@code columnKeys} contains duplicates * or if exactly one of {@code rowKeys} or {@code columnKeys} is empty. */ - public static ArrayTable create( - Iterable rowKeys, Iterable columnKeys) { + public static + ArrayTable create(Iterable rowKeys, Iterable columnKeys) { return new ArrayTable<>(rowKeys, columnKeys); } @@ -118,8 +123,9 @@ public static ArrayTable create( * * @throws NullPointerException if {@code table} has a null key */ - public static ArrayTable create(Table table) { - return (table instanceof ArrayTable) + public static + ArrayTable create(Table table) { + return (table instanceof ArrayTable) ? new ArrayTable((ArrayTable) table) : new ArrayTable(table); } @@ -130,7 +136,7 @@ public static ArrayTable create(Table table) { // TODO(jlevy): Add getters returning rowKeyToIndex and columnKeyToIndex? private final ImmutableMap rowKeyToIndex; private final ImmutableMap columnKeyToIndex; - private final V[][] array; + private final @Nullable V[][] array; private ArrayTable(Iterable rowKeys, Iterable columnKeys) { this.rowList = ImmutableList.copyOf(rowKeys); @@ -147,13 +153,14 @@ private ArrayTable(Iterable rowKeys, Iterable columnKe columnKeyToIndex = Maps.indexMap(columnList); @SuppressWarnings("unchecked") - V[][] tmpArray = (V[][]) new Object[rowList.size()][columnList.size()]; + @Nullable + V[][] tmpArray = (@Nullable V[][]) new Object[rowList.size()][columnList.size()]; array = tmpArray; // Necessary because in GWT the arrays are initialized with "undefined" instead of null. eraseAll(); } - private ArrayTable(Table table) { + private ArrayTable(Table table) { this(table.rowKeySet(), table.columnKeySet()); putAll(table); } @@ -164,14 +171,16 @@ private ArrayTable(ArrayTable table) { rowKeyToIndex = table.rowKeyToIndex; columnKeyToIndex = table.columnKeyToIndex; @SuppressWarnings("unchecked") - V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()]; + @Nullable + V[][] copy = (@Nullable V[][]) new Object[rowList.size()][columnList.size()]; array = copy; for (int i = 0; i < rowList.size(); i++) { System.arraycopy(table.array[i], 0, copy[i], 0, table.array[i].length); } } - private abstract static class ArrayMap extends IteratorBasedAbstractMap { + private abstract static class ArrayMap + extends IteratorBasedAbstractMap { private final ImmutableMap keyIndex; private ArrayMap(ImmutableMap keyIndex) { @@ -189,9 +198,9 @@ K getKey(int index) { abstract String getKeyRole(); - abstract @Nullable V getValue(int index); + abstract V getValue(int index); - abstract @Nullable V setValue(int index, V newValue); + abstract V setValue(int index, V newValue); @Override public int size() { @@ -246,7 +255,7 @@ public boolean containsKey(@Nullable Object key) { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { Integer index = keyIndex.get(key); if (index == null) { return null; @@ -256,7 +265,7 @@ public V get(@Nullable Object key) { } @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { Integer index = keyIndex.get(key); if (index == null) { throw new IllegalArgumentException( @@ -266,7 +275,7 @@ public V put(K key, V value) { } @Override - public V remove(Object key) { + public @Nullable V remove(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -304,7 +313,7 @@ public ImmutableList columnKeyList() { * or equal to the number of allowed row keys, or {@code columnIndex} is greater than or equal * to the number of allowed column keys */ - public V at(int rowIndex, int columnIndex) { + public @Nullable V at(int rowIndex, int columnIndex) { // In GWT array access never throws IndexOutOfBoundsException. checkElementIndex(rowIndex, rowList.size()); checkElementIndex(columnIndex, columnList.size()); @@ -325,7 +334,7 @@ public V at(int rowIndex, int columnIndex) { * to the number of allowed column keys */ @CanIgnoreReturnValue - public V set(int rowIndex, int columnIndex, @Nullable V value) { + public @Nullable V set(int rowIndex, int columnIndex, @Nullable V value) { // In GWT array access never throws IndexOutOfBoundsException. checkElementIndex(rowIndex, rowList.size()); checkElementIndex(columnIndex, columnList.size()); @@ -344,9 +353,11 @@ public V set(int rowIndex, int columnIndex, @Nullable V value) { * @param valueClass class of values stored in the returned array */ @GwtIncompatible // reflection - public V[][] toArray(Class valueClass) { +@SuppressWarnings("nullness") + public @Nullable V[][] toArray(Class valueClass) { @SuppressWarnings("unchecked") // TODO: safe? - V[][] copy = (V[][]) Array.newInstance(valueClass, rowList.size(), columnList.size()); + @Nullable + V[][] copy = (@Nullable V[][]) Array.newInstance(valueClass, rowList.size(), columnList.size()); for (int i = 0; i < rowList.size(); i++) { System.arraycopy(array[i], 0, copy[i], 0, array[i].length); } @@ -367,7 +378,7 @@ public void clear() { /** Associates the value {@code null} with every pair of allowed row and column keys. */ public void eraseAll() { - for (V[] row : array) { + for (@Nullable V[] row : array) { Arrays.fill(row, null); } } @@ -401,7 +412,7 @@ public boolean containsRow(@Nullable Object rowKey) { @Override public boolean containsValue(@Nullable Object value) { - for (V[] row : array) { + for (@Nullable V[] row : array) { for (V element : row) { if (Objects.equal(value, element)) { return true; @@ -411,8 +422,9 @@ public boolean containsValue(@Nullable Object value) { return false; } + // The return type is "extremely" @Nullable, since this is a Table. @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { Integer rowIndex = rowKeyToIndex.get(rowKey); Integer columnIndex = columnKeyToIndex.get(columnKey); return (rowIndex == null || columnIndex == null) ? null : at(rowIndex, columnIndex); @@ -434,13 +446,17 @@ public boolean isEmpty() { */ @CanIgnoreReturnValue @Override - public V put(R rowKey, C columnKey, @Nullable V value) { + public @Nullable V put(R rowKey, C columnKey, @Nullable V value) { checkNotNull(rowKey); checkNotNull(columnKey); Integer rowIndex = rowKeyToIndex.get(rowKey); - checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList); + if (rowIndex == null) { + throw new IllegalArgumentException("Row " + rowKey + " not in " + rowList); + } Integer columnIndex = columnKeyToIndex.get(columnKey); - checkArgument(columnIndex != null, "Column %s not in %s", columnKey, columnList); + if (columnIndex == null) { + throw new IllegalArgumentException("Column " + columnKey + " not in " + columnList); + } return set(rowIndex, columnIndex, value); } @@ -460,7 +476,7 @@ public V put(R rowKey, C columnKey, @Nullable V value) { * in {@link #rowKeySet()} or {@link #columnKeySet()} */ @Override - public void putAll(Table table) { + public void putAll(Table table) { super.putAll(table); } @@ -473,7 +489,7 @@ public void putAll(Table table) { @CanIgnoreReturnValue @Override @Deprecated - public V remove(Object rowKey, Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { throw new UnsupportedOperationException(); } @@ -491,7 +507,7 @@ public V remove(Object rowKey, Object columnKey) { * for the keys */ @CanIgnoreReturnValue - public V erase(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V erase(@Nullable Object rowKey, @Nullable Object columnKey) { Integer rowIndex = rowKeyToIndex.get(rowKey); Integer columnIndex = columnKeyToIndex.get(columnKey); if (rowIndex == null || columnIndex == null) { @@ -519,28 +535,28 @@ public int size() { * @return set of table cells consisting of row key / column key / value triplets */ @Override - public Set> cellSet() { + public Set> cellSet() { return super.cellSet(); } @Override - Iterator> cellIterator() { - return new AbstractIndexedListIterator>(size()) { + Iterator> cellIterator() { + return new AbstractIndexedListIterator>(size()) { @Override - protected Cell get(final int index) { + protected Cell get(final int index) { return getCell(index); } }; } @Override - Spliterator> cellSpliterator() { - return CollectSpliterators.indexed( + Spliterator> cellSpliterator() { + return CollectSpliterators.>indexed( size(), Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.DISTINCT, this::getCell); } - private Cell getCell(final int index) { - return new Tables.AbstractCell() { + private Cell getCell(final int index) { + return new Tables.AbstractCell() { final int rowIndex = index / columnList.size(); final int columnIndex = index % columnList.size(); @@ -555,13 +571,13 @@ public C getColumnKey() { } @Override - public V getValue() { + public @Nullable V getValue() { return at(rowIndex, columnIndex); } }; } - private V getValue(int index) { + private @Nullable V getValue(int index) { int rowIndex = index / columnList.size(); int columnIndex = index % columnList.size(); return at(rowIndex, columnIndex); @@ -579,13 +595,17 @@ private V getValue(int index) { * @return the corresponding map from row keys to values */ @Override - public Map column(C columnKey) { + public Map column(C columnKey) { checkNotNull(columnKey); Integer columnIndex = columnKeyToIndex.get(columnKey); - return (columnIndex == null) ? ImmutableMap.of() : new Column(columnIndex); + if (columnIndex == null) { + return emptyMap(); + } else { + return new Column(columnIndex); + } } - private class Column extends ArrayMap { + private class Column extends ArrayMap { final int columnIndex; Column(int columnIndex) { @@ -599,12 +619,14 @@ String getKeyRole() { } @Override + @Nullable V getValue(int index) { return at(index, columnIndex); } @Override - V setValue(int index, V newValue) { + @Nullable + V setValue(int index, @Nullable V newValue) { return set(index, columnIndex, newValue); } } @@ -623,13 +645,13 @@ public ImmutableSet columnKeySet() { private transient @Nullable ColumnMap columnMap; @Override - public Map> columnMap() { + public Map> columnMap() { ColumnMap map = columnMap; return (map == null) ? columnMap = new ColumnMap() : map; } @WeakOuter - private class ColumnMap extends ArrayMap> { + private class ColumnMap extends ArrayMap> { private ColumnMap() { super(columnKeyToIndex); } @@ -640,17 +662,17 @@ String getKeyRole() { } @Override - Map getValue(int index) { + Map getValue(int index) { return new Column(index); } @Override - Map setValue(int index, Map newValue) { + Map setValue(int index, Map newValue) { throw new UnsupportedOperationException(); } @Override - public Map put(C key, Map value) { + public @Nullable Map put(C key, Map value) { throw new UnsupportedOperationException(); } } @@ -667,13 +689,18 @@ public Map put(C key, Map value) { * @return the corresponding map from column keys to values */ @Override - public Map row(R rowKey) { + public Map row(R rowKey) { checkNotNull(rowKey); Integer rowIndex = rowKeyToIndex.get(rowKey); - return (rowIndex == null) ? ImmutableMap.of() : new Row(rowIndex); + // Avoid ternary operator to appease our prototype nullness checker. + if (rowIndex == null) { + return emptyMap(); + } else { + return new Row(rowIndex); + } } - private class Row extends ArrayMap { + private class Row extends ArrayMap { final int rowIndex; Row(int rowIndex) { @@ -687,12 +714,14 @@ String getKeyRole() { } @Override + @Nullable V getValue(int index) { return at(rowIndex, index); } @Override - V setValue(int index, V newValue) { + @Nullable + V setValue(int index, @Nullable V newValue) { return set(rowIndex, index, newValue); } } @@ -711,13 +740,13 @@ public ImmutableSet rowKeySet() { private transient @Nullable RowMap rowMap; @Override - public Map> rowMap() { + public Map> rowMap() { RowMap map = rowMap; return (map == null) ? rowMap = new RowMap() : map; } @WeakOuter - private class RowMap extends ArrayMap> { + private class RowMap extends ArrayMap> { private RowMap() { super(rowKeyToIndex); } @@ -728,17 +757,17 @@ String getKeyRole() { } @Override - Map getValue(int index) { + Map getValue(int index) { return new Row(index); } @Override - Map setValue(int index, Map newValue) { + Map setValue(int index, Map newValue) { throw new UnsupportedOperationException(); } @Override - public Map put(R key, Map value) { + public Map put(R key, Map value) { throw new UnsupportedOperationException(); } } @@ -753,23 +782,23 @@ public Map put(R key, Map value) { * @return collection of values */ @Override - public Collection values() { + public Collection<@Nullable V> values() { return super.values(); } @Override - Iterator valuesIterator() { - return new AbstractIndexedListIterator(size()) { + Iterator<@Nullable V> valuesIterator() { + return new AbstractIndexedListIterator<@Nullable V>(size()) { @Override - protected V get(int index) { + protected @Nullable V get(int index) { return getValue(index); } }; } @Override - Spliterator valuesSpliterator() { - return CollectSpliterators.indexed(size(), Spliterator.ORDERED, this::getValue); + Spliterator<@Nullable V> valuesSpliterator() { + return CollectSpliterators.<@Nullable V>indexed(size(), Spliterator.ORDERED, this::getValue); } private static final long serialVersionUID = 0; diff --git a/guava/src/com/google/common/collect/BaseImmutableMultimap.java b/guava/src/com/google/common/collect/BaseImmutableMultimap.java index 6ebdf14f52fa..94c90c491aa8 100644 --- a/guava/src/com/google/common/collect/BaseImmutableMultimap.java +++ b/guava/src/com/google/common/collect/BaseImmutableMultimap.java @@ -16,10 +16,12 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A dummy superclass of {@link ImmutableMultimap} that can be instanceof'd without ProGuard * retaining additional implementation details of {@link ImmutableMultimap}. */ @GwtCompatible -abstract class BaseImmutableMultimap extends AbstractMultimap {} +abstract class BaseImmutableMultimap + extends AbstractMultimap {} diff --git a/guava/src/com/google/common/collect/BiMap.java b/guava/src/com/google/common/collect/BiMap.java index e4a755ebb250..10e73a936225 100644 --- a/guava/src/com/google/common/collect/BiMap.java +++ b/guava/src/com/google/common/collect/BiMap.java @@ -47,7 +47,7 @@ public interface BiMap extends Map { @CanIgnoreReturnValue @Override @Nullable - V put(@Nullable K key, @Nullable V value); + V put(K key, V value); /** * An alternate form of {@code put} that silently removes any existing entry with the value {@code @@ -67,7 +67,7 @@ public interface BiMap extends Map { */ @CanIgnoreReturnValue @Nullable - V forcePut(@Nullable K key, @Nullable V value); + V forcePut(K key, V value); // Bulk Operations diff --git a/guava/src/com/google/common/collect/ByFunctionOrdering.java b/guava/src/com/google/common/collect/ByFunctionOrdering.java index f05bf01aa9ed..2cf9ae74fb41 100644 --- a/guava/src/com/google/common/collect/ByFunctionOrdering.java +++ b/guava/src/com/google/common/collect/ByFunctionOrdering.java @@ -29,7 +29,8 @@ * elements. */ @GwtCompatible(serializable = true) -final class ByFunctionOrdering extends Ordering implements Serializable { +final class ByFunctionOrdering + extends Ordering implements Serializable { final Function function; final Ordering ordering; @@ -49,7 +50,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof ByFunctionOrdering) { - ByFunctionOrdering that = (ByFunctionOrdering) object; + ByFunctionOrdering that = + (ByFunctionOrdering) object; return this.function.equals(that.function) && this.ordering.equals(that.ordering); } return false; diff --git a/guava/src/com/google/common/collect/CartesianList.java b/guava/src/com/google/common/collect/CartesianList.java index 6077ef49da14..041bae12ebec 100644 --- a/guava/src/com/google/common/collect/CartesianList.java +++ b/guava/src/com/google/common/collect/CartesianList.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.ListIterator; import java.util.RandomAccess; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -30,12 +31,13 @@ * @author Louis Wasserman */ @GwtCompatible -final class CartesianList extends AbstractList> implements RandomAccess { +final class CartesianList extends AbstractList> + implements RandomAccess { private final transient ImmutableList> axes; private final transient int[] axesSizeProduct; - static List> create(List> lists) { + static List> create(List> lists) { ImmutableList.Builder> axesBuilder = new ImmutableList.Builder<>(lists.size()); for (List list : lists) { List copy = ImmutableList.copyOf(list); @@ -67,7 +69,7 @@ private int getAxisIndexForProductIndex(int index, int axis) { } @Override - public int indexOf(Object o) { + public int indexOf(@Nullable Object o) { if (!(o instanceof List)) { return -1; } diff --git a/guava/src/com/google/common/collect/ClassToInstanceMap.java b/guava/src/com/google/common/collect/ClassToInstanceMap.java index a173556b150c..e6307095787b 100644 --- a/guava/src/com/google/common/collect/ClassToInstanceMap.java +++ b/guava/src/com/google/common/collect/ClassToInstanceMap.java @@ -18,8 +18,8 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -41,15 +41,15 @@ * @author Kevin Bourrillion * @since 2.0 */ -@DoNotMock("Use ImmutableClassToInstanceMap or MutableClassToInstanceMap") @GwtCompatible -public interface ClassToInstanceMap extends Map, B> { +public interface ClassToInstanceMap + extends Map, @Nullable B> { /** * Returns the value the specified class is mapped to, or {@code null} if no entry for this class * is present. This will only return a value that was bound to this specific class, not a value * that may have been bound to a subtype. */ - T getInstance(Class type); + @Nullable T getInstance(Class type); /** * Maps the specified class to the specified value. Does not associate this value with any @@ -59,5 +59,5 @@ public interface ClassToInstanceMap extends Map, B> { * null} if there was no previous entry. */ @CanIgnoreReturnValue - T putInstance(Class type, @Nullable T value); + @Nullable T putInstance(Class type, @Nullable T value); } diff --git a/guava/src/com/google/common/collect/CollectCollectors.java b/guava/src/com/google/common/collect/CollectCollectors.java index 8e038c8a613b..4556703101f4 100644 --- a/guava/src/com/google/common/collect/CollectCollectors.java +++ b/guava/src/com/google/common/collect/CollectCollectors.java @@ -23,13 +23,16 @@ import java.util.Comparator; import java.util.function.Function; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** Collectors utilities for {@code common.collect} internals. */ @GwtCompatible final class CollectCollectors { - static Collector> toImmutableBiMap( - Function keyFunction, - Function valueFunction) { + static + Collector> toImmutableBiMap( + Function keyFunction, + Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); return Collector.of( @@ -40,20 +43,22 @@ final class CollectCollectors { new Collector.Characteristics[0]); } - private static final Collector> TO_IMMUTABLE_LIST = + private static final Collector TO_IMMUTABLE_LIST = Collector.of( ImmutableList::builder, ImmutableList.Builder::add, ImmutableList.Builder::combine, ImmutableList.Builder::build); - static Collector> toImmutableList() { - return (Collector) TO_IMMUTABLE_LIST; + @SuppressWarnings({"unchecked", "nullness"}) + static Collector> toImmutableList() { + return (Collector>) TO_IMMUTABLE_LIST; } - static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction) { + static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); return Collector.of( @@ -63,21 +68,23 @@ final class CollectCollectors { ImmutableMap.Builder::build); } - private static final Collector> TO_IMMUTABLE_SET = + private static final Collector TO_IMMUTABLE_SET = Collector.of( ImmutableSet::builder, ImmutableSet.Builder::add, ImmutableSet.Builder::combine, ImmutableSet.Builder::build); - static Collector> toImmutableSet() { - return (Collector) TO_IMMUTABLE_SET; + @SuppressWarnings({"unchecked", "nullness"}) + static Collector> toImmutableSet() { + return (Collector>) TO_IMMUTABLE_SET; } - static Collector> toImmutableSortedMap( - Comparator comparator, - Function keyFunction, - Function valueFunction) { + static + Collector> toImmutableSortedMap( + Comparator comparator, + Function keyFunction, + Function valueFunction) { checkNotNull(comparator); checkNotNull(keyFunction); checkNotNull(valueFunction); @@ -93,7 +100,7 @@ final class CollectCollectors { Collector.Characteristics.UNORDERED); } - static Collector> toImmutableSortedSet( + static Collector> toImmutableSortedSet( Comparator comparator) { checkNotNull(comparator); return Collector.of( @@ -119,7 +126,7 @@ final class CollectCollectors { } @GwtIncompatible - static , V> + static , V extends @NonNull Object> Collector> toImmutableRangeMap( Function> keyFunction, Function valueFunction) { diff --git a/guava/src/com/google/common/collect/CollectPreconditions.java b/guava/src/com/google/common/collect/CollectPreconditions.java index 98b30c6d5e7b..0c7c2ee0d47c 100644 --- a/guava/src/com/google/common/collect/CollectPreconditions.java +++ b/guava/src/com/google/common/collect/CollectPreconditions.java @@ -16,8 +16,6 @@ package com.google.common.collect; -import static com.google.common.base.Preconditions.checkState; - import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -60,6 +58,12 @@ static void checkPositive(int value, String name) { * error message. */ static void checkRemove(boolean canRemove) { - checkState(canRemove, "no calls to next() since the last call to remove()"); + if (!canRemove) { + throw noCallsToNextSinceLastRemove(); + } + } + + static IllegalStateException noCallsToNextSinceLastRemove() { + return new IllegalStateException("no calls to next() since the last call to remove()"); } } diff --git a/guava/src/com/google/common/collect/CollectSpliterators.java b/guava/src/com/google/common/collect/CollectSpliterators.java index 974f77fdc0ec..8aadfef4e0ef 100644 --- a/guava/src/com/google/common/collect/CollectSpliterators.java +++ b/guava/src/com/google/common/collect/CollectSpliterators.java @@ -38,7 +38,8 @@ final class CollectSpliterators { private CollectSpliterators() {} - static Spliterator indexed(int size, int extraCharacteristics, IntFunction function) { + static Spliterator indexed( + int size, int extraCharacteristics, IntFunction function) { return indexed(size, extraCharacteristics, function, null); } @@ -46,7 +47,7 @@ static Spliterator indexed( int size, int extraCharacteristics, IntFunction function, - Comparator comparator) { + @Nullable Comparator comparator) { if (comparator != null) { checkArgument((extraCharacteristics & Spliterator.SORTED) != 0); } @@ -87,7 +88,7 @@ public int characteristics() { } @Override - public Comparator getComparator() { + public @Nullable Comparator getComparator() { if (hasCharacteristics(Spliterator.SORTED)) { return comparator; } else { @@ -102,9 +103,10 @@ public Comparator getComparator() { * Returns a {@code Spliterator} over the elements of {@code fromSpliterator} mapped by {@code * function}. */ - static Spliterator map( - Spliterator fromSpliterator, - Function function) { + static + Spliterator map( + Spliterator fromSpliterator, + Function function) { checkNotNull(fromSpliterator); checkNotNull(function); return new Spliterator() { @@ -121,7 +123,7 @@ public void forEachRemaining(Consumer action) { } @Override - public Spliterator trySplit() { + public @Nullable Spliterator trySplit() { Spliterator fromSplit = fromSpliterator.trySplit(); return (fromSplit != null) ? map(fromSplit, function) : null; } @@ -140,11 +142,12 @@ public int characteristics() { } /** Returns a {@code Spliterator} filtered by the specified predicate. */ - static Spliterator filter(Spliterator fromSpliterator, Predicate predicate) { + static Spliterator filter( + Spliterator fromSpliterator, Predicate predicate) { checkNotNull(fromSpliterator); checkNotNull(predicate); class Splitr implements Spliterator, Consumer { - T holder = null; + @Nullable T holder = null; @Override public void accept(T t) { @@ -155,8 +158,10 @@ public void accept(T t) { public boolean tryAdvance(Consumer action) { while (fromSpliterator.tryAdvance(this)) { try { - if (predicate.test(holder)) { - action.accept(holder); + // The cast is safe because tryAdvance puts a T into `holder`. + T next = uncheckedCastNullableTToT(holder); + if (predicate.test(next)) { + action.accept(uncheckedCastNullableTToT(next)); return true; } } finally { @@ -167,7 +172,7 @@ public boolean tryAdvance(Consumer action) { } @Override - public Spliterator trySplit() { + public @Nullable Spliterator trySplit() { Spliterator fromSplit = fromSpliterator.trySplit(); return (fromSplit == null) ? null : filter(fromSplit, predicate); } @@ -178,7 +183,7 @@ public long estimateSize() { } @Override - public Comparator getComparator() { + public @Nullable Comparator getComparator() { return fromSpliterator.getComparator(); } @@ -194,15 +199,27 @@ public int characteristics() { return new Splitr(); } + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T element) { + /* + * We can't use requireNonNull because `element` might be null. Specifically, it can be null + * because the spliterator might contain a null element to be returned to the user. This is in + * contrast to the other way for `element` to be null, which is for the spliterator not to have + * a next value computed yet. + */ + return element; + } + /** * Returns a {@code Spliterator} that iterates over the elements of the spliterators generated by * applying {@code function} to the elements of {@code fromSpliterator}. */ - static Spliterator flatMap( - Spliterator fromSpliterator, - Function> function, - int topCharacteristics, - long topSize) { + static + Spliterator flatMap( + Spliterator fromSpliterator, + Function> function, + int topCharacteristics, + long topSize) { checkArgument( (topCharacteristics & Spliterator.SUBSIZED) == 0, "flatMap does not support SUBSIZED characteristic"); @@ -289,13 +306,17 @@ static Spliterator.OfDouble flatMapToDouble( * @param the type of the output spliterators */ abstract static class FlatMapSpliterator< - InElementT, OutElementT, OutSpliteratorT extends Spliterator> + InElementT, + OutElementT, + OutSpliteratorT extends Spliterator> implements Spliterator { /** Factory for constructing {@link FlatMapSpliterator} instances. */ @FunctionalInterface - interface Factory> { + interface Factory< + InElementT, + OutSpliteratorT extends Spliterator> { OutSpliteratorT newFlatMapSpliterator( - OutSpliteratorT prefix, + @Nullable OutSpliteratorT prefix, Spliterator fromSplit, Function function, int splitCharacteristics, @@ -310,7 +331,7 @@ OutSpliteratorT newFlatMapSpliterator( long estimatedSize; FlatMapSpliterator( - OutSpliteratorT prefix, + @Nullable OutSpliteratorT prefix, Spliterator from, Function function, Factory factory, @@ -365,7 +386,7 @@ public final void forEachRemaining(Consumer action) { } @Override - public final OutSpliteratorT trySplit() { + public final @Nullable OutSpliteratorT trySplit() { Spliterator fromSplit = from.trySplit(); if (fromSplit != null) { int splitCharacteristics = characteristics & ~Spliterator.SIZED; @@ -414,10 +435,11 @@ public final int characteristics() { * @param the element type of the input spliterator * @param the element type of the output spliterators */ - static final class FlatMapSpliteratorOfObject + static final class FlatMapSpliteratorOfObject< + InElementT, OutElementT> extends FlatMapSpliterator> { FlatMapSpliteratorOfObject( - Spliterator prefix, + @Nullable Spliterator prefix, Spliterator from, Function> function, int characteristics, @@ -445,7 +467,7 @@ abstract static class FlatMapSpliteratorOfPrimitive< implements Spliterator.OfPrimitive { FlatMapSpliteratorOfPrimitive( - OutSpliteratorT prefix, + @Nullable OutSpliteratorT prefix, Spliterator from, Function function, Factory factory, @@ -493,7 +515,7 @@ static final class FlatMapSpliteratorOfInt extends FlatMapSpliteratorOfPrimitive implements Spliterator.OfInt { FlatMapSpliteratorOfInt( - Spliterator.OfInt prefix, + Spliterator.@Nullable OfInt prefix, Spliterator from, Function function, int characteristics, @@ -507,7 +529,7 @@ static final class FlatMapSpliteratorOfLong extends FlatMapSpliteratorOfPrimitive implements Spliterator.OfLong { FlatMapSpliteratorOfLong( - Spliterator.OfLong prefix, + Spliterator.@Nullable OfLong prefix, Spliterator from, Function function, int characteristics, @@ -522,7 +544,7 @@ static final class FlatMapSpliteratorOfDouble InElementT, Double, DoubleConsumer, Spliterator.OfDouble> implements Spliterator.OfDouble { FlatMapSpliteratorOfDouble( - Spliterator.OfDouble prefix, + Spliterator.@Nullable OfDouble prefix, Spliterator from, Function function, int characteristics, diff --git a/guava/src/com/google/common/collect/Collections2.java b/guava/src/com/google/common/collect/Collections2.java index 2685be9daa9b..e875a1b64acd 100644 --- a/guava/src/com/google/common/collect/Collections2.java +++ b/guava/src/com/google/common/collect/Collections2.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -37,6 +38,7 @@ import java.util.List; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -83,7 +85,8 @@ private Collections2() {} */ // TODO(kevinb): how can we omit that Iterables link when building gwt // javadoc? - public static Collection filter(Collection unfiltered, Predicate predicate) { + public static Collection filter( + Collection unfiltered, Predicate predicate) { if (unfiltered instanceof FilteredCollection) { // Support clear(), removeAll(), and retainAll() when filtering a filtered // collection. @@ -97,7 +100,8 @@ public static Collection filter(Collection unfiltered, Predicate collection, @Nullable Object object) { + static boolean safeContains( + Collection collection, @Nullable Object object) { checkNotNull(collection); try { return collection.contains(object); @@ -110,7 +114,8 @@ static boolean safeContains(Collection collection, @Nullable Object object) { * Delegates to {@link Collection#remove}. Returns {@code false} if the {@code remove} method * throws a {@code ClassCastException} or {@code NullPointerException}. */ - static boolean safeRemove(Collection collection, @Nullable Object object) { + static boolean safeRemove( + Collection collection, @Nullable Object object) { checkNotNull(collection); try { return collection.remove(object); @@ -194,7 +199,7 @@ public void forEach(Consumer action) { } @Override - public boolean remove(Object element) { + public boolean remove(@Nullable Object element) { return contains(element) && unfiltered.remove(element); } @@ -226,12 +231,14 @@ public int size() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { // creating an ArrayList so filtering happens once return Lists.newArrayList(iterator()).toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return Lists.newArrayList(iterator()).toArray(array); } @@ -261,7 +268,8 @@ public static Collection transform( return new TransformedCollection<>(fromCollection, function); } - static class TransformedCollection extends AbstractCollection { + static class TransformedCollection + extends AbstractCollection { final Collection fromCollection; final Function function; @@ -319,7 +327,8 @@ public int size() { * @param self a collection which might contain all elements in {@code c} * @param c a collection whose elements might be contained by {@code self} */ - static boolean containsAllImpl(Collection self, Collection c) { + static boolean containsAllImpl( + Collection self, Collection c) { for (Object o : c) { if (!self.contains(o)) { return false; @@ -432,12 +441,13 @@ public static > Collection> orderedPermu * @since 12.0 */ @Beta - public static Collection> orderedPermutations( + public static Collection> orderedPermutations( Iterable elements, Comparator comparator) { return new OrderedPermutationCollection(elements, comparator); } - private static final class OrderedPermutationCollection extends AbstractCollection> { + private static final class OrderedPermutationCollection + extends AbstractCollection> { final ImmutableList inputList; final Comparator comparator; final int size; @@ -457,7 +467,7 @@ private static final class OrderedPermutationCollection extends AbstractColle * increased by a factor of (n choose r). * */ - private static int calculateSize( + private static int calculateSize( List sortedInputList, Comparator comparator) { int permutations = 1; int n = 1; @@ -508,7 +518,8 @@ public String toString() { } } - private static final class OrderedPermutationIterator extends AbstractIterator> { + private static final class OrderedPermutationIterator + extends AbstractIterator> { @Nullable List nextPermutation; final Comparator comparator; @@ -533,6 +544,11 @@ void calculateNextPermutation() { nextPermutation = null; return; } + /* + * requireNonNull is safe because we don't clear nextPermutation until we're done calling this + * method. + */ + requireNonNull(nextPermutation); int l = findNextL(j); Collections.swap(nextPermutation, j, l); @@ -541,6 +557,11 @@ void calculateNextPermutation() { } int findNextJ() { + /* + * requireNonNull is safe because we don't clear nextPermutation until we're done calling this + * method. + */ + requireNonNull(nextPermutation); for (int k = nextPermutation.size() - 2; k >= 0; k--) { if (comparator.compare(nextPermutation.get(k), nextPermutation.get(k + 1)) < 0) { return k; @@ -550,6 +571,11 @@ int findNextJ() { } int findNextL(int j) { + /* + * requireNonNull is safe because we don't clear nextPermutation until we're done calling this + * method. + */ + requireNonNull(nextPermutation); E ak = nextPermutation.get(j); for (int l = nextPermutation.size() - 1; l > j; l--) { if (comparator.compare(ak, nextPermutation.get(l)) < 0) { @@ -578,11 +604,13 @@ int findNextL(int j) { * @since 12.0 */ @Beta - public static Collection> permutations(Collection elements) { + public static Collection> permutations( + Collection elements) { return new PermutationCollection(ImmutableList.copyOf(elements)); } - private static final class PermutationCollection extends AbstractCollection> { + private static final class PermutationCollection + extends AbstractCollection> { final ImmutableList inputList; PermutationCollection(ImmutableList input) { @@ -619,7 +647,8 @@ public String toString() { } } - private static class PermutationIterator extends AbstractIterator> { + private static class PermutationIterator + extends AbstractIterator> { final List list; final int[] c; final int[] o; @@ -683,7 +712,8 @@ void switchDirection() { } /** Returns {@code true} if the second list is a permutation of the first. */ - private static boolean isPermutation(List first, List second) { + private static boolean isPermutation( + List first, List second) { if (first.size() != second.size()) { return false; } diff --git a/guava/src/com/google/common/collect/CompactHashMap.java b/guava/src/com/google/common/collect/CompactHashMap.java index a68890e82b03..95c2e484286a 100644 --- a/guava/src/com/google/common/collect/CompactHashMap.java +++ b/guava/src/com/google/common/collect/CompactHashMap.java @@ -76,7 +76,9 @@ * @author Jon Noack */ @GwtIncompatible // not worth using in GWT for now -class CompactHashMap extends AbstractMap implements Serializable { +@SuppressWarnings("nullness") // too much effort for the payoff +class CompactHashMap + extends AbstractMap implements Serializable { /* * TODO: Make this a drop-in replacement for j.u. versions, actually drop them in, and test the * world. Figure out what sort of space-time tradeoff we're actually going to get here with the @@ -86,7 +88,8 @@ class CompactHashMap extends AbstractMap implements Serializable { */ /** Creates an empty {@code CompactHashMap} instance. */ - public static CompactHashMap create() { + public static + CompactHashMap create() { return new CompactHashMap<>(); } @@ -99,7 +102,8 @@ public static CompactHashMap create() { * elements without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ - public static CompactHashMap createWithExpectedSize(int expectedSize) { + public static + CompactHashMap createWithExpectedSize(int expectedSize) { return new CompactHashMap<>(expectedSize); } @@ -109,9 +113,7 @@ public static CompactHashMap createWithExpectedSize(int expectedSiz * Maximum allowed false positive probability of detecting a hash flooding attack given random * input. */ - @VisibleForTesting( - ) - static final double HASH_FLOODING_FPP = 0.001; + @VisibleForTesting() static final double HASH_FLOODING_FPP = 0.001; /** * Maximum allowed length of a hash table bucket before falling back to a j.u.LinkedHashMap-based @@ -138,7 +140,7 @@ public static CompactHashMap createWithExpectedSize(int expectedSiz *
  • null, if no entries have yet been added to the map * */ - @Nullable private transient Object table; + private transient @Nullable Object table; /** * Contains the logical entries, in the range of [0, size()). The high bits of each int are the @@ -161,13 +163,13 @@ public static CompactHashMap createWithExpectedSize(int expectedSiz * The keys of the entries in the map, in the range of [0, size()). The keys in [size(), * keys.length) are all {@code null}. */ - @VisibleForTesting transient Object @Nullable [] keys; + @VisibleForTesting transient @Nullable Object @Nullable [] keys; /** * The values of the entries in the map, in the range of [0, size()). The values in [size(), * values.length) are all {@code null}. */ - @VisibleForTesting transient Object @Nullable [] values; + @VisibleForTesting transient @Nullable Object @Nullable [] values; /** * Keeps track of metadata like the number of hash table bits and modifications of this data @@ -219,8 +221,8 @@ int allocArrays() { setHashTableMask(buckets - 1); this.entries = new int[expectedSize]; - this.keys = new Object[expectedSize]; - this.values = new Object[expectedSize]; + this.keys = new @Nullable Object[expectedSize]; + this.values = new @Nullable Object[expectedSize]; return expectedSize; } @@ -281,11 +283,11 @@ void accessEntry(int index) { @CanIgnoreReturnValue @Override - public @Nullable V put(@Nullable K key, @Nullable V value) { + public @Nullable V put(K key, V value) { if (needsAllocArrays()) { allocArrays(); } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.put(key, value); } @@ -349,7 +351,7 @@ void accessEntry(int index) { /** * Creates a fresh entry with the specified object at the specified position in the entry arrays. */ - void insertEntry(int entryIndex, @Nullable K key, @Nullable V value, int hash, int mask) { + void insertEntry(int entryIndex, K key, V value, int hash, int mask) { this.entries[entryIndex] = CompactHashing.maskCombine(hash, UNSET, mask); this.keys[entryIndex] = key; this.values[entryIndex] = value; @@ -440,14 +442,14 @@ private int indexOf(@Nullable Object key) { @Override public boolean containsKey(@Nullable Object key) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.containsKey(key) : indexOf(key) != -1; } @SuppressWarnings("unchecked") // known to be a V @Override - public V get(@Nullable Object key) { - @Nullable Map delegate = delegateOrNull(); + public @Nullable V get(@Nullable Object key) { + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.get(key); } @@ -463,7 +465,7 @@ public V get(@Nullable Object key) { @SuppressWarnings("unchecked") // known to be a V @Override public @Nullable V remove(@Nullable Object key) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.remove(key); } @@ -471,7 +473,7 @@ public V get(@Nullable Object key) { return (oldValue == NOT_FOUND) ? null : (V) oldValue; } - private @Nullable Object removeHelper(@Nullable Object key) { + private Object removeHelper(@Nullable Object key) { if (needsAllocArrays()) { return NOT_FOUND; } @@ -483,7 +485,7 @@ public V get(@Nullable Object key) { return NOT_FOUND; } - @Nullable Object oldValue = values[index]; + Object oldValue = values[index]; moveLastEntry(index, mask); size--; @@ -499,7 +501,7 @@ void moveLastEntry(int dstIndex, int mask) { int srcIndex = size() - 1; if (dstIndex < srcIndex) { // move last entry to deleted spot - @Nullable Object key = keys[srcIndex]; + Object key = keys[srcIndex]; keys[dstIndex] = key; values[dstIndex] = values[srcIndex]; keys[srcIndex] = null; @@ -601,7 +603,7 @@ private void checkForConcurrentModification() { @Override public void replaceAll(BiFunction function) { checkNotNull(function); - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { delegate.replaceAll(function); } else { @@ -629,17 +631,19 @@ class KeySetView extends Maps.KeySet { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { if (needsAllocArrays()) { return new Object[0]; } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.keySet().toArray() : ObjectArrays.copyAsObjectArray(keys, 0, size); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { if (needsAllocArrays()) { if (a.length > 0) { @@ -647,7 +651,7 @@ public T[] toArray(T[] a) { } return a; } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.keySet().toArray(a) : ObjectArrays.toArrayImpl(keys, 0, size, a); @@ -655,7 +659,7 @@ public T[] toArray(T[] a) { @Override public boolean remove(@Nullable Object o) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.keySet().remove(o) : CompactHashMap.this.removeHelper(o) != NOT_FOUND; @@ -671,7 +675,7 @@ public Spliterator spliterator() { if (needsAllocArrays()) { return Spliterators.spliterator(new Object[0], Spliterator.DISTINCT | Spliterator.ORDERED); } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.keySet().spliterator() : Spliterators.spliterator(keys, 0, size, Spliterator.DISTINCT | Spliterator.ORDERED); @@ -681,7 +685,7 @@ public Spliterator spliterator() { @Override public void forEach(Consumer action) { checkNotNull(action); - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { delegate.keySet().forEach(action); } else { @@ -693,7 +697,7 @@ public void forEach(Consumer action) { } Iterator keySetIterator() { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.keySet().iterator(); } @@ -710,7 +714,7 @@ K getOutput(int entry) { @Override public void forEach(BiConsumer action) { checkNotNull(action); - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { delegate.forEach(action); } else { @@ -745,7 +749,7 @@ public Iterator> iterator() { @Override public Spliterator> spliterator() { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.entrySet().spliterator() : CollectSpliterators.indexed( @@ -754,11 +758,12 @@ public Spliterator> spliterator() { @Override public boolean contains(@Nullable Object o) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.entrySet().contains(o); } else if (o instanceof Entry) { - Entry entry = (Entry) o; + Entry entry = + (Entry) o; int index = indexOf(entry.getKey()); return index != -1 && Objects.equal(values[index], entry.getValue()); } @@ -767,11 +772,12 @@ public boolean contains(@Nullable Object o) { @Override public boolean remove(@Nullable Object o) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.entrySet().remove(o); } else if (o instanceof Entry) { - Entry entry = (Entry) o; + Entry entry = + (Entry) o; if (needsAllocArrays()) { return false; } @@ -794,7 +800,7 @@ public boolean remove(@Nullable Object o) { } Iterator> entrySetIterator() { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.entrySet().iterator(); } @@ -807,7 +813,7 @@ Entry getOutput(int entry) { } final class MapEntry extends AbstractMapEntry { - private final @Nullable K key; + private final K key; private int lastKnownIndex; @@ -817,7 +823,6 @@ final class MapEntry extends AbstractMapEntry { this.lastKnownIndex = index; } - @Nullable @Override public K getKey() { return key; @@ -833,26 +838,28 @@ private void updateLastKnownIndex() { @SuppressWarnings("unchecked") // known to be a V @Override - public @Nullable V getValue() { - @Nullable Map delegate = delegateOrNull(); + public V getValue() { + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.get(key); } updateLastKnownIndex(); - return (lastKnownIndex == -1) ? null : (V) values[lastKnownIndex]; + // TODO(cpovirk): Maybe Map.Entry.getValue+setValue should return @Nullable V? + return (lastKnownIndex == -1) ? unsafeNull() : (V) values[lastKnownIndex]; } @SuppressWarnings("unchecked") // known to be a V @Override public V setValue(V value) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.put(key, value); } updateLastKnownIndex(); if (lastKnownIndex == -1) { put(key, value); - return null; + // TODO(cpovirk): Maybe Map.Entry.getValue+setValue should return @Nullable V? + return unsafeNull(); } else { V old = (V) values[lastKnownIndex]; values[lastKnownIndex] = value; @@ -861,9 +868,14 @@ public V setValue(V value) { } } + @SuppressWarnings("nullness") + private static V unsafeNull() { + return null; + } + @Override public int size() { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.size() : size; } @@ -874,7 +886,7 @@ public boolean isEmpty() { @Override public boolean containsValue(@Nullable Object value) { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.containsValue(value); } @@ -912,7 +924,7 @@ public Iterator iterator() { @Override public void forEach(Consumer action) { checkNotNull(action); - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { delegate.values().forEach(action); } else { @@ -927,24 +939,26 @@ public Spliterator spliterator() { if (needsAllocArrays()) { return Spliterators.spliterator(new Object[0], Spliterator.ORDERED); } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.values().spliterator() : Spliterators.spliterator(values, 0, size, Spliterator.ORDERED); } @Override +@SuppressWarnings("nullness") public Object[] toArray() { if (needsAllocArrays()) { return new Object[0]; } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.values().toArray() : ObjectArrays.copyAsObjectArray(values, 0, size); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { if (needsAllocArrays()) { if (a.length > 0) { @@ -952,7 +966,7 @@ public T[] toArray(T[] a) { } return a; } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); return (delegate != null) ? delegate.values().toArray(a) : ObjectArrays.toArrayImpl(values, 0, size, a); @@ -960,7 +974,7 @@ public T[] toArray(T[] a) { } Iterator valuesIterator() { - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { return delegate.values().iterator(); } @@ -981,7 +995,7 @@ public void trimToSize() { if (needsAllocArrays()) { return; } - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { Map newDelegate = createHashFloodingResistantDelegate(size()); newDelegate.putAll(delegate); @@ -1005,7 +1019,7 @@ public void clear() { return; } incrementModCount(); - @Nullable Map delegate = delegateOrNull(); + Map delegate = delegateOrNull(); if (delegate != null) { metadata = Ints.constrainToRange(size(), CompactHashing.DEFAULT_SIZE, CompactHashing.MAX_SIZE); diff --git a/guava/src/com/google/common/collect/CompactHashSet.java b/guava/src/com/google/common/collect/CompactHashSet.java index d54e16648143..8f7e7e2ae994 100644 --- a/guava/src/com/google/common/collect/CompactHashSet.java +++ b/guava/src/com/google/common/collect/CompactHashSet.java @@ -74,6 +74,7 @@ * @author Jon Noack */ @GwtIncompatible // not worth using in GWT for now +@SuppressWarnings("nullness") // too much effort for the payoff class CompactHashSet extends AbstractSet implements Serializable { // TODO(user): cache all field accesses in local vars @@ -89,7 +90,8 @@ public static CompactHashSet create() { * @param collection the elements that the set should contain * @return a new {@code CompactHashSet} containing those elements (minus duplicates) */ - public static CompactHashSet create(Collection collection) { + public static CompactHashSet create( + Collection collection) { CompactHashSet set = createWithExpectedSize(collection.size()); set.addAll(collection); return set; @@ -118,7 +120,8 @@ public static CompactHashSet create(E... elements) { * elements without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ - public static CompactHashSet createWithExpectedSize(int expectedSize) { + public static CompactHashSet createWithExpectedSize( + int expectedSize) { return new CompactHashSet<>(expectedSize); } @@ -126,9 +129,7 @@ public static CompactHashSet createWithExpectedSize(int expectedSize) { * Maximum allowed false positive probability of detecting a hash flooding attack given random * input. */ - @VisibleForTesting( - ) - static final double HASH_FLOODING_FPP = 0.001; + @VisibleForTesting() static final double HASH_FLOODING_FPP = 0.001; /** * Maximum allowed length of a hash table bucket before falling back to a j.u.LinkedHashSet based @@ -155,7 +156,7 @@ public static CompactHashSet createWithExpectedSize(int expectedSize) { *
  • null, if no entries have yet been added to the map * */ - @Nullable private transient Object table; + private transient @Nullable Object table; /** * Contains the logical entries, in the range of [0, size()). The high bits of each int are the @@ -178,7 +179,7 @@ public static CompactHashSet createWithExpectedSize(int expectedSize) { * The elements contained in the set, in the range of [0, size()). The elements in [size(), * elements.length) are all {@code null}. */ - @VisibleForTesting transient Object @Nullable [] elements; + @VisibleForTesting transient @Nullable Object @Nullable [] elements; /** * Keeps track of metadata like the number of hash table bits and modifications of this data @@ -230,7 +231,7 @@ int allocArrays() { setHashTableMask(buckets - 1); this.entries = new int[expectedSize]; - this.elements = new Object[expectedSize]; + this.elements = new @Nullable Object[expectedSize]; return expectedSize; } @@ -287,11 +288,11 @@ void incrementModCount() { @CanIgnoreReturnValue @Override - public boolean add(@Nullable E object) { + public boolean add(E object) { if (needsAllocArrays()) { allocArrays(); } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { return delegate.add(object); } @@ -348,7 +349,7 @@ public boolean add(@Nullable E object) { /** * Creates a fresh entry with the specified object at the specified position in the entry arrays. */ - void insertEntry(int entryIndex, @Nullable E object, int hash, int mask) { + void insertEntry(int entryIndex, E object, int hash, int mask) { this.entries[entryIndex] = CompactHashing.maskCombine(hash, UNSET, mask); this.elements[entryIndex] = object; } @@ -417,7 +418,7 @@ public boolean contains(@Nullable Object object) { if (needsAllocArrays()) { return false; } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { return delegate.contains(object); } @@ -446,7 +447,7 @@ public boolean remove(@Nullable Object object) { if (needsAllocArrays()) { return false; } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { return delegate.remove(object); } @@ -472,7 +473,7 @@ void moveLastEntry(int dstIndex, int mask) { int srcIndex = size() - 1; if (dstIndex < srcIndex) { // move last entry to deleted spot - @Nullable Object object = elements[srcIndex]; + Object object = elements[srcIndex]; elements[dstIndex] = object; elements[srcIndex] = null; @@ -524,7 +525,7 @@ int adjustAfterRemove(int indexBeforeRemove, @SuppressWarnings("unused") int ind @Override public Iterator iterator() { - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { return delegate.iterator(); } @@ -578,7 +579,7 @@ public Spliterator spliterator() { if (needsAllocArrays()) { return Spliterators.spliterator(new Object[0], Spliterator.DISTINCT | Spliterator.ORDERED); } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); return (delegate != null) ? delegate.spliterator() : Spliterators.spliterator(elements, 0, size, Spliterator.DISTINCT | Spliterator.ORDERED); @@ -588,7 +589,7 @@ public Spliterator spliterator() { @Override public void forEach(Consumer action) { checkNotNull(action); - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { delegate.forEach(action); } else { @@ -600,7 +601,7 @@ public void forEach(Consumer action) { @Override public int size() { - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); return (delegate != null) ? delegate.size() : size; } @@ -610,16 +611,18 @@ public boolean isEmpty() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { if (needsAllocArrays()) { return new Object[0]; } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); return (delegate != null) ? delegate.toArray() : Arrays.copyOf(elements, size); } @CanIgnoreReturnValue @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { if (needsAllocArrays()) { if (a.length > 0) { @@ -627,7 +630,7 @@ public T[] toArray(T[] a) { } return a; } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); return (delegate != null) ? delegate.toArray(a) : ObjectArrays.toArrayImpl(elements, 0, size, a); @@ -641,7 +644,7 @@ public void trimToSize() { if (needsAllocArrays()) { return; } - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { Set newDelegate = createHashFloodingResistantDelegate(size()); newDelegate.addAll(delegate); @@ -665,7 +668,7 @@ public void clear() { return; } incrementModCount(); - @Nullable Set delegate = delegateOrNull(); + Set delegate = delegateOrNull(); if (delegate != null) { metadata = Ints.constrainToRange(size(), CompactHashing.DEFAULT_SIZE, CompactHashing.MAX_SIZE); diff --git a/guava/src/com/google/common/collect/CompactHashing.java b/guava/src/com/google/common/collect/CompactHashing.java index 3444aeb84198..e1ae56cf0e43 100644 --- a/guava/src/com/google/common/collect/CompactHashing.java +++ b/guava/src/com/google/common/collect/CompactHashing.java @@ -148,8 +148,8 @@ static int remove( int mask, Object table, int[] entries, - Object[] keys, - Object @Nullable [] values) { + @Nullable Object[] keys, + @Nullable Object @Nullable [] values) { int hash = Hashing.smearedHash(key); int tableIndex = hash & mask; int next = tableGet(table, tableIndex); diff --git a/guava/src/com/google/common/collect/CompactLinkedHashMap.java b/guava/src/com/google/common/collect/CompactLinkedHashMap.java index be878c86a144..962c157dabbd 100644 --- a/guava/src/com/google/common/collect/CompactLinkedHashMap.java +++ b/guava/src/com/google/common/collect/CompactLinkedHashMap.java @@ -50,11 +50,14 @@ * @author Louis Wasserman */ @GwtIncompatible // not worth using in GWT for now -class CompactLinkedHashMap extends CompactHashMap { +@SuppressWarnings("nullness") // too much effort for the payoff +class CompactLinkedHashMap + extends CompactHashMap { // TODO(lowasser): implement removeEldestEntry so this can be used as a drop-in replacement /** Creates an empty {@code CompactLinkedHashMap} instance. */ - public static CompactLinkedHashMap create() { + public static + CompactLinkedHashMap create() { return new CompactLinkedHashMap<>(); } @@ -67,7 +70,8 @@ public static CompactLinkedHashMap create() { * expectedSize} elements without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ - public static CompactLinkedHashMap createWithExpectedSize(int expectedSize) { + public static + CompactLinkedHashMap createWithExpectedSize(int expectedSize) { return new CompactLinkedHashMap<>(expectedSize); } @@ -166,7 +170,7 @@ private void setSucceeds(int pred, int succ) { } @Override - void insertEntry(int entryIndex, @Nullable K key, @Nullable V value, int hash, int mask) { + void insertEntry(int entryIndex, K key, V value, int hash, int mask) { super.insertEntry(entryIndex, key, value, hash, mask); setSucceeds(lastEntry, entryIndex); setSucceeds(entryIndex, ENDPOINT); @@ -230,11 +234,13 @@ Set createKeySet() { @WeakOuter class KeySetImpl extends KeySetView { @Override +@SuppressWarnings("nullness") public Object[] toArray() { return ObjectArrays.toArrayImpl(this); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { return ObjectArrays.toArrayImpl(this, a); } @@ -252,11 +258,13 @@ Collection createValues() { @WeakOuter class ValuesImpl extends ValuesView { @Override +@SuppressWarnings("nullness") public Object[] toArray() { return ObjectArrays.toArrayImpl(this); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { return ObjectArrays.toArrayImpl(this, a); } diff --git a/guava/src/com/google/common/collect/CompactLinkedHashSet.java b/guava/src/com/google/common/collect/CompactLinkedHashSet.java index 74caf47e367b..2e918366cd7a 100644 --- a/guava/src/com/google/common/collect/CompactLinkedHashSet.java +++ b/guava/src/com/google/common/collect/CompactLinkedHashSet.java @@ -48,6 +48,7 @@ * @author Louis Wasserman */ @GwtIncompatible // not worth using in GWT for now +@SuppressWarnings("nullness") // too much effort for the payoff class CompactLinkedHashSet extends CompactHashSet { /** Creates an empty {@code CompactLinkedHashSet} instance. */ @@ -62,7 +63,8 @@ public static CompactLinkedHashSet create() { * @param collection the elements that the set should contain * @return a new {@code CompactLinkedHashSet} containing those elements (minus duplicates) */ - public static CompactLinkedHashSet create(Collection collection) { + public static CompactLinkedHashSet create( + Collection collection) { CompactLinkedHashSet set = createWithExpectedSize(collection.size()); set.addAll(collection); return set; @@ -91,7 +93,8 @@ public static CompactLinkedHashSet create(E... elements) { * expectedSize} elements without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ - public static CompactLinkedHashSet createWithExpectedSize(int expectedSize) { + public static CompactLinkedHashSet createWithExpectedSize( + int expectedSize) { return new CompactLinkedHashSet<>(expectedSize); } @@ -183,7 +186,7 @@ private void setSucceeds(int pred, int succ) { } @Override - void insertEntry(int entryIndex, @Nullable E object, int hash, int mask) { + void insertEntry(int entryIndex, E object, int hash, int mask) { super.insertEntry(entryIndex, object, hash, mask); setSucceeds(lastEntry, entryIndex); setSucceeds(entryIndex, ENDPOINT); @@ -221,11 +224,13 @@ int adjustAfterRemove(int indexBeforeRemove, int indexRemoved) { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { return ObjectArrays.toArrayImpl(this); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { return ObjectArrays.toArrayImpl(this, a); } diff --git a/guava/src/com/google/common/collect/ComparatorOrdering.java b/guava/src/com/google/common/collect/ComparatorOrdering.java index 52cbf2af6fd8..03123bd04f73 100644 --- a/guava/src/com/google/common/collect/ComparatorOrdering.java +++ b/guava/src/com/google/common/collect/ComparatorOrdering.java @@ -25,7 +25,8 @@ /** An ordering for a pre-existing comparator. */ @GwtCompatible(serializable = true) -final class ComparatorOrdering extends Ordering implements Serializable { +final class ComparatorOrdering extends Ordering + implements Serializable { final Comparator comparator; ComparatorOrdering(Comparator comparator) { @@ -43,7 +44,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof ComparatorOrdering) { - ComparatorOrdering that = (ComparatorOrdering) object; + ComparatorOrdering that = + (ComparatorOrdering) object; return this.comparator.equals(that.comparator); } return false; diff --git a/guava/src/com/google/common/collect/Comparators.java b/guava/src/com/google/common/collect/Comparators.java index 06b398f3ce1e..139d4c96fc32 100644 --- a/guava/src/com/google/common/collect/Comparators.java +++ b/guava/src/com/google/common/collect/Comparators.java @@ -26,6 +26,8 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Provides static methods for working with {@link Comparator} instances. For many other helpful @@ -61,7 +63,8 @@ private Comparators() {} // desired return type. However, *nested* generics introduce a special class of problems that we // think tip it over into being worthwhile. @Beta - public static Comparator> lexicographical(Comparator comparator) { + public static Comparator> lexicographical( + Comparator comparator) { return new LexicographicalOrdering(checkNotNull(comparator)); } @@ -71,7 +74,8 @@ public static Comparator> lexicographical(Comparato * always true when the iterable has fewer than two elements. */ @Beta - public static boolean isInOrder(Iterable iterable, Comparator comparator) { + public static boolean isInOrder( + Iterable iterable, Comparator comparator) { checkNotNull(comparator); Iterator it = iterable.iterator(); if (it.hasNext()) { @@ -130,7 +134,8 @@ public static boolean isInStrictOrder( * @throws IllegalArgumentException if {@code k < 0} * @since 22.0 */ - public static Collector> least(int k, Comparator comparator) { + public static Collector> least( + int k, Comparator comparator) { checkNonnegative(k, "k"); checkNotNull(comparator); return Collector.of( @@ -161,7 +166,8 @@ public static boolean isInStrictOrder( * @throws IllegalArgumentException if {@code k < 0} * @since 22.0 */ - public static Collector> greatest(int k, Comparator comparator) { + public static Collector> greatest( + int k, Comparator comparator) { return least(k, comparator.reversed()); } @@ -173,9 +179,11 @@ public static boolean isInStrictOrder( * @since 22.0 */ @Beta - public static Comparator> emptiesFirst(Comparator valueComparator) { + public static Comparator> emptiesFirst( + Comparator valueComparator) { checkNotNull(valueComparator); - return Comparator.comparing(o -> o.orElse(null), Comparator.nullsFirst(valueComparator)); + return Comparator., @Nullable T>comparing( + o -> o.orElse(null), Comparator.nullsFirst(valueComparator)); } /** @@ -186,8 +194,10 @@ public static Comparator> emptiesFirst(Comparator val * @since 22.0 */ @Beta - public static Comparator> emptiesLast(Comparator valueComparator) { + public static Comparator> emptiesLast( + Comparator valueComparator) { checkNotNull(valueComparator); - return Comparator.comparing(o -> o.orElse(null), Comparator.nullsLast(valueComparator)); + return Comparator., @Nullable T>comparing( + o -> o.orElse(null), Comparator.nullsLast(valueComparator)); } } diff --git a/guava/src/com/google/common/collect/ComparisonChain.java b/guava/src/com/google/common/collect/ComparisonChain.java index 578166de0e93..bff3d169db0d 100644 --- a/guava/src/com/google/common/collect/ComparisonChain.java +++ b/guava/src/com/google/common/collect/ComparisonChain.java @@ -75,7 +75,7 @@ public ComparisonChain compare(Comparable left, Comparable right) { @Override public ComparisonChain compare( - @Nullable T left, @Nullable T right, Comparator comparator) { + T left, T right, Comparator comparator) { return classify(comparator.compare(left, right)); } @@ -131,13 +131,13 @@ private static final class InactiveComparisonChain extends ComparisonChain { } @Override - public ComparisonChain compare(@Nullable Comparable left, @Nullable Comparable right) { + public ComparisonChain compare(Comparable left, Comparable right) { return this; } @Override public ComparisonChain compare( - @Nullable T left, @Nullable T right, @Nullable Comparator comparator) { + T left, T right, Comparator comparator) { return this; } @@ -188,7 +188,7 @@ public int result() { * already been determined. */ public abstract ComparisonChain compare( - @Nullable T left, @Nullable T right, Comparator comparator); + T left, T right, Comparator comparator); /** * Compares two {@code int} values as specified by {@link Ints#compare}, if the result of diff --git a/guava/src/com/google/common/collect/CompoundOrdering.java b/guava/src/com/google/common/collect/CompoundOrdering.java index e803acb4fbb7..c785056391a5 100644 --- a/guava/src/com/google/common/collect/CompoundOrdering.java +++ b/guava/src/com/google/common/collect/CompoundOrdering.java @@ -20,10 +20,12 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; +import org.checkerframework.checker.nullness.qual.Nullable; /** An ordering that tries several comparators in order. */ @GwtCompatible(serializable = true) -final class CompoundOrdering extends Ordering implements Serializable { +final class CompoundOrdering extends Ordering + implements Serializable { final Comparator[] comparators; CompoundOrdering(Comparator primary, Comparator secondary) { @@ -46,12 +48,13 @@ public int compare(T left, T right) { } @Override - public boolean equals(Object object) { + public boolean equals(@Nullable Object object) { if (object == this) { return true; } if (object instanceof CompoundOrdering) { - CompoundOrdering that = (CompoundOrdering) object; + CompoundOrdering that = + (CompoundOrdering) object; return Arrays.equals(this.comparators, that.comparators); } return false; diff --git a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java index 3aaa76e3da3f..fae1687d86d9 100644 --- a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java +++ b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java @@ -19,7 +19,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -41,6 +42,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -56,7 +58,8 @@ * @since 2.0 */ @GwtIncompatible -public final class ConcurrentHashMultiset extends AbstractMultiset implements Serializable { +public final class ConcurrentHashMultiset extends AbstractMultiset + implements Serializable { /* * The ConcurrentHashMultiset's atomic operations are implemented primarily in terms of @@ -82,7 +85,7 @@ private static class FieldSettersHolder { * Creates a new, empty {@code ConcurrentHashMultiset} using the default initial capacity, load * factor, and concurrency settings. */ - public static ConcurrentHashMultiset create() { + public static ConcurrentHashMultiset create() { // TODO(schmoe): provide a way to use this class with other (possibly arbitrary) // ConcurrentMap implementors. One possibility is to extract most of this class into // an AbstractConcurrentMapMultiset. @@ -97,7 +100,8 @@ public static ConcurrentHashMultiset create() { * * @param elements the elements that the multiset should contain */ - public static ConcurrentHashMultiset create(Iterable elements) { + public static ConcurrentHashMultiset create( + Iterable elements) { ConcurrentHashMultiset multiset = ConcurrentHashMultiset.create(); Iterables.addAll(multiset, elements); return multiset; @@ -118,7 +122,8 @@ public static ConcurrentHashMultiset create(Iterable element * @since 20.0 */ @Beta - public static ConcurrentHashMultiset create(ConcurrentMap countMap) { + public static ConcurrentHashMultiset create( + ConcurrentMap countMap) { return new ConcurrentHashMultiset(countMap); } @@ -163,11 +168,13 @@ public int size() { */ @Override +@SuppressWarnings("nullness") public Object[] toArray() { return snapshot().toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return snapshot().toArray(array); } @@ -285,7 +292,8 @@ public int remove(@Nullable Object element, int occurrences) { if (newValue == 0) { // Just CASed to 0; remove the entry to clean up the map. If the removal fails, // another thread has already replaced it with a new counter, which is fine. - countMap.remove(element, existingCounter); + // requireNonNull is safe because of the safeGet check above. + countMap.remove(requireNonNull(element), existingCounter); } return oldValue; } @@ -328,7 +336,8 @@ public boolean removeExactly(@Nullable Object element, int occurrences) { if (newValue == 0) { // Just CASed to 0; remove the entry to clean up the map. If the removal fails, // another thread has already replaced it with a new counter, which is fine. - countMap.remove(element, existingCounter); + // requireNonNull is safe because of the safeGet check above. + countMap.remove(requireNonNull(element), existingCounter); } return true; } @@ -464,7 +473,7 @@ public boolean containsAll(Collection collection) { } @Override - public boolean remove(Object object) { + public boolean remove(@Nullable Object object) { return object != null && Collections2.safeRemove(delegate, object); } @@ -537,7 +546,9 @@ public Entry next() { @Override public void remove() { - checkRemove(last != null); + if (last == null) { + throw noCallsToNextSinceLastRemove(); + } ConcurrentHashMultiset.this.setCount(last.getElement(), 0); last = null; } @@ -567,11 +578,13 @@ ConcurrentHashMultiset multiset() { */ @Override +@SuppressWarnings("nullness") public Object[] toArray() { return snapshot().toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return snapshot().toArray(array); } diff --git a/guava/src/com/google/common/collect/ConsumingQueueIterator.java b/guava/src/com/google/common/collect/ConsumingQueueIterator.java index 2f288f041f4e..e60360d57994 100644 --- a/guava/src/com/google/common/collect/ConsumingQueueIterator.java +++ b/guava/src/com/google/common/collect/ConsumingQueueIterator.java @@ -17,9 +17,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; -import java.util.ArrayDeque; -import java.util.Collections; import java.util.Queue; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An Iterator implementation which draws elements from a queue, removing them from the queue as it @@ -29,11 +28,6 @@ class ConsumingQueueIterator extends AbstractIterator { private final Queue queue; - ConsumingQueueIterator(T... elements) { - this.queue = new ArrayDeque(elements.length); - Collections.addAll(queue, elements); - } - ConsumingQueueIterator(Queue queue) { this.queue = checkNotNull(queue); } diff --git a/guava/src/com/google/common/collect/ContiguousSet.java b/guava/src/com/google/common/collect/ContiguousSet.java index 6755be6eceeb..710a9c84f3fb 100644 --- a/guava/src/com/google/common/collect/ContiguousSet.java +++ b/guava/src/com/google/common/collect/ContiguousSet.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.Beta; import com.google.common.annotations.GwtCompatible; @@ -23,6 +24,7 @@ import java.util.Collections; import java.util.NoSuchElementException; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A sorted set of contiguous values in a given {@link DiscreteDomain}. Example: @@ -77,8 +79,12 @@ public static ContiguousSet create( boolean empty = effectiveRange.isEmpty() || Range.compareOrThrow( - range.lowerBound.leastValueAbove(domain), - range.upperBound.greatestValueBelow(domain)) + /* + * requireNonNull is safe because the effectiveRange operations above would have + * thrown or effectiveRange.isEmpty() would have returned true. + */ + requireNonNull(range.lowerBound.leastValueAbove(domain)), + requireNonNull(range.upperBound.greatestValueBelow(domain))) > 0; return empty @@ -252,7 +258,7 @@ public String toString() { * @deprecated Use {@link #create}. */ @Deprecated - public static ImmutableSortedSet.Builder builder() { + public static ImmutableSortedSet.Builder builder() { throw new UnsupportedOperationException(); } } diff --git a/guava/src/com/google/common/collect/Cut.java b/guava/src/com/google/common/collect/Cut.java index 8f6cd818f738..f5f3714590ef 100644 --- a/guava/src/com/google/common/collect/Cut.java +++ b/guava/src/com/google/common/collect/Cut.java @@ -33,9 +33,9 @@ */ @GwtCompatible abstract class Cut implements Comparable>, Serializable { - final @Nullable C endpoint; + final C endpoint; - Cut(@Nullable C endpoint) { + Cut(C endpoint) { this.endpoint = endpoint; } @@ -53,9 +53,9 @@ abstract class Cut implements Comparable>, Serializ abstract void describeAsUpperBound(StringBuilder sb); - abstract C leastValueAbove(DiscreteDomain domain); + abstract @Nullable C leastValueAbove(DiscreteDomain domain); - abstract C greatestValueBelow(DiscreteDomain domain); + abstract @Nullable C greatestValueBelow(DiscreteDomain domain); /* * The canonical form is a BelowValue cut whenever possible, otherwise ABOVE_ALL, or @@ -88,7 +88,7 @@ C endpoint() { @SuppressWarnings("unchecked") // catching CCE @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof Cut) { // It might not really be a Cut, but we'll catch a CCE if it's not Cut that = (Cut) obj; @@ -119,6 +119,13 @@ static Cut belowAll() { private static final class BelowAll extends Cut> { private static final BelowAll INSTANCE = new BelowAll(); + /* + * No code ever sees this null value for `endpoint`: This class overrides both methods that use + * the `endpoint` field, compareTo() and endpoint(). Additionally, the main implementation of + * Cut.compareTo checks for belowAll before reading accessing `endpoint` on another Cut + * instance. + */ + @SuppressWarnings("nullness") private BelowAll() { super(null); } @@ -218,6 +225,7 @@ static Cut aboveAll() { private static final class AboveAll extends Cut> { private static final AboveAll INSTANCE = new AboveAll(); + @SuppressWarnings("nullness") // see BelowAll private AboveAll() { super(null); } @@ -326,7 +334,7 @@ Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain) { case CLOSED: return this; case OPEN: - @Nullable C previous = domain.previous(endpoint); + C previous = domain.previous(endpoint); return (previous == null) ? Cut.belowAll() : new AboveValue(previous); default: throw new AssertionError(); @@ -337,7 +345,7 @@ Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain) { Cut withUpperBoundType(BoundType boundType, DiscreteDomain domain) { switch (boundType) { case CLOSED: - @Nullable C previous = domain.previous(endpoint); + C previous = domain.previous(endpoint); return (previous == null) ? Cut.aboveAll() : new AboveValue(previous); case OPEN: return this; @@ -362,6 +370,7 @@ C leastValueAbove(DiscreteDomain domain) { } @Override + @Nullable C greatestValueBelow(DiscreteDomain domain) { return domain.previous(endpoint); } @@ -409,7 +418,7 @@ Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain) { case OPEN: return this; case CLOSED: - @Nullable C next = domain.next(endpoint); + C next = domain.next(endpoint); return (next == null) ? Cut.belowAll() : belowValue(next); default: throw new AssertionError(); @@ -420,7 +429,7 @@ Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain) { Cut withUpperBoundType(BoundType boundType, DiscreteDomain domain) { switch (boundType) { case OPEN: - @Nullable C next = domain.next(endpoint); + C next = domain.next(endpoint); return (next == null) ? Cut.aboveAll() : belowValue(next); case CLOSED: return this; @@ -440,6 +449,7 @@ void describeAsUpperBound(StringBuilder sb) { } @Override + @Nullable C leastValueAbove(DiscreteDomain domain) { return domain.next(endpoint); } diff --git a/guava/src/com/google/common/collect/DenseImmutableTable.java b/guava/src/com/google/common/collect/DenseImmutableTable.java index 91c2d484f041..7c0cd36b0fab 100644 --- a/guava/src/com/google/common/collect/DenseImmutableTable.java +++ b/guava/src/com/google/common/collect/DenseImmutableTable.java @@ -14,17 +14,22 @@ package com.google.common.collect; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.GwtCompatible; import com.google.common.collect.ImmutableMap.IteratorBasedImmutableMap; import com.google.errorprone.annotations.Immutable; import com.google.j2objc.annotations.WeakOuter; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** A {@code RegularImmutableTable} optimized for dense data. */ @GwtCompatible @Immutable(containerOf = {"R", "C", "V"}) -final class DenseImmutableTable extends RegularImmutableTable { +final class DenseImmutableTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends RegularImmutableTable { private final ImmutableMap rowKeyToIndex; private final ImmutableMap columnKeyToIndex; private final ImmutableMap> rowMap; @@ -37,7 +42,7 @@ final class DenseImmutableTable extends RegularImmutableTable private final int[] columnCounts; @SuppressWarnings("Immutable") // We don't modify this after construction. - private final V[][] values; + private final @Nullable V[][] values; // For each cell in iteration order, the index of that cell's row key in the row key list. @SuppressWarnings("Immutable") // We don't modify this after construction. @@ -52,7 +57,8 @@ final class DenseImmutableTable extends RegularImmutableTable ImmutableSet rowSpace, ImmutableSet columnSpace) { @SuppressWarnings("unchecked") - V[][] array = (V[][]) new Object[rowSpace.size()][columnSpace.size()]; + @Nullable + V[][] array = (@Nullable V[][]) new Object[rowSpace.size()][columnSpace.size()]; this.values = array; this.rowKeyToIndex = Maps.indexMap(rowSpace); this.columnKeyToIndex = Maps.indexMap(columnSpace); @@ -64,8 +70,9 @@ final class DenseImmutableTable extends RegularImmutableTable Cell cell = cellList.get(i); R rowKey = cell.getRowKey(); C columnKey = cell.getColumnKey(); - int rowIndex = rowKeyToIndex.get(rowKey); - int columnIndex = columnKeyToIndex.get(columnKey); + // The requireNonNull calls are safe because we construct the indexes with indexMap. + int rowIndex = requireNonNull(rowKeyToIndex.get(rowKey)); + int columnIndex = requireNonNull(columnKeyToIndex.get(columnKey)); V existingValue = values[rowIndex][columnIndex]; checkNoDuplicate(rowKey, columnKey, existingValue, cell.getValue()); values[rowIndex][columnIndex] = cell.getValue(); @@ -81,7 +88,9 @@ final class DenseImmutableTable extends RegularImmutableTable } /** An immutable map implementation backed by an indexed nullable array. */ - private abstract static class ImmutableArrayMap extends IteratorBasedImmutableMap { + private abstract static class ImmutableArrayMap< + K extends @NonNull Object, V extends @NonNull Object> + extends IteratorBasedImmutableMap { private final int size; ImmutableArrayMap(int size) { @@ -112,7 +121,7 @@ public int size() { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { Integer keyIndex = keyToIndex().get(key); return (keyIndex == null) ? null : getValue(keyIndex); } @@ -151,6 +160,7 @@ ImmutableMap keyToIndex() { } @Override + @Nullable V getValue(int keyIndex) { return values[rowIndex][keyIndex]; } @@ -175,6 +185,7 @@ ImmutableMap keyToIndex() { } @Override + @Nullable V getValue(int keyIndex) { return values[keyIndex][columnIndex]; } @@ -244,7 +255,7 @@ public ImmutableMap> rowMap() { } @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { Integer rowIndex = rowKeyToIndex.get(rowKey); Integer columnIndex = columnKeyToIndex.get(columnKey); return ((rowIndex == null) || (columnIndex == null)) ? null : values[rowIndex][columnIndex]; @@ -261,13 +272,15 @@ Cell getCell(int index) { int columnIndex = cellColumnIndices[index]; R rowKey = rowKeySet().asList().get(rowIndex); C columnKey = columnKeySet().asList().get(columnIndex); - V value = values[rowIndex][columnIndex]; + // requireNonNull is safe because we use indexes that were populated by the constructor. + V value = requireNonNull(values[rowIndex][columnIndex]); return cellOf(rowKey, columnKey, value); } @Override V getValue(int index) { - return values[cellRowIndices[index]][cellColumnIndices[index]]; + // requireNonNull is safe because we use indexes that were populated by the constructor. + return requireNonNull(values[cellRowIndices[index]][cellColumnIndices[index]]); } @Override diff --git a/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java b/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java index 346bafb5ee20..89bf1638b3e1 100644 --- a/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java +++ b/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java @@ -15,6 +15,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtIncompatible; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -24,7 +25,8 @@ */ @SuppressWarnings("serial") // uses writeReplace, not default serialization @GwtIncompatible -final class DescendingImmutableSortedMultiset extends ImmutableSortedMultiset { +final class DescendingImmutableSortedMultiset + extends ImmutableSortedMultiset { private final transient ImmutableSortedMultiset forward; DescendingImmutableSortedMultiset(ImmutableSortedMultiset forward) { @@ -37,12 +39,12 @@ public int count(@Nullable Object element) { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return forward.lastEntry(); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return forward.firstEntry(); } diff --git a/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java b/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java index 635437837386..2d3d95f3dc80 100644 --- a/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java +++ b/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java @@ -17,6 +17,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtIncompatible; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -25,7 +26,7 @@ * @author Louis Wasserman */ @GwtIncompatible -final class DescendingImmutableSortedSet extends ImmutableSortedSet { +final class DescendingImmutableSortedSet extends ImmutableSortedSet { private final ImmutableSortedSet forward; DescendingImmutableSortedSet(ImmutableSortedSet forward) { @@ -83,22 +84,22 @@ ImmutableSortedSet createDescendingSet() { } @Override - public E lower(E element) { + public @Nullable E lower(E element) { return forward.higher(element); } @Override - public E floor(E element) { + public @Nullable E floor(E element) { return forward.ceiling(element); } @Override - public E ceiling(E element) { + public @Nullable E ceiling(E element) { return forward.floor(element); } @Override - public E higher(E element) { + public @Nullable E higher(E element) { return forward.lower(element); } diff --git a/guava/src/com/google/common/collect/DescendingMultiset.java b/guava/src/com/google/common/collect/DescendingMultiset.java index 74590ac1544a..5232d79aa725 100644 --- a/guava/src/com/google/common/collect/DescendingMultiset.java +++ b/guava/src/com/google/common/collect/DescendingMultiset.java @@ -31,7 +31,8 @@ * @author Louis Wasserman */ @GwtCompatible(emulated = true) -abstract class DescendingMultiset extends ForwardingMultiset implements SortedMultiset { +abstract class DescendingMultiset extends ForwardingMultiset + implements SortedMultiset { abstract SortedMultiset forwardMultiset(); private transient @Nullable Comparator comparator; @@ -57,12 +58,12 @@ public NavigableSet elementSet() { } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { return forwardMultiset().pollLastEntry(); } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { return forwardMultiset().pollFirstEntry(); } @@ -95,12 +96,12 @@ public SortedMultiset descendingMultiset() { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return forwardMultiset().lastEntry(); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return forwardMultiset().firstEntry(); } @@ -141,11 +142,13 @@ public Iterator iterator() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { return standardToArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return standardToArray(array); } diff --git a/guava/src/com/google/common/collect/DiscreteDomain.java b/guava/src/com/google/common/collect/DiscreteDomain.java index 3777a6d4bbc9..c87c8a150fe4 100644 --- a/guava/src/com/google/common/collect/DiscreteDomain.java +++ b/guava/src/com/google/common/collect/DiscreteDomain.java @@ -25,6 +25,7 @@ import java.io.Serializable; import java.math.BigInteger; import java.util.NoSuchElementException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A descriptor for a discrete {@code Comparable} domain such as all {@link Integer} @@ -62,13 +63,13 @@ private static final class IntegerDomain extends DiscreteDomain impleme } @Override - public Integer next(Integer value) { + public @Nullable Integer next(Integer value) { int i = value; return (i == Integer.MAX_VALUE) ? null : i + 1; } @Override - public Integer previous(Integer value) { + public @Nullable Integer previous(Integer value) { int i = value; return (i == Integer.MIN_VALUE) ? null : i - 1; } @@ -123,13 +124,13 @@ private static final class LongDomain extends DiscreteDomain implements Se } @Override - public Long next(Long value) { + public @Nullable Long next(Long value) { long l = value; return (l == Long.MAX_VALUE) ? null : l + 1; } @Override - public Long previous(Long value) { + public @Nullable Long previous(Long value) { long l = value; return (l == Long.MIN_VALUE) ? null : l - 1; } @@ -248,11 +249,16 @@ private DiscreteDomain(boolean supportsFastOffset) { * #next} on {@code origin} {@code distance} times. */ C offset(C origin, long distance) { + C current = origin; checkNonnegative(distance, "distance"); for (long i = 0; i < distance; i++) { - origin = next(origin); + current = next(current); + if (current == null) { + throw new IllegalArgumentException( + "overflowed computing offset(" + origin + ", " + distance + ")"); + } } - return origin; + return current; } /** @@ -263,7 +269,7 @@ C offset(C origin, long distance) { * @return the least value greater than {@code value}, or {@code null} if {@code value} is {@code * maxValue()} */ - public abstract C next(C value); + public abstract @Nullable C next(C value); /** * Returns the unique greatest value of type {@code C} that is less than {@code value}, or {@code @@ -273,7 +279,7 @@ C offset(C origin, long distance) { * @return the greatest value less than {@code value}, or {@code null} if {@code value} is {@code * minValue()} */ - public abstract C previous(C value); + public abstract @Nullable C previous(C value); /** * Returns a signed value indicating how many nested invocations of {@link #next} (if positive) or diff --git a/guava/src/com/google/common/collect/EmptyContiguousSet.java b/guava/src/com/google/common/collect/EmptyContiguousSet.java index fd90124b59c3..880cb401304a 100644 --- a/guava/src/com/google/common/collect/EmptyContiguousSet.java +++ b/guava/src/com/google/common/collect/EmptyContiguousSet.java @@ -79,13 +79,13 @@ ContiguousSet tailSetImpl(C fromElement, boolean fromInclusive) { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { return false; } @GwtIncompatible // not used by GWT emulation @Override - int indexOf(Object target) { + int indexOf(@Nullable Object target) { return -1; } diff --git a/guava/src/com/google/common/collect/EnumBiMap.java b/guava/src/com/google/common/collect/EnumBiMap.java index f72b8b96f706..fd1ae50cb795 100644 --- a/guava/src/com/google/common/collect/EnumBiMap.java +++ b/guava/src/com/google/common/collect/EnumBiMap.java @@ -26,6 +26,8 @@ import java.io.ObjectOutputStream; import java.util.EnumMap; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@code BiMap} backed by two {@code EnumMap} instances. Null keys and values are not permitted. @@ -85,7 +87,8 @@ static > Class inferKeyType(Map map) { return map.keySet().iterator().next().getDeclaringClass(); } - private static > Class inferValueType(Map map) { + private static > Class inferValueType( + Map map) { if (map instanceof EnumBiMap) { return ((EnumBiMap) map).valueType; } diff --git a/guava/src/com/google/common/collect/EnumHashBiMap.java b/guava/src/com/google/common/collect/EnumHashBiMap.java index 47094aefdcd7..3af1d0c49493 100644 --- a/guava/src/com/google/common/collect/EnumHashBiMap.java +++ b/guava/src/com/google/common/collect/EnumHashBiMap.java @@ -17,10 +17,10 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -41,7 +41,8 @@ * @since 2.0 */ @GwtCompatible(emulated = true) -public final class EnumHashBiMap, V> extends AbstractBiMap { +public final class EnumHashBiMap, V> + extends AbstractBiMap { private transient Class keyType; /** @@ -49,7 +50,8 @@ public final class EnumHashBiMap, V> extends AbstractBiMap, V> EnumHashBiMap create(Class keyType) { + public static , V> EnumHashBiMap create( + Class keyType) { return new EnumHashBiMap<>(keyType); } @@ -63,7 +65,8 @@ public static , V> EnumHashBiMap create(Class keyType * @throws IllegalArgumentException if map is not an {@code EnumBiMap} or an {@code EnumHashBiMap} * instance and contains no mappings */ - public static , V> EnumHashBiMap create(Map map) { + public static , V> EnumHashBiMap create( + Map map) { EnumHashBiMap bimap = create(EnumBiMap.inferKeyType(map)); bimap.putAll(map); return bimap; @@ -72,34 +75,25 @@ public static , V> EnumHashBiMap create(Map keyType) { super( new EnumMap(keyType), - Maps.newHashMapWithExpectedSize(keyType.getEnumConstants().length)); + Maps.newHashMapWithExpectedSize(getEnumConstants(keyType).length)); this.keyType = keyType; } - // Overriding these 3 methods to show that values may be null (but not keys) - @Override K checkKey(K key) { return checkNotNull(key); } - @CanIgnoreReturnValue - @Override - public V put(K key, @Nullable V value) { - return super.put(key, value); - } - - @CanIgnoreReturnValue - @Override - public V forcePut(K key, @Nullable V value) { - return super.forcePut(key, value); - } - /** Returns the associated key type. */ public Class keyType() { return keyType; } + private static > E[] getEnumConstants(Class clazz) { + // requireNonNull is safe because the class is an enum class. + return requireNonNull(clazz.getEnumConstants()); + } + /** * @serialData the key class, number of entries, first key, first value, second key, second value, * and so on. @@ -117,7 +111,7 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo stream.defaultReadObject(); keyType = (Class) stream.readObject(); setDelegates( - new EnumMap(keyType), new HashMap(keyType.getEnumConstants().length * 3 / 2)); + new EnumMap(keyType), new HashMap(getEnumConstants(keyType).length * 3 / 2)); Serialization.populateMap(this, stream); } diff --git a/guava/src/com/google/common/collect/EnumMultiset.java b/guava/src/com/google/common/collect/EnumMultiset.java index c6b9b5b4c4d4..9812638e920b 100644 --- a/guava/src/com/google/common/collect/EnumMultiset.java +++ b/guava/src/com/google/common/collect/EnumMultiset.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; import static com.google.common.collect.CollectPreconditions.checkRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -90,7 +91,7 @@ public static > EnumMultiset create(Iterable elements, C private EnumMultiset(Class type) { this.type = type; checkArgument(type.isEnum()); - this.enumConstants = type.getEnumConstants(); + this.enumConstants = getEnumConstants(type); this.counts = new int[enumConstants.length]; } @@ -107,7 +108,7 @@ private boolean isActuallyE(@Nullable Object o) { * Returns {@code element} cast to {@code E}, if it actually is a nonnull E. Otherwise, throws * either a NullPointerException or a ClassCastException as appropriate. */ - void checkIsE(@Nullable Object element) { + private void checkIsE(Object element) { checkNotNull(element); if (!isActuallyE(element)) { throw new ClassCastException("Expected an " + type + " but got " + element); @@ -126,7 +127,7 @@ public int size() { @Override public int count(@Nullable Object element) { - if (!isActuallyE(element)) { + if (element == null || !isActuallyE(element)) { return 0; } Enum e = (Enum) element; @@ -158,7 +159,7 @@ public int add(E element, int occurrences) { @CanIgnoreReturnValue @Override public int remove(@Nullable Object element, int occurrences) { - if (!isActuallyE(element)) { + if (element == null || !isActuallyE(element)) { return 0; } Enum e = (Enum) element; @@ -290,6 +291,11 @@ public Iterator iterator() { return Multisets.iteratorImpl(this); } + private static > E[] getEnumConstants(Class clazz) { + // requireNonNull is safe because the class is an enum class. + return requireNonNull(clazz.getEnumConstants()); + } + @GwtIncompatible // java.io.ObjectOutputStream private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); @@ -307,7 +313,7 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo @SuppressWarnings("unchecked") // reading data stored by writeObject Class localType = (Class) stream.readObject(); type = localType; - enumConstants = type.getEnumConstants(); + enumConstants = getEnumConstants(type); counts = new int[enumConstants.length]; Serialization.populateMultiset(this, stream); } diff --git a/guava/src/com/google/common/collect/EvictingQueue.java b/guava/src/com/google/common/collect/EvictingQueue.java index 37a65f3e0deb..bd5e17c2fb91 100644 --- a/guava/src/com/google/common/collect/EvictingQueue.java +++ b/guava/src/com/google/common/collect/EvictingQueue.java @@ -27,6 +27,7 @@ import java.util.ArrayDeque; import java.util.Collection; import java.util.Queue; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A non-blocking queue which automatically evicts elements from the head of the queue when @@ -45,7 +46,8 @@ */ @Beta @GwtCompatible -public final class EvictingQueue extends ForwardingQueue implements Serializable { +public final class EvictingQueue extends ForwardingQueue + implements Serializable { private final Queue delegate; @@ -63,7 +65,7 @@ private EvictingQueue(int maxSize) { *

    When {@code maxSize} is zero, elements will be evicted immediately after being added to the * queue. */ - public static EvictingQueue create(int maxSize) { + public static EvictingQueue create(int maxSize) { return new EvictingQueue(maxSize); } @@ -126,13 +128,17 @@ public boolean addAll(Collection collection) { } @Override - public boolean contains(Object object) { + public boolean contains( + // TODO(cpovirk): Consider accepting null. + @SuppressWarnings("nullness") Object object) { return delegate().contains(checkNotNull(object)); } @Override @CanIgnoreReturnValue - public boolean remove(Object object) { + public boolean remove( + // TODO(cpovirk): Consider accepting null. + @SuppressWarnings("nullness") Object object) { return delegate().remove(checkNotNull(object)); } diff --git a/guava/src/com/google/common/collect/ExplicitOrdering.java b/guava/src/com/google/common/collect/ExplicitOrdering.java index 526e6e39b425..a96fc2e8b2a2 100644 --- a/guava/src/com/google/common/collect/ExplicitOrdering.java +++ b/guava/src/com/google/common/collect/ExplicitOrdering.java @@ -19,11 +19,13 @@ import com.google.common.annotations.GwtCompatible; import java.io.Serializable; import java.util.List; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** An ordering that compares objects according to a given order. */ @GwtCompatible(serializable = true) -final class ExplicitOrdering extends Ordering implements Serializable { +final class ExplicitOrdering extends Ordering + implements Serializable { final ImmutableMap rankMap; ExplicitOrdering(List valuesInOrder) { diff --git a/guava/src/com/google/common/collect/FilteredEntryMultimap.java b/guava/src/com/google/common/collect/FilteredEntryMultimap.java index ced909a2120b..a12f0bd6fa30 100644 --- a/guava/src/com/google/common/collect/FilteredEntryMultimap.java +++ b/guava/src/com/google/common/collect/FilteredEntryMultimap.java @@ -42,7 +42,8 @@ * @author Louis Wasserman */ @GwtCompatible -class FilteredEntryMultimap extends AbstractMultimap implements FilteredMultimap { +class FilteredEntryMultimap + extends AbstractMultimap implements FilteredMultimap { final Multimap unfiltered; final Predicate> predicate; @@ -78,7 +79,7 @@ final class ValuePredicate implements Predicate { } @Override - public boolean apply(@Nullable V value) { + public boolean apply(V value) { return satisfies(key, value); } } @@ -176,7 +177,7 @@ public void clear() { } @Override - public Collection get(@Nullable Object key) { + public @Nullable Collection get(@Nullable Object key) { Collection result = unfiltered.asMap().get(key); if (result == null) { return null; @@ -188,7 +189,7 @@ public Collection get(@Nullable Object key) { } @Override - public Collection remove(@Nullable Object key) { + public @Nullable Collection remove(@Nullable Object key) { Collection collection = unfiltered.asMap().get(key); if (collection == null) { return null; diff --git a/guava/src/com/google/common/collect/FilteredEntrySetMultimap.java b/guava/src/com/google/common/collect/FilteredEntrySetMultimap.java index 94740a4cf1a6..8d54a677b357 100644 --- a/guava/src/com/google/common/collect/FilteredEntrySetMultimap.java +++ b/guava/src/com/google/common/collect/FilteredEntrySetMultimap.java @@ -20,6 +20,7 @@ import com.google.common.base.Predicate; import java.util.Map.Entry; import java.util.Set; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Implementation of {@link Multimaps#filterEntries(SetMultimap, Predicate)}. @@ -27,8 +28,8 @@ * @author Louis Wasserman */ @GwtCompatible -final class FilteredEntrySetMultimap extends FilteredEntryMultimap - implements FilteredSetMultimap { +final class FilteredEntrySetMultimap + extends FilteredEntryMultimap implements FilteredSetMultimap { FilteredEntrySetMultimap(SetMultimap unfiltered, Predicate> predicate) { super(unfiltered, predicate); @@ -45,7 +46,7 @@ public Set get(K key) { } @Override - public Set removeAll(Object key) { + public Set removeAll(@Nullable Object key) { return (Set) super.removeAll(key); } diff --git a/guava/src/com/google/common/collect/FilteredKeyListMultimap.java b/guava/src/com/google/common/collect/FilteredKeyListMultimap.java index 8de9ed426042..1a40830119ab 100644 --- a/guava/src/com/google/common/collect/FilteredKeyListMultimap.java +++ b/guava/src/com/google/common/collect/FilteredKeyListMultimap.java @@ -27,8 +27,8 @@ * @author Louis Wasserman */ @GwtCompatible -final class FilteredKeyListMultimap extends FilteredKeyMultimap - implements ListMultimap { +final class FilteredKeyListMultimap + extends FilteredKeyMultimap implements ListMultimap { FilteredKeyListMultimap(ListMultimap unfiltered, Predicate keyPredicate) { super(unfiltered, keyPredicate); } diff --git a/guava/src/com/google/common/collect/FilteredKeyMultimap.java b/guava/src/com/google/common/collect/FilteredKeyMultimap.java index 12456b3891f7..f3cd15cdfa5f 100644 --- a/guava/src/com/google/common/collect/FilteredKeyMultimap.java +++ b/guava/src/com/google/common/collect/FilteredKeyMultimap.java @@ -16,6 +16,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndex; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Predicate; @@ -36,7 +38,8 @@ * @author Louis Wasserman */ @GwtCompatible -class FilteredKeyMultimap extends AbstractMultimap implements FilteredMultimap { +class FilteredKeyMultimap + extends AbstractMultimap implements FilteredMultimap { final Multimap unfiltered; final Predicate keyPredicate; @@ -67,23 +70,35 @@ public int size() { @Override public boolean containsKey(@Nullable Object key) { if (unfiltered.containsKey(key)) { - @SuppressWarnings("unchecked") // k is equal to a K, if not one itself - K k = (K) key; + // Fairly safe because k is equal to a K, if not one itself. + K k = uncheckedCastNullableObjectToK(key); return keyPredicate.apply(k); } return false; } + @SuppressWarnings({"unchecked", "nullness"}) + private static K uncheckedCastNullableObjectToK( + @Nullable Object key) { + /* + * We can't use requireNonNull because `key` might be null. Specifically, it can be null because + * the multimap might contain a null key to be returned to the user. This is in contrast to the + * other way for `key` to be null, which is for the iterator not to have a next value computed + * yet. + */ + return (K) key; + } + @Override - public Collection removeAll(Object key) { + public Collection removeAll(@Nullable Object key) { return containsKey(key) ? unfiltered.removeAll(key) : unmodifiableEmptyCollection(); } Collection unmodifiableEmptyCollection() { if (unfiltered instanceof SetMultimap) { - return ImmutableSet.of(); + return emptySet(); } else { - return ImmutableList.of(); + return emptyList(); } } @@ -108,7 +123,8 @@ public Collection get(K key) { } } - static class AddRejectingSet extends ForwardingSet { + static class AddRejectingSet + extends ForwardingSet { final K key; AddRejectingSet(K key) { @@ -132,7 +148,8 @@ protected Set delegate() { } } - static class AddRejectingList extends ForwardingList { + static class AddRejectingList + extends ForwardingList { final K key; AddRejectingList(K key) { @@ -192,7 +209,8 @@ protected Collection> delegate() { @SuppressWarnings("unchecked") public boolean remove(@Nullable Object o) { if (o instanceof Entry) { - Entry entry = (Entry) o; + Entry entry = + (Entry) o; if (unfiltered.containsKey(entry.getKey()) // if this holds, then we know entry.getKey() is a K && keyPredicate.apply((K) entry.getKey())) { diff --git a/guava/src/com/google/common/collect/FilteredKeySetMultimap.java b/guava/src/com/google/common/collect/FilteredKeySetMultimap.java index f6fb61d58830..d0e4ed31302e 100644 --- a/guava/src/com/google/common/collect/FilteredKeySetMultimap.java +++ b/guava/src/com/google/common/collect/FilteredKeySetMultimap.java @@ -28,8 +28,8 @@ * @author Louis Wasserman */ @GwtCompatible -final class FilteredKeySetMultimap extends FilteredKeyMultimap - implements FilteredSetMultimap { +final class FilteredKeySetMultimap + extends FilteredKeyMultimap implements FilteredSetMultimap { FilteredKeySetMultimap(SetMultimap unfiltered, Predicate keyPredicate) { super(unfiltered, keyPredicate); @@ -46,7 +46,7 @@ public Set get(K key) { } @Override - public Set removeAll(Object key) { + public Set removeAll(@Nullable Object key) { return (Set) super.removeAll(key); } diff --git a/guava/src/com/google/common/collect/FilteredMultimap.java b/guava/src/com/google/common/collect/FilteredMultimap.java index ef5ed4ab26f3..30cab734ff6a 100644 --- a/guava/src/com/google/common/collect/FilteredMultimap.java +++ b/guava/src/com/google/common/collect/FilteredMultimap.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.base.Predicate; import java.util.Map.Entry; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An interface for all filtered multimap types. @@ -26,7 +27,8 @@ * @author Louis Wasserman */ @GwtCompatible -interface FilteredMultimap extends Multimap { +interface FilteredMultimap + extends Multimap { Multimap unfiltered(); Predicate> entryPredicate(); diff --git a/guava/src/com/google/common/collect/FilteredMultimapValues.java b/guava/src/com/google/common/collect/FilteredMultimapValues.java index 7e3d25707855..e92b8f35025d 100644 --- a/guava/src/com/google/common/collect/FilteredMultimapValues.java +++ b/guava/src/com/google/common/collect/FilteredMultimapValues.java @@ -33,7 +33,8 @@ * @author Louis Wasserman */ @GwtCompatible -final class FilteredMultimapValues extends AbstractCollection { +final class FilteredMultimapValues + extends AbstractCollection { @Weak private final FilteredMultimap multimap; FilteredMultimapValues(FilteredMultimap multimap) { diff --git a/guava/src/com/google/common/collect/FilteredSetMultimap.java b/guava/src/com/google/common/collect/FilteredSetMultimap.java index a0a149fd7d5b..23f659a303ae 100644 --- a/guava/src/com/google/common/collect/FilteredSetMultimap.java +++ b/guava/src/com/google/common/collect/FilteredSetMultimap.java @@ -17,6 +17,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A supertype for filtered {@link SetMultimap} implementations. @@ -24,7 +25,8 @@ * @author Louis Wasserman */ @GwtCompatible -interface FilteredSetMultimap extends FilteredMultimap, SetMultimap { +interface FilteredSetMultimap + extends FilteredMultimap, SetMultimap { @Override SetMultimap unfiltered(); } diff --git a/guava/src/com/google/common/collect/FluentIterable.java b/guava/src/com/google/common/collect/FluentIterable.java index 3acf75a99435..564243ca7881 100644 --- a/guava/src/com/google/common/collect/FluentIterable.java +++ b/guava/src/com/google/common/collect/FluentIterable.java @@ -27,11 +27,13 @@ import com.google.errorprone.annotations.DoNotCall; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -189,7 +191,8 @@ public static FluentIterable from(FluentIterable iterable) { * @since 20.0 */ @Beta - public static FluentIterable concat(Iterable a, Iterable b) { + public static FluentIterable concat( + Iterable a, Iterable b) { return concatNoDefensiveCopy(a, b); } @@ -251,7 +254,8 @@ public static FluentIterable concat( * @since 20.0 */ @Beta - public static FluentIterable concat(Iterable... inputs) { + public static FluentIterable concat( + Iterable... inputs) { return concatNoDefensiveCopy(Arrays.copyOf(inputs, inputs.length)); } @@ -311,7 +315,7 @@ public Iterator get(int i) { */ @Beta public static FluentIterable of() { - return FluentIterable.from(ImmutableList.of()); + return FluentIterable.from(Collections.emptyList()); } /** @@ -323,7 +327,7 @@ public static FluentIterable of() { * @since 20.0 */ @Beta - public static FluentIterable of(@Nullable E element, E... elements) { + public static FluentIterable of(E element, E... elements) { return from(Lists.asList(element, elements)); } @@ -432,7 +436,7 @@ public final FluentIterable filter(Predicate predicate) { * */ @GwtIncompatible // Class.isInstance - public final FluentIterable filter(Class type) { + public final FluentIterable filter(Class type) { return from(Iterables.filter(getDelegate(), type)); } @@ -464,6 +468,7 @@ public final boolean allMatch(Predicate predicate) { * *

    {@code Stream} equivalent: {@code stream.filter(predicate).findFirst()}. */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final Optional firstMatch(Predicate predicate) { return Iterables.tryFind(getDelegate(), predicate); } @@ -478,7 +483,8 @@ public final Optional firstMatch(Predicate predicate) { * *

    {@code Stream} equivalent: {@link Stream#map}. */ - public final FluentIterable transform(Function function) { + public final FluentIterable transform( + Function function) { return from(Iterables.transform(getDelegate(), function)); } @@ -510,6 +516,7 @@ public FluentIterable transformAndConcat( * @throws NullPointerException if the first element is null; if this is a possibility, use {@code * iterator().next()} or {@link Iterables#getFirst} instead. */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final Optional first() { Iterator iterator = getDelegate().iterator(); return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.absent(); @@ -526,6 +533,7 @@ public final Optional first() { * @throws NullPointerException if the last element is null; if this is a possibility, use {@link * Iterables#getLast} instead. */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final Optional last() { // Iterables#getLast was inlined here so we don't have to throw/catch a NSEE @@ -615,6 +623,7 @@ public final boolean isEmpty() { * @throws NullPointerException if any element is {@code null} * @since 14.0 (since 12.0 as {@code toImmutableList()}). */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final ImmutableList toList() { return ImmutableList.copyOf(getDelegate()); } @@ -631,6 +640,7 @@ public final ImmutableList toList() { * @throws NullPointerException if any element of this iterable is {@code null} * @since 14.0 (since 13.0 as {@code toSortedImmutableList()}). */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final ImmutableList toSortedList(Comparator comparator) { return Ordering.from(comparator).immutableSortedCopy(getDelegate()); } @@ -645,6 +655,7 @@ public final ImmutableList toSortedList(Comparator comparator) { * @throws NullPointerException if any element is {@code null} * @since 14.0 (since 12.0 as {@code toImmutableSet()}). */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final ImmutableSet toSet() { return ImmutableSet.copyOf(getDelegate()); } @@ -662,6 +673,7 @@ public final ImmutableSet toSet() { * @throws NullPointerException if any element of this iterable is {@code null} * @since 14.0 (since 12.0 as {@code toImmutableSortedSet()}). */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final ImmutableSortedSet toSortedSet(Comparator comparator) { return ImmutableSortedSet.copyOf(comparator, getDelegate()); } @@ -675,6 +687,7 @@ public final ImmutableSortedSet toSortedSet(Comparator comparator) * @throws NullPointerException if any element is null * @since 19.0 */ + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. public final ImmutableMultiset toMultiset() { return ImmutableMultiset.copyOf(getDelegate()); } @@ -695,7 +708,9 @@ public final ImmutableMultiset toMultiset() { * valueFunction} produces {@code null} for any key * @since 14.0 */ - public final ImmutableMap toMap(Function valueFunction) { + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. + public final ImmutableMap toMap( + Function valueFunction) { return Maps.toMap(getDelegate(), valueFunction); } @@ -717,7 +732,9 @@ public final ImmutableMap toMap(Function valueFunction) * keyFunction} produces {@code null} for any key * @since 14.0 */ - public final ImmutableListMultimap index(Function keyFunction) { + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. + public final ImmutableListMultimap index( + Function keyFunction) { return Multimaps.index(getDelegate(), keyFunction); } @@ -751,7 +768,9 @@ public final ImmutableListMultimap index(Function keyFun * keyFunction} produces {@code null} for any key * @since 14.0 */ - public final ImmutableMap uniqueIndex(Function keyFunction) { + @SuppressWarnings("nullness") // Unsafe, but we can't do much about it now. + public final ImmutableMap uniqueIndex( + Function keyFunction) { return Maps.uniqueIndex(getDelegate(), keyFunction); } @@ -768,6 +787,7 @@ public final ImmutableMap uniqueIndex(Function keyFuncti * copied */ @GwtIncompatible // Array.newArray(Class, int) +@SuppressWarnings("nullness") public final E[] toArray(Class type) { return Iterables.toArray(getDelegate(), type); } @@ -824,7 +844,6 @@ public final String join(Joiner joiner) { * @throws IndexOutOfBoundsException if {@code position} is negative or greater than or equal to * the size of this fluent iterable */ - // TODO(kevinb): add @Nullable? public final E get(int position) { return Iterables.get(getDelegate(), position); } @@ -844,7 +863,8 @@ public final Stream stream() { } /** Function that transforms {@code Iterable} into a fluent iterable. */ - private static class FromIterableFunction implements Function, FluentIterable> { + private static class FromIterableFunction + implements Function, FluentIterable> { @Override public FluentIterable apply(Iterable fromObject) { return FluentIterable.from(fromObject); diff --git a/guava/src/com/google/common/collect/ForwardingBlockingDeque.java b/guava/src/com/google/common/collect/ForwardingBlockingDeque.java index 7d3895d01502..ff9e39bb00da 100644 --- a/guava/src/com/google/common/collect/ForwardingBlockingDeque.java +++ b/guava/src/com/google/common/collect/ForwardingBlockingDeque.java @@ -20,6 +20,8 @@ import java.util.Collection; import java.util.concurrent.BlockingDeque; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link BlockingDeque} which forwards all its method calls to another {@code BlockingDeque}. @@ -46,7 +48,7 @@ */ @Deprecated @GwtIncompatible -public abstract class ForwardingBlockingDeque extends ForwardingDeque +public abstract class ForwardingBlockingDeque extends ForwardingDeque implements BlockingDeque { /** Constructor for use by subclasses. */ @@ -91,12 +93,12 @@ public E takeLast() throws InterruptedException { } @Override - public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E pollFirst(long timeout, TimeUnit unit) throws InterruptedException { return delegate().pollFirst(timeout, unit); } @Override - public E pollLast(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E pollLast(long timeout, TimeUnit unit) throws InterruptedException { return delegate().pollLast(timeout, unit); } @@ -116,7 +118,7 @@ public E take() throws InterruptedException { } @Override - public E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { return delegate().poll(timeout, unit); } diff --git a/guava/src/com/google/common/collect/ForwardingCollection.java b/guava/src/com/google/common/collect/ForwardingCollection.java index 66219c8622eb..9aac920225ad 100644 --- a/guava/src/com/google/common/collect/ForwardingCollection.java +++ b/guava/src/com/google/common/collect/ForwardingCollection.java @@ -46,7 +46,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingCollection extends ForwardingObject implements Collection { +public abstract class ForwardingCollection extends ForwardingObject + implements Collection { // TODO(lowasser): identify places where thread safety is actually lost /** Constructor for use by subclasses. */ @@ -77,7 +78,7 @@ public boolean isEmpty() { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { return delegate().contains(object); } @@ -89,7 +90,7 @@ public boolean add(E element) { @CanIgnoreReturnValue @Override - public boolean remove(Object object) { + public boolean remove(@Nullable Object object) { return delegate().remove(object); } @@ -116,12 +117,14 @@ public void clear() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { return delegate().toArray(); } @CanIgnoreReturnValue @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return delegate().toArray(array); } @@ -238,6 +241,7 @@ protected String standardToString() { * * @since 7.0 */ + @SuppressWarnings("return.type.incompatible") // arrays protected Object[] standardToArray() { Object[] newArray = new Object[size()]; return toArray(newArray); diff --git a/guava/src/com/google/common/collect/ForwardingConcurrentMap.java b/guava/src/com/google/common/collect/ForwardingConcurrentMap.java index 0910424b7e58..1fbb924b77fc 100644 --- a/guava/src/com/google/common/collect/ForwardingConcurrentMap.java +++ b/guava/src/com/google/common/collect/ForwardingConcurrentMap.java @@ -19,6 +19,8 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.concurrent.ConcurrentMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A concurrent map which forwards all its method calls to another concurrent map. Subclasses should @@ -36,8 +38,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingConcurrentMap extends ForwardingMap - implements ConcurrentMap { +public abstract class ForwardingConcurrentMap + extends ForwardingMap implements ConcurrentMap { /** Constructor for use by subclasses. */ protected ForwardingConcurrentMap() {} @@ -47,19 +49,19 @@ protected ForwardingConcurrentMap() {} @CanIgnoreReturnValue @Override - public V putIfAbsent(K key, V value) { + public @Nullable V putIfAbsent(K key, V value) { return delegate().putIfAbsent(key, value); } @CanIgnoreReturnValue @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { return delegate().remove(key, value); } @CanIgnoreReturnValue @Override - public V replace(K key, V value) { + public @Nullable V replace(K key, V value) { return delegate().replace(key, value); } diff --git a/guava/src/com/google/common/collect/ForwardingDeque.java b/guava/src/com/google/common/collect/ForwardingDeque.java index 87ac71bd67ec..b71078e3790c 100644 --- a/guava/src/com/google/common/collect/ForwardingDeque.java +++ b/guava/src/com/google/common/collect/ForwardingDeque.java @@ -20,6 +20,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Deque; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A deque which forwards all its method calls to another deque. Subclasses should override one or @@ -39,7 +40,8 @@ * @since 12.0 */ @GwtIncompatible -public abstract class ForwardingDeque extends ForwardingQueue implements Deque { +public abstract class ForwardingDeque extends ForwardingQueue + implements Deque { /** Constructor for use by subclasses. */ protected ForwardingDeque() {} @@ -85,24 +87,24 @@ public boolean offerLast(E e) { } @Override - public E peekFirst() { + public @Nullable E peekFirst() { return delegate().peekFirst(); } @Override - public E peekLast() { + public @Nullable E peekLast() { return delegate().peekLast(); } @CanIgnoreReturnValue // TODO(cpovirk): Consider removing this? @Override - public E pollFirst() { + public @Nullable E pollFirst() { return delegate().pollFirst(); } @CanIgnoreReturnValue // TODO(cpovirk): Consider removing this? @Override - public E pollLast() { + public @Nullable E pollLast() { return delegate().pollLast(); } @@ -131,13 +133,13 @@ public E removeLast() { @CanIgnoreReturnValue @Override - public boolean removeFirstOccurrence(Object o) { + public boolean removeFirstOccurrence(@Nullable Object o) { return delegate().removeFirstOccurrence(o); } @CanIgnoreReturnValue @Override - public boolean removeLastOccurrence(Object o) { + public boolean removeLastOccurrence(@Nullable Object o) { return delegate().removeLastOccurrence(o); } } diff --git a/guava/src/com/google/common/collect/ForwardingImmutableList.java b/guava/src/com/google/common/collect/ForwardingImmutableList.java index 2b9092ea4c93..d1d134b4f98b 100644 --- a/guava/src/com/google/common/collect/ForwardingImmutableList.java +++ b/guava/src/com/google/common/collect/ForwardingImmutableList.java @@ -17,6 +17,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Unused stub class, unreferenced under Java and manually emulated under GWT. @@ -24,6 +25,6 @@ * @author Chris Povirk */ @GwtCompatible(emulated = true) -abstract class ForwardingImmutableList { +abstract class ForwardingImmutableList { private ForwardingImmutableList() {} } diff --git a/guava/src/com/google/common/collect/ForwardingImmutableMap.java b/guava/src/com/google/common/collect/ForwardingImmutableMap.java index a36715743f0a..ae4c9a29a6e7 100644 --- a/guava/src/com/google/common/collect/ForwardingImmutableMap.java +++ b/guava/src/com/google/common/collect/ForwardingImmutableMap.java @@ -17,6 +17,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Unused stub class, unreferenced under Java and manually emulated under GWT. @@ -24,6 +25,6 @@ * @author Chris Povirk */ @GwtCompatible(emulated = true) -abstract class ForwardingImmutableMap { +abstract class ForwardingImmutableMap { private ForwardingImmutableMap() {} } diff --git a/guava/src/com/google/common/collect/ForwardingImmutableSet.java b/guava/src/com/google/common/collect/ForwardingImmutableSet.java index c7d7bf6d778b..30bc3af6acd7 100644 --- a/guava/src/com/google/common/collect/ForwardingImmutableSet.java +++ b/guava/src/com/google/common/collect/ForwardingImmutableSet.java @@ -17,6 +17,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Unused stub class, unreferenced under Java and manually emulated under GWT. @@ -24,6 +25,6 @@ * @author Chris Povirk */ @GwtCompatible(emulated = true) -abstract class ForwardingImmutableSet { +abstract class ForwardingImmutableSet { private ForwardingImmutableSet() {} } diff --git a/guava/src/com/google/common/collect/ForwardingIterator.java b/guava/src/com/google/common/collect/ForwardingIterator.java index 5ecd3d293126..17c39ac56a3c 100644 --- a/guava/src/com/google/common/collect/ForwardingIterator.java +++ b/guava/src/com/google/common/collect/ForwardingIterator.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An iterator which forwards all its method calls to another iterator. Subclasses should override @@ -36,7 +37,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingIterator extends ForwardingObject implements Iterator { +public abstract class ForwardingIterator extends ForwardingObject + implements Iterator { /** Constructor for use by subclasses. */ protected ForwardingIterator() {} diff --git a/guava/src/com/google/common/collect/ForwardingList.java b/guava/src/com/google/common/collect/ForwardingList.java index d2ba154c6227..6a8afe11a98e 100644 --- a/guava/src/com/google/common/collect/ForwardingList.java +++ b/guava/src/com/google/common/collect/ForwardingList.java @@ -51,7 +51,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingList extends ForwardingCollection implements List { +public abstract class ForwardingList extends ForwardingCollection + implements List { // TODO(lowasser): identify places where thread safety is actually lost /** Constructor for use by subclasses. */ @@ -77,12 +78,12 @@ public E get(int index) { } @Override - public int indexOf(Object element) { + public int indexOf(@Nullable Object element) { return delegate().indexOf(element); } @Override - public int lastIndexOf(Object element) { + public int lastIndexOf(@Nullable Object element) { return delegate().lastIndexOf(element); } diff --git a/guava/src/com/google/common/collect/ForwardingListIterator.java b/guava/src/com/google/common/collect/ForwardingListIterator.java index bc2a5ad4ff58..0b8916a86968 100644 --- a/guava/src/com/google/common/collect/ForwardingListIterator.java +++ b/guava/src/com/google/common/collect/ForwardingListIterator.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.ListIterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A list iterator which forwards all its method calls to another list iterator. Subclasses should @@ -36,8 +37,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingListIterator extends ForwardingIterator - implements ListIterator { +public abstract class ForwardingListIterator + extends ForwardingIterator implements ListIterator { /** Constructor for use by subclasses. */ protected ForwardingListIterator() {} diff --git a/guava/src/com/google/common/collect/ForwardingListMultimap.java b/guava/src/com/google/common/collect/ForwardingListMultimap.java index c67d56c47e43..b43e5e7e8c96 100644 --- a/guava/src/com/google/common/collect/ForwardingListMultimap.java +++ b/guava/src/com/google/common/collect/ForwardingListMultimap.java @@ -34,8 +34,8 @@ * @since 3.0 */ @GwtCompatible -public abstract class ForwardingListMultimap extends ForwardingMultimap - implements ListMultimap { +public abstract class ForwardingListMultimap + extends ForwardingMultimap implements ListMultimap { /** Constructor for use by subclasses. */ protected ForwardingListMultimap() {} @@ -44,7 +44,7 @@ protected ForwardingListMultimap() {} protected abstract ListMultimap delegate(); @Override - public List get(@Nullable K key) { + public List get(K key) { return delegate().get(key); } diff --git a/guava/src/com/google/common/collect/ForwardingMap.java b/guava/src/com/google/common/collect/ForwardingMap.java index 20e32b3009ee..c9f8304a7707 100644 --- a/guava/src/com/google/common/collect/ForwardingMap.java +++ b/guava/src/com/google/common/collect/ForwardingMap.java @@ -55,7 +55,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingMap extends ForwardingObject implements Map { +public abstract class ForwardingMap + extends ForwardingObject implements Map { // TODO(lowasser): identify places where thread safety is actually lost /** Constructor for use by subclasses. */ @@ -76,7 +77,7 @@ public boolean isEmpty() { @CanIgnoreReturnValue @Override - public V remove(Object object) { + public @Nullable V remove(@Nullable Object object) { return delegate().remove(object); } @@ -96,13 +97,13 @@ public boolean containsValue(@Nullable Object value) { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { return delegate().get(key); } @CanIgnoreReturnValue @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { return delegate().put(key, value); } @@ -158,7 +159,7 @@ protected void standardPutAll(Map map) { * @since 7.0 */ @Beta - protected V standardRemove(@Nullable Object key) { + protected @Nullable V standardRemove(@Nullable Object key) { Iterator> entryIterator = entrySet().iterator(); while (entryIterator.hasNext()) { Entry entry = entryIterator.next(); diff --git a/guava/src/com/google/common/collect/ForwardingMapEntry.java b/guava/src/com/google/common/collect/ForwardingMapEntry.java index c775986d6052..987dfb6d967f 100644 --- a/guava/src/com/google/common/collect/ForwardingMapEntry.java +++ b/guava/src/com/google/common/collect/ForwardingMapEntry.java @@ -47,7 +47,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingMapEntry extends ForwardingObject implements Map.Entry { +public abstract class ForwardingMapEntry + extends ForwardingObject implements Map.Entry { // TODO(lowasser): identify places where thread safety is actually lost /** Constructor for use by subclasses. */ @@ -90,7 +91,8 @@ public int hashCode() { */ protected boolean standardEquals(@Nullable Object object) { if (object instanceof Entry) { - Entry that = (Entry) object; + Entry that = + (Entry) object; return Objects.equal(this.getKey(), that.getKey()) && Objects.equal(this.getValue(), that.getValue()); } diff --git a/guava/src/com/google/common/collect/ForwardingMultimap.java b/guava/src/com/google/common/collect/ForwardingMultimap.java index bc6d9020e125..b8ede2be229a 100644 --- a/guava/src/com/google/common/collect/ForwardingMultimap.java +++ b/guava/src/com/google/common/collect/ForwardingMultimap.java @@ -37,7 +37,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingMultimap extends ForwardingObject implements Multimap { +public abstract class ForwardingMultimap + extends ForwardingObject implements Multimap { /** Constructor for use by subclasses. */ protected ForwardingMultimap() {} @@ -76,7 +77,7 @@ public Collection> entries() { } @Override - public Collection get(@Nullable K key) { + public Collection get(K key) { return delegate().get(key); } diff --git a/guava/src/com/google/common/collect/ForwardingMultiset.java b/guava/src/com/google/common/collect/ForwardingMultiset.java index 6bf5c33bc3f7..306e23571d63 100644 --- a/guava/src/com/google/common/collect/ForwardingMultiset.java +++ b/guava/src/com/google/common/collect/ForwardingMultiset.java @@ -48,7 +48,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingMultiset extends ForwardingCollection implements Multiset { +public abstract class ForwardingMultiset extends ForwardingCollection + implements Multiset { /** Constructor for use by subclasses. */ protected ForwardingMultiset() {} @@ -57,7 +58,7 @@ protected ForwardingMultiset() {} protected abstract Multiset delegate(); @Override - public int count(Object element) { + public int count(@Nullable Object element) { return delegate().count(element); } @@ -69,7 +70,7 @@ public int add(E element, int occurrences) { @CanIgnoreReturnValue @Override - public int remove(Object element, int occurrences) { + public int remove(@Nullable Object element, int occurrences) { return delegate().remove(element, occurrences); } @@ -137,7 +138,7 @@ protected void standardClear() { */ @Beta protected int standardCount(@Nullable Object object) { - for (Entry entry : this.entrySet()) { + for (Entry entry : this.entrySet()) { if (Objects.equal(entry.getElement(), object)) { return entry.getCount(); } @@ -178,7 +179,7 @@ protected boolean standardAddAll(Collection elementsToAdd) { * @since 7.0 */ @Override - protected boolean standardRemove(Object element) { + protected boolean standardRemove(@Nullable Object element) { return remove(element, 1) > 0; } diff --git a/guava/src/com/google/common/collect/ForwardingNavigableMap.java b/guava/src/com/google/common/collect/ForwardingNavigableMap.java index 5f23d05c8b39..44a8a1331b9b 100644 --- a/guava/src/com/google/common/collect/ForwardingNavigableMap.java +++ b/guava/src/com/google/common/collect/ForwardingNavigableMap.java @@ -16,8 +16,9 @@ package com.google.common.collect; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; import static com.google.common.collect.Maps.keyOrNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -27,6 +28,7 @@ import java.util.NoSuchElementException; import java.util.SortedMap; import java.util.function.BiFunction; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A navigable map which forwards all its method calls to another navigable map. Subclasses should @@ -55,8 +57,8 @@ * @since 12.0 */ @GwtIncompatible -public abstract class ForwardingNavigableMap extends ForwardingSortedMap - implements NavigableMap { +public abstract class ForwardingNavigableMap + extends ForwardingSortedMap implements NavigableMap { /** Constructor for use by subclasses. */ protected ForwardingNavigableMap() {} @@ -65,7 +67,7 @@ protected ForwardingNavigableMap() {} protected abstract NavigableMap delegate(); @Override - public Entry lowerEntry(K key) { + public @Nullable Entry lowerEntry(K key) { return delegate().lowerEntry(key); } @@ -74,12 +76,12 @@ public Entry lowerEntry(K key) { * #headMap(Object, boolean)}. If you override {@code headMap}, you may wish to override {@code * lowerEntry} to forward to this implementation. */ - protected Entry standardLowerEntry(K key) { + protected @Nullable Entry standardLowerEntry(K key) { return headMap(key, false).lastEntry(); } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return delegate().lowerKey(key); } @@ -88,12 +90,12 @@ public K lowerKey(K key) { * {@link #lowerEntry}, you may wish to override {@code lowerKey} to forward to this * implementation. */ - protected K standardLowerKey(K key) { + protected @Nullable K standardLowerKey(K key) { return keyOrNull(lowerEntry(key)); } @Override - public Entry floorEntry(K key) { + public @Nullable Entry floorEntry(K key) { return delegate().floorEntry(key); } @@ -102,12 +104,12 @@ public Entry floorEntry(K key) { * #headMap(Object, boolean)}. If you override {@code headMap}, you may wish to override {@code * floorEntry} to forward to this implementation. */ - protected Entry standardFloorEntry(K key) { + protected @Nullable Entry standardFloorEntry(K key) { return headMap(key, true).lastEntry(); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return delegate().floorKey(key); } @@ -116,12 +118,12 @@ public K floorKey(K key) { * {@code floorEntry}, you may wish to override {@code floorKey} to forward to this * implementation. */ - protected K standardFloorKey(K key) { + protected @Nullable K standardFloorKey(K key) { return keyOrNull(floorEntry(key)); } @Override - public Entry ceilingEntry(K key) { + public @Nullable Entry ceilingEntry(K key) { return delegate().ceilingEntry(key); } @@ -130,12 +132,12 @@ public Entry ceilingEntry(K key) { * #tailMap(Object, boolean)}. If you override {@code tailMap}, you may wish to override {@code * ceilingEntry} to forward to this implementation. */ - protected Entry standardCeilingEntry(K key) { + protected @Nullable Entry standardCeilingEntry(K key) { return tailMap(key, true).firstEntry(); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return delegate().ceilingKey(key); } @@ -144,12 +146,12 @@ public K ceilingKey(K key) { * {@code ceilingEntry}, you may wish to override {@code ceilingKey} to forward to this * implementation. */ - protected K standardCeilingKey(K key) { + protected @Nullable K standardCeilingKey(K key) { return keyOrNull(ceilingEntry(key)); } @Override - public Entry higherEntry(K key) { + public @Nullable Entry higherEntry(K key) { return delegate().higherEntry(key); } @@ -158,12 +160,12 @@ public Entry higherEntry(K key) { * #tailMap(Object, boolean)}. If you override {@code tailMap}, you may wish to override {@code * higherEntry} to forward to this implementation. */ - protected Entry standardHigherEntry(K key) { + protected @Nullable Entry standardHigherEntry(K key) { return tailMap(key, false).firstEntry(); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return delegate().higherKey(key); } @@ -172,12 +174,12 @@ public K higherKey(K key) { * {@code higherEntry}, you may wish to override {@code higherKey} to forward to this * implementation. */ - protected K standardHigherKey(K key) { + protected @Nullable K standardHigherKey(K key) { return keyOrNull(higherEntry(key)); } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return delegate().firstEntry(); } @@ -186,7 +188,7 @@ public Entry firstEntry() { * #entrySet}. If you override {@code entrySet}, you may wish to override {@code firstEntry} to * forward to this implementation. */ - protected Entry standardFirstEntry() { + protected @Nullable Entry standardFirstEntry() { return Iterables.getFirst(entrySet(), null); } @@ -205,7 +207,7 @@ protected K standardFirstKey() { } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return delegate().lastEntry(); } @@ -214,7 +216,7 @@ public Entry lastEntry() { * #entrySet} of {@link #descendingMap}. If you override {@code descendingMap}, you may wish to * override {@code lastEntry} to forward to this implementation. */ - protected Entry standardLastEntry() { + protected @Nullable Entry standardLastEntry() { return Iterables.getFirst(descendingMap().entrySet(), null); } @@ -232,7 +234,7 @@ protected K standardLastKey() { } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { return delegate().pollFirstEntry(); } @@ -241,12 +243,12 @@ public Entry pollFirstEntry() { * entrySet}. If you override {@code entrySet}, you may wish to override {@code pollFirstEntry} to * forward to this implementation. */ - protected Entry standardPollFirstEntry() { + protected @Nullable Entry standardPollFirstEntry() { return Iterators.pollNext(entrySet().iterator()); } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { return delegate().pollLastEntry(); } @@ -255,7 +257,7 @@ public Entry pollLastEntry() { * entrySet} of {@code descendingMap}. If you override {@code descendingMap}, you may wish to * override {@code pollFirstEntry} to forward to this implementation. */ - protected Entry standardPollLastEntry() { + protected @Nullable Entry standardPollLastEntry() { return Iterators.pollNext(descendingMap().entrySet().iterator()); } @@ -293,8 +295,8 @@ public void replaceAll(BiFunction function) { @Override protected Iterator> entryIterator() { return new Iterator>() { - private Entry toRemove = null; - private Entry nextOrNull = forward().lastEntry(); + private @Nullable Entry toRemove = null; + private @Nullable Entry nextOrNull = forward().lastEntry(); @Override public boolean hasNext() { @@ -306,6 +308,8 @@ public java.util.Map.Entry next() { if (!hasNext()) { throw new NoSuchElementException(); } + // requireNonNull is safe because of the hasNext() check. + requireNonNull(nextOrNull); try { return nextOrNull; } finally { @@ -316,7 +320,9 @@ public java.util.Map.Entry next() { @Override public void remove() { - checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } forward().remove(toRemove.getKey()); toRemove = null; } diff --git a/guava/src/com/google/common/collect/ForwardingNavigableSet.java b/guava/src/com/google/common/collect/ForwardingNavigableSet.java index 827698edd545..ed07e922ea2f 100644 --- a/guava/src/com/google/common/collect/ForwardingNavigableSet.java +++ b/guava/src/com/google/common/collect/ForwardingNavigableSet.java @@ -21,6 +21,7 @@ import java.util.Iterator; import java.util.NavigableSet; import java.util.SortedSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A navigable set which forwards all its method calls to another navigable set. Subclasses should @@ -49,8 +50,8 @@ * @since 12.0 */ @GwtIncompatible -public abstract class ForwardingNavigableSet extends ForwardingSortedSet - implements NavigableSet { +public abstract class ForwardingNavigableSet + extends ForwardingSortedSet implements NavigableSet { /** Constructor for use by subclasses. */ protected ForwardingNavigableSet() {} @@ -59,7 +60,7 @@ protected ForwardingNavigableSet() {} protected abstract NavigableSet delegate(); @Override - public E lower(E e) { + public @Nullable E lower(E e) { return delegate().lower(e); } @@ -68,12 +69,12 @@ public E lower(E e) { * {@link #headSet(Object, boolean)}. If you override {@link #headSet(Object, boolean)}, you may * wish to override {@link #lower} to forward to this implementation. */ - protected E standardLower(E e) { + protected @Nullable E standardLower(E e) { return Iterators.getNext(headSet(e, false).descendingIterator(), null); } @Override - public E floor(E e) { + public @Nullable E floor(E e) { return delegate().floor(e); } @@ -82,12 +83,12 @@ public E floor(E e) { * {@link #headSet(Object, boolean)}. If you override {@link #headSet(Object, boolean)}, you may * wish to override {@link #floor} to forward to this implementation. */ - protected E standardFloor(E e) { + protected @Nullable E standardFloor(E e) { return Iterators.getNext(headSet(e, true).descendingIterator(), null); } @Override - public E ceiling(E e) { + public @Nullable E ceiling(E e) { return delegate().ceiling(e); } @@ -96,12 +97,12 @@ public E ceiling(E e) { * #tailSet(Object, boolean)}. If you override {@link #tailSet(Object, boolean)}, you may wish to * override {@link #ceiling} to forward to this implementation. */ - protected E standardCeiling(E e) { + protected @Nullable E standardCeiling(E e) { return Iterators.getNext(tailSet(e, true).iterator(), null); } @Override - public E higher(E e) { + public @Nullable E higher(E e) { return delegate().higher(e); } @@ -110,12 +111,12 @@ public E higher(E e) { * #tailSet(Object, boolean)}. If you override {@link #tailSet(Object, boolean)}, you may wish to * override {@link #higher} to forward to this implementation. */ - protected E standardHigher(E e) { + protected @Nullable E standardHigher(E e) { return Iterators.getNext(tailSet(e, false).iterator(), null); } @Override - public E pollFirst() { + public @Nullable E pollFirst() { return delegate().pollFirst(); } @@ -124,12 +125,12 @@ public E pollFirst() { * override {@link #iterator} you may wish to override {@link #pollFirst} to forward to this * implementation. */ - protected E standardPollFirst() { + protected @Nullable E standardPollFirst() { return Iterators.pollNext(iterator()); } @Override - public E pollLast() { + public @Nullable E pollLast() { return delegate().pollLast(); } @@ -138,7 +139,7 @@ public E pollLast() { * If you override {@link #descendingIterator} you may wish to override {@link #pollLast} to * forward to this implementation. */ - protected E standardPollLast() { + protected @Nullable E standardPollLast() { return Iterators.pollNext(descendingIterator()); } diff --git a/guava/src/com/google/common/collect/ForwardingQueue.java b/guava/src/com/google/common/collect/ForwardingQueue.java index f77e5608d3ff..e37d0f72c26c 100644 --- a/guava/src/com/google/common/collect/ForwardingQueue.java +++ b/guava/src/com/google/common/collect/ForwardingQueue.java @@ -20,6 +20,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.NoSuchElementException; import java.util.Queue; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A queue which forwards all its method calls to another queue. Subclasses should override one or @@ -44,7 +45,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingQueue extends ForwardingCollection implements Queue { +public abstract class ForwardingQueue extends ForwardingCollection + implements Queue { /** Constructor for use by subclasses. */ protected ForwardingQueue() {} @@ -60,7 +62,7 @@ public boolean offer(E o) { @CanIgnoreReturnValue // TODO(cpovirk): Consider removing this? @Override - public E poll() { + public @Nullable E poll() { return delegate().poll(); } @@ -71,7 +73,7 @@ public E remove() { } @Override - public E peek() { + public @Nullable E peek() { return delegate().peek(); } @@ -100,7 +102,7 @@ protected boolean standardOffer(E e) { * * @since 7.0 */ - protected E standardPeek() { + protected @Nullable E standardPeek() { try { return element(); } catch (NoSuchElementException caught) { @@ -114,7 +116,7 @@ protected E standardPeek() { * * @since 7.0 */ - protected E standardPoll() { + protected @Nullable E standardPoll() { try { return remove(); } catch (NoSuchElementException caught) { diff --git a/guava/src/com/google/common/collect/ForwardingSet.java b/guava/src/com/google/common/collect/ForwardingSet.java index ff21924c0e6c..0ea57bc4dfa8 100644 --- a/guava/src/com/google/common/collect/ForwardingSet.java +++ b/guava/src/com/google/common/collect/ForwardingSet.java @@ -46,7 +46,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingSet extends ForwardingCollection implements Set { +public abstract class ForwardingSet extends ForwardingCollection + implements Set { // TODO(lowasser): identify places where thread safety is actually lost /** Constructor for use by subclasses. */ diff --git a/guava/src/com/google/common/collect/ForwardingSetMultimap.java b/guava/src/com/google/common/collect/ForwardingSetMultimap.java index a4d6c76f5d5b..4a2ad8605e3e 100644 --- a/guava/src/com/google/common/collect/ForwardingSetMultimap.java +++ b/guava/src/com/google/common/collect/ForwardingSetMultimap.java @@ -35,8 +35,8 @@ * @since 3.0 */ @GwtCompatible -public abstract class ForwardingSetMultimap extends ForwardingMultimap - implements SetMultimap { +public abstract class ForwardingSetMultimap + extends ForwardingMultimap implements SetMultimap { @Override protected abstract SetMultimap delegate(); @@ -47,7 +47,7 @@ public Set> entries() { } @Override - public Set get(@Nullable K key) { + public Set get(K key) { return delegate().get(key); } diff --git a/guava/src/com/google/common/collect/ForwardingSortedMap.java b/guava/src/com/google/common/collect/ForwardingSortedMap.java index 8539adf1b676..d88664927981 100644 --- a/guava/src/com/google/common/collect/ForwardingSortedMap.java +++ b/guava/src/com/google/common/collect/ForwardingSortedMap.java @@ -51,8 +51,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingSortedMap extends ForwardingMap - implements SortedMap { +public abstract class ForwardingSortedMap + extends ForwardingMap implements SortedMap { // TODO(lowasser): identify places where thread safety is actually lost /** Constructor for use by subclasses. */ @@ -62,7 +62,7 @@ protected ForwardingSortedMap() {} protected abstract SortedMap delegate(); @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return delegate().comparator(); } @@ -106,14 +106,14 @@ public StandardKeySet() { } } - // unsafe, but worst case is a CCE is thrown, which callers will be expecting - @SuppressWarnings("unchecked") - private int unsafeCompare(Object k1, Object k2) { + // unsafe, but worst case is a CCE or NPE is thrown, which callers will be expecting + @SuppressWarnings({"unchecked", "nullness"}) + private int unsafeCompare(@Nullable Object k1, @Nullable Object k2) { Comparator comparator = comparator(); if (comparator == null) { - return ((Comparable) k1).compareTo(k2); + return ((Comparable<@Nullable Object>) k1).compareTo(k2); } else { - return ((Comparator) comparator).compare(k1, k2); + return ((Comparator<@Nullable Object>) comparator).compare(k1, k2); } } @@ -128,9 +128,9 @@ private int unsafeCompare(Object k1, Object k2) { @Beta protected boolean standardContainsKey(@Nullable Object key) { try { - // any CCE will be caught - @SuppressWarnings("unchecked") - SortedMap self = (SortedMap) this; + // any ClassCastExceptions and NullPointerExceptions are caught + @SuppressWarnings({"unchecked", "nullness"}) + SortedMap<@Nullable Object, V> self = (SortedMap<@Nullable Object, V>) this; Object ceilingKey = self.tailMap(key).firstKey(); return unsafeCompare(ceilingKey, key) == 0; } catch (ClassCastException | NoSuchElementException | NullPointerException e) { diff --git a/guava/src/com/google/common/collect/ForwardingSortedMultiset.java b/guava/src/com/google/common/collect/ForwardingSortedMultiset.java index 1d34fb3d559f..22871ffecce4 100644 --- a/guava/src/com/google/common/collect/ForwardingSortedMultiset.java +++ b/guava/src/com/google/common/collect/ForwardingSortedMultiset.java @@ -19,6 +19,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.NavigableSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A sorted multiset which forwards all its method calls to another sorted multiset. Subclasses @@ -44,8 +45,8 @@ */ @Beta @GwtCompatible(emulated = true) -public abstract class ForwardingSortedMultiset extends ForwardingMultiset - implements SortedMultiset { +public abstract class ForwardingSortedMultiset + extends ForwardingMultiset implements SortedMultiset { /** Constructor for use by subclasses. */ protected ForwardingSortedMultiset() {} @@ -110,7 +111,7 @@ SortedMultiset forwardMultiset() { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return delegate().firstEntry(); } @@ -120,7 +121,7 @@ public Entry firstEntry() { *

    If you override {@link #entrySet()}, you may wish to override {@link #firstEntry()} to * forward to this implementation. */ - protected Entry standardFirstEntry() { + protected @Nullable Entry standardFirstEntry() { Iterator> entryIterator = entrySet().iterator(); if (!entryIterator.hasNext()) { return null; @@ -130,7 +131,7 @@ protected Entry standardFirstEntry() { } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return delegate().lastEntry(); } @@ -141,7 +142,7 @@ public Entry lastEntry() { *

    If you override {@link #descendingMultiset} or {@link #entrySet()}, you may wish to override * {@link #firstEntry()} to forward to this implementation. */ - protected Entry standardLastEntry() { + protected @Nullable Entry standardLastEntry() { Iterator> entryIterator = descendingMultiset().entrySet().iterator(); if (!entryIterator.hasNext()) { return null; @@ -151,7 +152,7 @@ protected Entry standardLastEntry() { } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { return delegate().pollFirstEntry(); } @@ -161,7 +162,7 @@ public Entry pollFirstEntry() { *

    If you override {@link #entrySet()}, you may wish to override {@link #pollFirstEntry()} to * forward to this implementation. */ - protected Entry standardPollFirstEntry() { + protected @Nullable Entry standardPollFirstEntry() { Iterator> entryIterator = entrySet().iterator(); if (!entryIterator.hasNext()) { return null; @@ -173,7 +174,7 @@ protected Entry standardPollFirstEntry() { } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { return delegate().pollLastEntry(); } @@ -184,7 +185,7 @@ public Entry pollLastEntry() { *

    If you override {@link #descendingMultiset()} or {@link #entrySet()}, you may wish to * override {@link #pollLastEntry()} to forward to this implementation. */ - protected Entry standardPollLastEntry() { + protected @Nullable Entry standardPollLastEntry() { Iterator> entryIterator = descendingMultiset().entrySet().iterator(); if (!entryIterator.hasNext()) { return null; diff --git a/guava/src/com/google/common/collect/ForwardingSortedSet.java b/guava/src/com/google/common/collect/ForwardingSortedSet.java index 4c4ddf4ebeec..27bd6ca79041 100644 --- a/guava/src/com/google/common/collect/ForwardingSortedSet.java +++ b/guava/src/com/google/common/collect/ForwardingSortedSet.java @@ -52,7 +52,8 @@ * @since 2.0 */ @GwtCompatible -public abstract class ForwardingSortedSet extends ForwardingSet implements SortedSet { +public abstract class ForwardingSortedSet extends ForwardingSet + implements SortedSet { /** Constructor for use by subclasses. */ protected ForwardingSortedSet() {} @@ -61,7 +62,7 @@ protected ForwardingSortedSet() {} protected abstract SortedSet delegate(); @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return delegate().comparator(); } @@ -90,13 +91,13 @@ public SortedSet tailSet(E fromElement) { return delegate().tailSet(fromElement); } - // unsafe, but worst case is a CCE is thrown, which callers will be expecting - @SuppressWarnings("unchecked") + // unsafe, but worst case is a CCE or NPE is thrown, which callers will be expecting + @SuppressWarnings({"unchecked", "nullness"}) private int unsafeCompare(@Nullable Object o1, @Nullable Object o2) { Comparator comparator = comparator(); return (comparator == null) - ? ((Comparable) o1).compareTo(o2) - : ((Comparator) comparator).compare(o1, o2); + ? ((Comparable<@Nullable Object>) o1).compareTo(o2) + : ((Comparator<@Nullable Object>) comparator).compare(o1, o2); } /** @@ -110,9 +111,9 @@ private int unsafeCompare(@Nullable Object o1, @Nullable Object o2) { @Beta protected boolean standardContains(@Nullable Object object) { try { - // any ClassCastExceptions are caught - @SuppressWarnings("unchecked") - SortedSet self = (SortedSet) this; + // any ClassCastExceptions and NullPointerExceptions are caught + @SuppressWarnings({"unchecked", "nullness"}) + SortedSet<@Nullable Object> self = (SortedSet<@Nullable Object>) this; Object ceiling = self.tailSet(object).first(); return unsafeCompare(ceiling, object) == 0; } catch (ClassCastException | NoSuchElementException | NullPointerException e) { @@ -131,10 +132,10 @@ protected boolean standardContains(@Nullable Object object) { @Beta protected boolean standardRemove(@Nullable Object object) { try { - // any ClassCastExceptions are caught - @SuppressWarnings("unchecked") - SortedSet self = (SortedSet) this; - Iterator iterator = self.tailSet(object).iterator(); + // any ClassCastExceptions and NullPointerExceptions are caught + @SuppressWarnings({"unchecked", "nullness"}) + SortedSet<@Nullable Object> self = (SortedSet<@Nullable Object>) this; + Iterator<@Nullable Object> iterator = self.tailSet(object).iterator(); if (iterator.hasNext()) { Object ceiling = iterator.next(); if (unsafeCompare(ceiling, object) == 0) { diff --git a/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java b/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java index 546eb477e942..6aec49e4627b 100644 --- a/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java +++ b/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java @@ -34,8 +34,9 @@ * @since 3.0 */ @GwtCompatible -public abstract class ForwardingSortedSetMultimap extends ForwardingSetMultimap - implements SortedSetMultimap { +public abstract class ForwardingSortedSetMultimap< + K, V> + extends ForwardingSetMultimap implements SortedSetMultimap { /** Constructor for use by subclasses. */ protected ForwardingSortedSetMultimap() {} @@ -44,7 +45,7 @@ protected ForwardingSortedSetMultimap() {} protected abstract SortedSetMultimap delegate(); @Override - public SortedSet get(@Nullable K key) { + public SortedSet get(K key) { return delegate().get(key); } @@ -59,7 +60,7 @@ public SortedSet replaceValues(K key, Iterable values) { } @Override - public Comparator valueComparator() { + public @Nullable Comparator valueComparator() { return delegate().valueComparator(); } } diff --git a/guava/src/com/google/common/collect/ForwardingTable.java b/guava/src/com/google/common/collect/ForwardingTable.java index 71a54cfbcfea..18724eb176e6 100644 --- a/guava/src/com/google/common/collect/ForwardingTable.java +++ b/guava/src/com/google/common/collect/ForwardingTable.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A table which forwards all its method calls to another table. Subclasses should override one or @@ -31,7 +32,9 @@ * @since 7.0 */ @GwtCompatible -public abstract class ForwardingTable extends ForwardingObject implements Table { +public abstract class ForwardingTable< + R, C, V> + extends ForwardingObject implements Table { /** Constructor for use by subclasses. */ protected ForwardingTable() {} @@ -64,27 +67,27 @@ public Map> columnMap() { } @Override - public boolean contains(Object rowKey, Object columnKey) { + public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) { return delegate().contains(rowKey, columnKey); } @Override - public boolean containsColumn(Object columnKey) { + public boolean containsColumn(@Nullable Object columnKey) { return delegate().containsColumn(columnKey); } @Override - public boolean containsRow(Object rowKey) { + public boolean containsRow(@Nullable Object rowKey) { return delegate().containsRow(rowKey); } @Override - public boolean containsValue(Object value) { + public boolean containsValue(@Nullable Object value) { return delegate().containsValue(value); } @Override - public V get(Object rowKey, Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { return delegate().get(rowKey, columnKey); } @@ -95,7 +98,7 @@ public boolean isEmpty() { @CanIgnoreReturnValue @Override - public V put(R rowKey, C columnKey, V value) { + public @Nullable V put(R rowKey, C columnKey, V value) { return delegate().put(rowKey, columnKey, value); } @@ -106,7 +109,7 @@ public void putAll(Table table) { @CanIgnoreReturnValue @Override - public V remove(Object rowKey, Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { return delegate().remove(rowKey, columnKey); } @@ -136,7 +139,7 @@ public Collection values() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { return (obj == this) || delegate().equals(obj); } diff --git a/guava/src/com/google/common/collect/GeneralRange.java b/guava/src/com/google/common/collect/GeneralRange.java index 1ce5659239bb..1301904b5222 100644 --- a/guava/src/com/google/common/collect/GeneralRange.java +++ b/guava/src/com/google/common/collect/GeneralRange.java @@ -38,10 +38,10 @@ final class GeneralRange implements Serializable { /** Converts a Range to a GeneralRange. */ static GeneralRange from(Range range) { - @Nullable T lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : null; + T lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : null; BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : OPEN; - @Nullable T upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : null; + T upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : null; BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : OPEN; return new GeneralRange( Ordering.natural(), @@ -63,7 +63,7 @@ static GeneralRange all(Comparator comparator) { * endpoint behavior. */ static GeneralRange downTo( - Comparator comparator, @Nullable T endpoint, BoundType boundType) { + Comparator comparator, T endpoint, BoundType boundType) { return new GeneralRange(comparator, true, endpoint, boundType, false, null, OPEN); } @@ -72,7 +72,7 @@ static GeneralRange downTo( * endpoint behavior. */ static GeneralRange upTo( - Comparator comparator, @Nullable T endpoint, BoundType boundType) { + Comparator comparator, T endpoint, BoundType boundType) { return new GeneralRange(comparator, false, null, OPEN, true, endpoint, boundType); } @@ -82,9 +82,9 @@ static GeneralRange upTo( */ static GeneralRange range( Comparator comparator, - @Nullable T lower, + T lower, BoundType lowerType, - @Nullable T upper, + T upper, BoundType upperType) { return new GeneralRange(comparator, true, lower, lowerType, true, upper, upperType); } @@ -97,6 +97,7 @@ static GeneralRange range( private final @Nullable T upperEndpoint; private final BoundType upperBoundType; + @SuppressWarnings("nullness") // too much effort for the payoff private GeneralRange( Comparator comparator, boolean hasLowerBound, @@ -143,35 +144,50 @@ boolean hasUpperBound() { } boolean isEmpty() { - return (hasUpperBound() && tooLow(getUpperEndpoint())) - || (hasLowerBound() && tooHigh(getLowerEndpoint())); + // The casts are safe because of the has*Bound() checks. + return (hasUpperBound() && tooLow(uncheckedCastNullableTToT(getUpperEndpoint()))) + || (hasLowerBound() && tooHigh(uncheckedCastNullableTToT(getLowerEndpoint()))); } - boolean tooLow(@Nullable T t) { + boolean tooLow(T t) { if (!hasLowerBound()) { return false; } - T lbound = getLowerEndpoint(); + // The cast is safe because of the hasLowerBound() check. + T lbound = uncheckedCastNullableTToT(getLowerEndpoint()); int cmp = comparator.compare(t, lbound); return cmp < 0 | (cmp == 0 & getLowerBoundType() == OPEN); } - boolean tooHigh(@Nullable T t) { + boolean tooHigh(T t) { if (!hasUpperBound()) { return false; } - T ubound = getUpperEndpoint(); + // The cast is safe because of the hasUpperBound() check. + T ubound = uncheckedCastNullableTToT(getUpperEndpoint()); int cmp = comparator.compare(t, ubound); return cmp > 0 | (cmp == 0 & getUpperBoundType() == OPEN); } - boolean contains(@Nullable T t) { + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T endpoint) { + /* + * We can't use requireNonNull because `endpoint` might be null. Specifically, it can be null + * because the range might have one of its endpoints at the null value. This is in contrast to + * the other way for `endpoint` to be null, which is for the range not to have an endpoint on + * that side. + */ + return endpoint; + } + + boolean contains(T t) { return !tooLow(t) && !tooHigh(t); } /** * Returns the intersection of the two ranges, or an empty range if their intersection is empty. */ + @SuppressWarnings("nullness") // too much effort for the payoff GeneralRange intersect(GeneralRange other) { checkNotNull(other); checkArgument(comparator.equals(other.comparator)); @@ -276,6 +292,7 @@ public String toString() { + (upperBoundType == CLOSED ? ']' : ')'); } + @Nullable T getLowerEndpoint() { return lowerEndpoint; } @@ -284,6 +301,7 @@ BoundType getLowerBoundType() { return lowerBoundType; } + @Nullable T getUpperEndpoint() { return upperEndpoint; } diff --git a/guava/src/com/google/common/collect/HashBasedTable.java b/guava/src/com/google/common/collect/HashBasedTable.java index 8f6df57808e6..ab5614c78b15 100644 --- a/guava/src/com/google/common/collect/HashBasedTable.java +++ b/guava/src/com/google/common/collect/HashBasedTable.java @@ -20,11 +20,10 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.base.Supplier; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.Serializable; import java.util.LinkedHashMap; import java.util.Map; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Implementation of {@link Table} using linked hash tables. This guarantees predictable iteration @@ -49,8 +48,11 @@ * @since 7.0 */ @GwtCompatible(serializable = true) -public class HashBasedTable extends StandardTable { - private static class Factory implements Supplier>, Serializable { +public class HashBasedTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends StandardTable { + private static class Factory + implements Supplier>, Serializable { final int expectedSize; Factory(int expectedSize) { @@ -66,7 +68,8 @@ public Map get() { } /** Creates an empty {@code HashBasedTable}. */ - public static HashBasedTable create() { + public static + HashBasedTable create() { return new HashBasedTable<>(new LinkedHashMap>(), new Factory(0)); } @@ -78,8 +81,8 @@ public static HashBasedTable create() { * @throws IllegalArgumentException if {@code expectedRows} or {@code expectedCellsPerRow} is * negative */ - public static HashBasedTable create( - int expectedRows, int expectedCellsPerRow) { + public static + HashBasedTable create(int expectedRows, int expectedCellsPerRow) { checkNonnegative(expectedCellsPerRow, "expectedCellsPerRow"); Map> backingMap = Maps.newLinkedHashMapWithExpectedSize(expectedRows); return new HashBasedTable<>(backingMap, new Factory(expectedCellsPerRow)); @@ -92,8 +95,8 @@ public static HashBasedTable create( * @throws NullPointerException if any of the row keys, column keys, or values in {@code table} is * null */ - public static HashBasedTable create( - Table table) { + public static + HashBasedTable create(Table table) { HashBasedTable result = create(); result.putAll(table); return result; @@ -103,43 +106,5 @@ public static HashBasedTable create( super(backingMap, factory); } - // Overriding so NullPointerTester test passes. - - @Override - public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) { - return super.contains(rowKey, columnKey); - } - - @Override - public boolean containsColumn(@Nullable Object columnKey) { - return super.containsColumn(columnKey); - } - - @Override - public boolean containsRow(@Nullable Object rowKey) { - return super.containsRow(rowKey); - } - - @Override - public boolean containsValue(@Nullable Object value) { - return super.containsValue(value); - } - - @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { - return super.get(rowKey, columnKey); - } - - @Override - public boolean equals(@Nullable Object obj) { - return super.equals(obj); - } - - @CanIgnoreReturnValue - @Override - public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { - return super.remove(rowKey, columnKey); - } - private static final long serialVersionUID = 0; } diff --git a/guava/src/com/google/common/collect/HashBiMap.java b/guava/src/com/google/common/collect/HashBiMap.java index 33365ec7314b..575e0e48b185 100644 --- a/guava/src/com/google/common/collect/HashBiMap.java +++ b/guava/src/com/google/common/collect/HashBiMap.java @@ -17,8 +17,9 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; import static com.google.common.collect.Hashing.smearedHash; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -56,8 +57,8 @@ * @since 2.0 */ @GwtCompatible(emulated = true) -public final class HashBiMap extends IteratorBasedAbstractMap - implements BiMap, Serializable { +public final class HashBiMap + extends IteratorBasedAbstractMap implements BiMap, Serializable { /** Returns a new, empty {@code HashBiMap} with the default initial capacity (16). */ public static HashBiMap create() { @@ -70,7 +71,8 @@ public static HashBiMap create() { * @param expectedSize the expected number of entries * @throws IllegalArgumentException if the specified expected size is negative */ - public static HashBiMap create(int expectedSize) { + public static HashBiMap create( + int expectedSize) { return new HashBiMap<>(expectedSize); } @@ -78,13 +80,15 @@ public static HashBiMap create(int expectedSize) { * Constructs a new bimap containing initial values from {@code map}. The bimap is created with an * initial capacity sufficient to hold the mappings in the specified map. */ - public static HashBiMap create(Map map) { + public static HashBiMap create( + Map map) { HashBiMap bimap = create(map.size()); bimap.putAll(map); return bimap; } - private static final class BiEntry extends ImmutableEntry { + private static final class BiEntry + extends ImmutableEntry { final int keyHash; final int valueHash; @@ -103,14 +107,16 @@ private static final class BiEntry extends ImmutableEntry { private static final double LOAD_FACTOR = 1.0; - private transient BiEntry[] hashTableKToV; - private transient BiEntry[] hashTableVToK; + private transient @Nullable BiEntry[] hashTableKToV; + private transient @Nullable BiEntry[] hashTableVToK; private transient @Nullable BiEntry firstInKeyInsertionOrder; private transient @Nullable BiEntry lastInKeyInsertionOrder; private transient int size; private transient int mask; private transient int modCount; + // hashTableKToV and hashTableVToK are initialized by init(). + @SuppressWarnings("nullness") private HashBiMap(int expectedSize) { init(expectedSize); } @@ -134,9 +140,14 @@ private void init(int expectedSize) { private void delete(BiEntry entry) { int keyBucket = entry.keyHash & mask; BiEntry prevBucketEntry = null; + /* + * requireNonNull is safe as long as we are careful to call delete() only on entries that still + * exist in the map. (There may be edge cases when the map is modified after an entry is + * returned to the user, but in general, all bets are off then.) + */ for (BiEntry bucketEntry = hashTableKToV[keyBucket]; true; - bucketEntry = bucketEntry.nextInKToVBucket) { + bucketEntry = requireNonNull(bucketEntry).nextInKToVBucket) { if (bucketEntry == entry) { if (prevBucketEntry == null) { hashTableKToV[keyBucket] = entry.nextInKToVBucket; @@ -150,9 +161,10 @@ private void delete(BiEntry entry) { int valueBucket = entry.valueHash & mask; prevBucketEntry = null; + // requireNonNull is safe: See the comment above the previous loop. for (BiEntry bucketEntry = hashTableVToK[valueBucket]; true; - bucketEntry = bucketEntry.nextInVToKBucket) { + bucketEntry = requireNonNull(bucketEntry).nextInVToKBucket) { if (bucketEntry == entry) { if (prevBucketEntry == null) { hashTableVToK[valueBucket] = entry.nextInVToKBucket; @@ -217,7 +229,7 @@ private void insert(BiEntry entry, @Nullable BiEntry oldEntryForKey) modCount++; } - private BiEntry seekByKey(@Nullable Object key, int keyHash) { + private @Nullable BiEntry seekByKey(@Nullable Object key, int keyHash) { for (BiEntry entry = hashTableKToV[keyHash & mask]; entry != null; entry = entry.nextInKToVBucket) { @@ -228,7 +240,7 @@ private BiEntry seekByKey(@Nullable Object key, int keyHash) { return null; } - private BiEntry seekByValue(@Nullable Object value, int valueHash) { + private @Nullable BiEntry seekByValue(@Nullable Object value, int valueHash) { for (BiEntry entry = hashTableVToK[valueHash & mask]; entry != null; entry = entry.nextInVToKBucket) { @@ -266,11 +278,11 @@ public boolean containsValue(@Nullable Object value) { @CanIgnoreReturnValue @Override - public V put(@Nullable K key, @Nullable V value) { + public @Nullable V put(K key, V value) { return put(key, value, false); } - private V put(@Nullable K key, @Nullable V value, boolean force) { + private @Nullable V put(K key, V value, boolean force) { int keyHash = smearedHash(key); int valueHash = smearedHash(value); @@ -306,11 +318,11 @@ private V put(@Nullable K key, @Nullable V value, boolean force) { @CanIgnoreReturnValue @Override - public @Nullable V forcePut(@Nullable K key, @Nullable V value) { + public @Nullable V forcePut(K key, V value) { return put(key, value, true); } - private @Nullable K putInverse(@Nullable V value, @Nullable K key, boolean force) { + private @Nullable K putInverse(V value, K key, boolean force) { int valueHash = smearedHash(value); int keyHash = smearedHash(key); @@ -355,7 +367,7 @@ private V put(@Nullable K key, @Nullable V value, boolean force) { } private void rehashIfNecessary() { - BiEntry[] oldKToV = hashTableKToV; + @Nullable BiEntry[] oldKToV = hashTableKToV; if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) { int newTableSize = oldKToV.length * 2; @@ -374,7 +386,7 @@ private void rehashIfNecessary() { } @SuppressWarnings("unchecked") - private BiEntry[] createTable(int length) { + private @Nullable BiEntry[] createTable(int length) { return new BiEntry[length]; } @@ -408,8 +420,8 @@ public int size() { } abstract class Itr implements Iterator { - BiEntry next = firstInKeyInsertionOrder; - BiEntry toRemove = null; + @Nullable BiEntry next = firstInKeyInsertionOrder; + @Nullable BiEntry toRemove = null; int expectedModCount = modCount; int remaining = size(); @@ -427,7 +439,8 @@ public T next() { throw new NoSuchElementException(); } - BiEntry entry = next; + // requireNonNull is safe because of the hasNext check. + BiEntry entry = requireNonNull(next); next = entry.nextInKeyInsertionOrder; toRemove = entry; remaining--; @@ -439,7 +452,9 @@ public void remove() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } - checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } delete(toRemove); expectedModCount = modCount; toRemove = null; @@ -587,18 +602,18 @@ public boolean containsKey(@Nullable Object value) { } @Override - public K get(@Nullable Object value) { + public @Nullable K get(@Nullable Object value) { return Maps.keyOrNull(seekByValue(value, smearedHash(value))); } @CanIgnoreReturnValue @Override - public @Nullable K put(@Nullable V value, @Nullable K key) { + public @Nullable K put(V value, K key) { return putInverse(value, key, false); } @Override - public @Nullable K forcePut(@Nullable V value, @Nullable K key) { + public @Nullable K forcePut(V value, K key) { return putInverse(value, key, true); } @@ -724,7 +739,9 @@ Object writeReplace() { } } - private static final class InverseSerializedForm implements Serializable { + private static final class InverseSerializedForm< + K, V> + implements Serializable { private final HashBiMap bimap; InverseSerializedForm(HashBiMap bimap) { diff --git a/guava/src/com/google/common/collect/HashMultimap.java b/guava/src/com/google/common/collect/HashMultimap.java index 250f4f6473d5..98bfde3caceb 100644 --- a/guava/src/com/google/common/collect/HashMultimap.java +++ b/guava/src/com/google/common/collect/HashMultimap.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Implementation of {@link Multimap} using hash tables. @@ -44,7 +45,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public final class HashMultimap extends HashMultimapGwtSerializationDependencies { +public final class HashMultimap + extends HashMultimapGwtSerializationDependencies { private static final int DEFAULT_VALUES_PER_KEY = 2; @VisibleForTesting transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY; @@ -55,7 +57,8 @@ public final class HashMultimap extends HashMultimapGwtSerializationDepend *

    This method will soon be deprecated in favor of {@code * MultimapBuilder.hashKeys().hashSetValues().build()}. */ - public static HashMultimap create() { + public static + HashMultimap create() { return new HashMultimap<>(); } @@ -71,7 +74,8 @@ public static HashMultimap create() { * @throws IllegalArgumentException if {@code expectedKeys} or {@code expectedValuesPerKey} is * negative */ - public static HashMultimap create(int expectedKeys, int expectedValuesPerKey) { + public static HashMultimap create( + int expectedKeys, int expectedValuesPerKey) { return new HashMultimap<>(expectedKeys, expectedValuesPerKey); } @@ -85,7 +89,8 @@ public static HashMultimap create(int expectedKeys, int expectedVal * * @param multimap the multimap whose contents are copied to this multimap */ - public static HashMultimap create(Multimap multimap) { + public static HashMultimap create( + Multimap multimap) { return new HashMultimap<>(multimap); } diff --git a/guava/src/com/google/common/collect/HashMultimapGwtSerializationDependencies.java b/guava/src/com/google/common/collect/HashMultimapGwtSerializationDependencies.java index 0922c3839080..45d287a029bc 100644 --- a/guava/src/com/google/common/collect/HashMultimapGwtSerializationDependencies.java +++ b/guava/src/com/google/common/collect/HashMultimapGwtSerializationDependencies.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Collection; import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A dummy superclass to support GWT serialization of the element types of a {@link HashMultimap}. @@ -30,7 +31,9 @@ *

    TODO(cpovirk): Consider applying this subclass approach to our other types. */ @GwtCompatible(emulated = true) -abstract class HashMultimapGwtSerializationDependencies extends AbstractSetMultimap { +abstract class HashMultimapGwtSerializationDependencies< + K, V> + extends AbstractSetMultimap { HashMultimapGwtSerializationDependencies(Map> map) { super(map); } diff --git a/guava/src/com/google/common/collect/HashMultiset.java b/guava/src/com/google/common/collect/HashMultiset.java index d820434eba16..b48313224714 100644 --- a/guava/src/com/google/common/collect/HashMultiset.java +++ b/guava/src/com/google/common/collect/HashMultiset.java @@ -22,6 +22,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashMap; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Multiset implementation backed by a {@link HashMap}. @@ -56,7 +57,8 @@ public static HashMultiset create(int distinctElements) { * * @param elements the elements that the multiset should contain */ - public static HashMultiset create(Iterable elements) { + public static HashMultiset create( + Iterable elements) { HashMultiset multiset = create(Multisets.inferDistinctElements(elements)); Iterables.addAll(multiset, elements); return multiset; diff --git a/guava/src/com/google/common/collect/ImmutableAsList.java b/guava/src/com/google/common/collect/ImmutableAsList.java index 528a8dca1f85..56f2771fc17c 100644 --- a/guava/src/com/google/common/collect/ImmutableAsList.java +++ b/guava/src/com/google/common/collect/ImmutableAsList.java @@ -21,6 +21,8 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.Serializable; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * List returned by {@link ImmutableCollection#asList} that delegates {@code contains} checks to the @@ -31,11 +33,11 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") -abstract class ImmutableAsList extends ImmutableList { +abstract class ImmutableAsList extends ImmutableList { abstract ImmutableCollection delegateCollection(); @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // The collection's contains() is at least as fast as ImmutableList's // and is often faster. return delegateCollection().contains(target); diff --git a/guava/src/com/google/common/collect/ImmutableBiMap.java b/guava/src/com/google/common/collect/ImmutableBiMap.java index d26a32c671bd..9a8c1ad662f6 100644 --- a/guava/src/com/google/common/collect/ImmutableBiMap.java +++ b/guava/src/com/google/common/collect/ImmutableBiMap.java @@ -29,6 +29,8 @@ import java.util.function.Function; import java.util.stream.Collector; import java.util.stream.Collectors; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link BiMap} whose contents will never change, with many other important properties detailed @@ -38,8 +40,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public abstract class ImmutableBiMap extends ImmutableBiMapFauxverideShim - implements BiMap { +public abstract class ImmutableBiMap + extends ImmutableBiMapFauxverideShim implements BiMap { /** * Returns a {@link Collector} that accumulates elements into an {@code ImmutableBiMap} whose keys @@ -53,21 +55,23 @@ public abstract class ImmutableBiMap extends ImmutableBiMapFauxverideShim< * * @since 21.0 */ - public static Collector> toImmutableBiMap( - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableBiMap( + Function keyFunction, + Function valueFunction) { return CollectCollectors.toImmutableBiMap(keyFunction, valueFunction); } /** Returns the empty bimap. */ // Casting to any type is safe because the set will never hold any elements. @SuppressWarnings("unchecked") - public static ImmutableBiMap of() { + public static ImmutableBiMap of() { return (ImmutableBiMap) RegularImmutableBiMap.EMPTY; } /** Returns an immutable bimap containing a single entry. */ - public static ImmutableBiMap of(K k1, V v1) { + public static ImmutableBiMap of( + K k1, V v1) { return new SingletonImmutableBiMap<>(k1, v1); } @@ -76,7 +80,8 @@ public static ImmutableBiMap of(K k1, V v1) { * * @throws IllegalArgumentException if duplicate keys or values are added */ - public static ImmutableBiMap of(K k1, V v1, K k2, V v2) { + public static ImmutableBiMap of( + K k1, V v1, K k2, V v2) { return RegularImmutableBiMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2)); } @@ -85,7 +90,8 @@ public static ImmutableBiMap of(K k1, V v1, K k2, V v2) { * * @throws IllegalArgumentException if duplicate keys or values are added */ - public static ImmutableBiMap of(K k1, V v1, K k2, V v2, K k3, V v3) { + public static ImmutableBiMap of( + K k1, V v1, K k2, V v2, K k3, V v3) { return RegularImmutableBiMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); } @@ -94,7 +100,8 @@ public static ImmutableBiMap of(K k1, V v1, K k2, V v2, K k3, V v3) * * @throws IllegalArgumentException if duplicate keys or values are added */ - public static ImmutableBiMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static ImmutableBiMap of( + K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { return RegularImmutableBiMap.fromEntries( entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); } @@ -104,7 +111,7 @@ public static ImmutableBiMap of(K k1, V v1, K k2, V v2, K k3, V v3, * * @throws IllegalArgumentException if duplicate keys or values are added */ - public static ImmutableBiMap of( + public static ImmutableBiMap of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { return RegularImmutableBiMap.fromEntries( entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); @@ -116,7 +123,7 @@ public static ImmutableBiMap of( * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder<>(); } @@ -133,7 +140,8 @@ public static Builder builder() { * @since 23.1 */ @Beta - public static Builder builderWithExpectedSize(int expectedSize) { + public static + Builder builderWithExpectedSize(int expectedSize) { checkNonnegative(expectedSize, "expectedSize"); return new Builder<>(expectedSize); } @@ -166,7 +174,8 @@ public static Builder builderWithExpectedSize(int expectedSize) { * * @since 2.0 */ - public static final class Builder extends ImmutableMap.Builder { + public static final class Builder + extends ImmutableMap.Builder { /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link @@ -326,7 +335,8 @@ ImmutableBiMap buildJdkBacked() { * key * @throws NullPointerException if any key or value in {@code map} is null */ - public static ImmutableBiMap copyOf(Map map) { + public static ImmutableBiMap copyOf( + Map map) { if (map instanceof ImmutableBiMap) { @SuppressWarnings("unchecked") // safe since map is not writable ImmutableBiMap bimap = (ImmutableBiMap) map; @@ -349,7 +359,7 @@ public static ImmutableBiMap copyOf(Map m * @since 19.0 */ @Beta - public static ImmutableBiMap copyOf( + public static ImmutableBiMap copyOf( Iterable> entries) { @SuppressWarnings("unchecked") // we'll only be using getKey and getValue, which are covariant Entry[] entryArray = (Entry[]) Iterables.toArray(entries, EMPTY_ENTRY_ARRAY); @@ -401,7 +411,7 @@ final ImmutableSet createValues() { @CanIgnoreReturnValue @Deprecated @Override - public V forcePut(K key, V value) { + public @Nullable V forcePut(K key, V value) { throw new UnsupportedOperationException(); } @@ -414,7 +424,11 @@ public V forcePut(K key, V value) { * bimap and its inverse in sync during serialization, the way AbstractBiMap does. */ private static class SerializedForm extends ImmutableMap.SerializedForm { - SerializedForm(ImmutableBiMap bimap) { + /* + * The explicit "extends Object" works around + * https://github.com/typetools/checker-framework/issues/3013 + */ + SerializedForm(ImmutableBiMap bimap) { super(bimap); } diff --git a/guava/src/com/google/common/collect/ImmutableBiMapFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableBiMapFauxverideShim.java index dd787d5a57aa..157011ecdd1e 100644 --- a/guava/src/com/google/common/collect/ImmutableBiMapFauxverideShim.java +++ b/guava/src/com/google/common/collect/ImmutableBiMapFauxverideShim.java @@ -20,6 +20,8 @@ import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * "Overrides" the {@link ImmutableMap} static methods that lack {@link ImmutableBiMap} equivalents @@ -29,7 +31,8 @@ * @author Louis Wasserman */ @GwtIncompatible -abstract class ImmutableBiMapFauxverideShim extends ImmutableMap { +abstract class ImmutableBiMapFauxverideShim + extends ImmutableMap { /** * Not supported. Use {@link ImmutableBiMap#toImmutableBiMap} instead. This method exists only to * hide {@link ImmutableMap#toImmutableMap(Function, Function)} from consumers of {@code @@ -39,9 +42,10 @@ abstract class ImmutableBiMapFauxverideShim extends ImmutableMap { * @deprecated Use {@link ImmutableBiMap#toImmutableBiMap}. */ @Deprecated - public static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction) { throw new UnsupportedOperationException(); } @@ -54,10 +58,11 @@ abstract class ImmutableBiMapFauxverideShim extends ImmutableMap { * @deprecated */ @Deprecated - public static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction, - BinaryOperator mergeFunction) { + public static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction, + BinaryOperator mergeFunction) { throw new UnsupportedOperationException(); } } diff --git a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java index 8370f0ae91c2..e154784d05ca 100644 --- a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java +++ b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java @@ -17,6 +17,7 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Collections.unmodifiableMap; import com.google.common.annotations.GwtIncompatible; import com.google.common.primitives.Primitives; @@ -24,6 +25,7 @@ import com.google.errorprone.annotations.Immutable; import java.io.Serializable; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -35,7 +37,8 @@ */ @Immutable(containerOf = "B") @GwtIncompatible -public final class ImmutableClassToInstanceMap extends ForwardingMap, B> +public final class ImmutableClassToInstanceMap + extends ForwardingMap, @Nullable B> implements ClassToInstanceMap, Serializable { private static final ImmutableClassToInstanceMap EMPTY = @@ -47,7 +50,7 @@ public final class ImmutableClassToInstanceMap extends ForwardingMap ImmutableClassToInstanceMap of() { + public static ImmutableClassToInstanceMap of() { return (ImmutableClassToInstanceMap) EMPTY; } @@ -56,7 +59,8 @@ public static ImmutableClassToInstanceMap of() { * * @since 19.0 */ - public static ImmutableClassToInstanceMap of(Class type, T value) { + public static ImmutableClassToInstanceMap of( + Class type, T value) { ImmutableMap, B> map = ImmutableMap., B>of(type, value); return new ImmutableClassToInstanceMap(map); } @@ -65,7 +69,7 @@ public static ImmutableClassToInstanceMap of(Class type, * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder(); } @@ -86,7 +90,7 @@ public static Builder builder() { * * @since 2.0 */ - public static final class Builder { + public static final class Builder { private final ImmutableMap.Builder, B> mapBuilder = ImmutableMap.builder(); /** @@ -116,7 +120,7 @@ public Builder putAll(Map, ? exten return this; } - private static T cast(Class type, B value) { + private static T cast(Class type, Object value) { return Primitives.wrap(type).cast(value); } @@ -147,7 +151,7 @@ public ImmutableClassToInstanceMap build() { * @throws NullPointerException if any key or value in {@code map} is null * @throws ClassCastException if any value is not an instance of the type specified by its key */ - public static ImmutableClassToInstanceMap copyOf( + public static ImmutableClassToInstanceMap copyOf( Map, ? extends S> map) { if (map instanceof ImmutableClassToInstanceMap) { @SuppressWarnings("unchecked") // covariant casts safe (unmodifiable) @@ -157,14 +161,15 @@ public static ImmutableClassToInstanceMap copyOf( return new Builder().putAll(map).build(); } - private final ImmutableMap, B> delegate; + private final Map, @Nullable B> delegate; private ImmutableClassToInstanceMap(ImmutableMap, B> delegate) { - this.delegate = delegate; + // Convert from Map<..., B> to Map<..., @Nullable B>. + this.delegate = unmodifiableMap(delegate); } @Override - protected Map, B> delegate() { + protected Map, @Nullable B> delegate() { return delegate; } @@ -183,7 +188,7 @@ protected Map, B> delegate() { @CanIgnoreReturnValue @Deprecated @Override - public T putInstance(Class type, T value) { + public @Nullable T putInstance(Class type, @Nullable T value) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/collect/ImmutableCollection.java b/guava/src/com/google/common/collect/ImmutableCollection.java index 5a76efa9aa9f..732e888b26ea 100644 --- a/guava/src/com/google/common/collect/ImmutableCollection.java +++ b/guava/src/com/google/common/collect/ImmutableCollection.java @@ -20,7 +20,6 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.io.Serializable; import java.util.AbstractCollection; import java.util.Collection; @@ -31,6 +30,7 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Predicate; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -158,12 +158,12 @@ * * @since 2.0 */ -@DoNotMock("Use ImmutableList.of or another implementation") @GwtCompatible(emulated = true) @SuppressWarnings("serial") // we're overriding default serialization // TODO(kevinb): I think we should push everything down to "BaseImmutableCollection" or something, // just to do everything we can to emphasize the "practically an interface" nature of this class. -public abstract class ImmutableCollection extends AbstractCollection implements Serializable { +public abstract class ImmutableCollection extends AbstractCollection + implements Serializable { /* * We expect SIZED (and SUBSIZED, if applicable) to be added by the spliterator factory methods. * These are properties of the collection as a whole; SIZED and SUBSIZED are more properties of @@ -186,12 +186,14 @@ public Spliterator spliterator() { private static final Object[] EMPTY_ARRAY = {}; @Override +@SuppressWarnings("nullness") public final Object[] toArray() { return toArray(EMPTY_ARRAY); } @CanIgnoreReturnValue @Override +@SuppressWarnings("nullness") public final T[] toArray(T[] other) { checkNotNull(other); int size = size(); @@ -255,7 +257,7 @@ public final boolean add(E e) { @CanIgnoreReturnValue @Deprecated @Override - public final boolean remove(Object object) { + public final boolean remove(@Nullable Object object) { throw new UnsupportedOperationException(); } @@ -373,8 +375,7 @@ Object writeReplace() { * * @since 10.0 */ - @DoNotMock - public abstract static class Builder { + public abstract static class Builder { static final int DEFAULT_INITIAL_CAPACITY = 4; static int expandedCapacity(int oldCapacity, int minCapacity) { diff --git a/guava/src/com/google/common/collect/ImmutableEntry.java b/guava/src/com/google/common/collect/ImmutableEntry.java index 0f435e97069a..cbf0dff22d23 100644 --- a/guava/src/com/google/common/collect/ImmutableEntry.java +++ b/guava/src/com/google/common/collect/ImmutableEntry.java @@ -22,22 +22,23 @@ /** @see com.google.common.collect.Maps#immutableEntry(Object, Object) */ @GwtCompatible(serializable = true) -class ImmutableEntry extends AbstractMapEntry implements Serializable { - final @Nullable K key; - final @Nullable V value; +class ImmutableEntry + extends AbstractMapEntry implements Serializable { + final K key; + final V value; - ImmutableEntry(@Nullable K key, @Nullable V value) { + ImmutableEntry(K key, V value) { this.key = key; this.value = value; } @Override - public final @Nullable K getKey() { + public final K getKey() { return key; } @Override - public final @Nullable V getValue() { + public final V getValue() { return value; } diff --git a/guava/src/com/google/common/collect/ImmutableEnumMap.java b/guava/src/com/google/common/collect/ImmutableEnumMap.java index f12e1a9e686c..8b86b11918ec 100644 --- a/guava/src/com/google/common/collect/ImmutableEnumMap.java +++ b/guava/src/com/google/common/collect/ImmutableEnumMap.java @@ -24,6 +24,7 @@ import java.util.EnumMap; import java.util.Spliterator; import java.util.function.BiConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -33,8 +34,10 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization -final class ImmutableEnumMap, V> extends IteratorBasedImmutableMap { - static , V> ImmutableMap asImmutable(EnumMap map) { +final class ImmutableEnumMap, V extends @NonNull Object> + extends IteratorBasedImmutableMap { + static , V extends @NonNull Object> ImmutableMap asImmutable( + EnumMap map) { switch (map.size()) { case 0: return ImmutableMap.of(); @@ -74,12 +77,14 @@ public boolean containsKey(@Nullable Object key) { } @Override - public V get(Object key) { + public @Nullable V get(@Nullable Object key) { return delegate.get(key); } @Override - public boolean equals(Object object) { + public boolean equals(@Nullable Object param) { + // Declare a "true" local variable to avoid flowexpr problems. + Object object = param; if (object == this) { return true; } @@ -118,7 +123,8 @@ Object writeReplace() { /* * This class is used to serialize ImmutableEnumMap instances. */ - private static class EnumSerializedForm, V> implements Serializable { + private static class EnumSerializedForm, V extends @NonNull Object> + implements Serializable { final EnumMap delegate; EnumSerializedForm(EnumMap delegate) { diff --git a/guava/src/com/google/common/collect/ImmutableEnumSet.java b/guava/src/com/google/common/collect/ImmutableEnumSet.java index 5677cbe4fb67..a60d0c6d9970 100644 --- a/guava/src/com/google/common/collect/ImmutableEnumSet.java +++ b/guava/src/com/google/common/collect/ImmutableEnumSet.java @@ -23,6 +23,7 @@ import java.util.EnumSet; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Implementation of {@link ImmutableSet} backed by a non-empty {@link java.util.EnumSet}. @@ -84,13 +85,13 @@ public int size() { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { return delegate.contains(object); } @Override public boolean containsAll(Collection collection) { - if (collection instanceof ImmutableEnumSet) { + if (collection instanceof ImmutableEnumSet) { collection = ((ImmutableEnumSet) collection).delegate; } return delegate.containsAll(collection); @@ -102,7 +103,9 @@ public boolean isEmpty() { } @Override - public boolean equals(Object object) { + public boolean equals(@Nullable Object param) { + // Declare a "true" local variable to avoid flowexpr problems. + Object object = param; if (object == this) { return true; } diff --git a/guava/src/com/google/common/collect/ImmutableList.java b/guava/src/com/google/common/collect/ImmutableList.java index 05e708882b84..d44282acd6e1 100644 --- a/guava/src/com/google/common/collect/ImmutableList.java +++ b/guava/src/com/google/common/collect/ImmutableList.java @@ -42,6 +42,7 @@ import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -58,7 +59,7 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization -public abstract class ImmutableList extends ImmutableCollection +public abstract class ImmutableList extends ImmutableCollection implements List, RandomAccess { /** @@ -67,7 +68,7 @@ public abstract class ImmutableList extends ImmutableCollection * * @since 21.0 */ - public static Collector> toImmutableList() { + public static Collector> toImmutableList() { return CollectCollectors.toImmutableList(); } @@ -78,7 +79,7 @@ public abstract class ImmutableList extends ImmutableCollection */ // Casting to any type is safe because the list will never hold any elements. @SuppressWarnings("unchecked") - public static ImmutableList of() { + public static ImmutableList of() { return (ImmutableList) EMPTY; } @@ -89,7 +90,7 @@ public static ImmutableList of() { * * @throws NullPointerException if {@code element} is null */ - public static ImmutableList of(E element) { + public static ImmutableList of(E element) { return new SingletonImmutableList(element); } @@ -98,7 +99,7 @@ public static ImmutableList of(E element) { * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2) { + public static ImmutableList of(E e1, E e2) { return construct(e1, e2); } @@ -107,7 +108,7 @@ public static ImmutableList of(E e1, E e2) { * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3) { + public static ImmutableList of(E e1, E e2, E e3) { return construct(e1, e2, e3); } @@ -116,7 +117,7 @@ public static ImmutableList of(E e1, E e2, E e3) { * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3, E e4) { + public static ImmutableList of(E e1, E e2, E e3, E e4) { return construct(e1, e2, e3, e4); } @@ -125,7 +126,7 @@ public static ImmutableList of(E e1, E e2, E e3, E e4) { * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3, E e4, E e5) { + public static ImmutableList of(E e1, E e2, E e3, E e4, E e5) { return construct(e1, e2, e3, e4, e5); } @@ -134,7 +135,8 @@ public static ImmutableList of(E e1, E e2, E e3, E e4, E e5) { * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6) { + public static ImmutableList of( + E e1, E e2, E e3, E e4, E e5, E e6) { return construct(e1, e2, e3, e4, e5, e6); } @@ -143,7 +145,8 @@ public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6) { * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + public static ImmutableList of( + E e1, E e2, E e3, E e4, E e5, E e6, E e7) { return construct(e1, e2, e3, e4, e5, e6, e7); } @@ -152,7 +155,8 @@ public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + public static ImmutableList of( + E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { return construct(e1, e2, e3, e4, e5, e6, e7, e8); } @@ -161,7 +165,8 @@ public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, * * @throws NullPointerException if any element is null */ - public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + public static ImmutableList of( + E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9); } @@ -170,7 +175,7 @@ public static ImmutableList of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, * * @throws NullPointerException if any element is null */ - public static ImmutableList of( + public static ImmutableList of( E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); } @@ -180,7 +185,7 @@ public static ImmutableList of( * * @throws NullPointerException if any element is null */ - public static ImmutableList of( + public static ImmutableList of( E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) { return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11); } @@ -197,7 +202,7 @@ public static ImmutableList of( * @since 3.0 (source-compatible since 2.0) */ @SafeVarargs // For Eclipse. For internal javac we have disabled this pointless type of warning. - public static ImmutableList of( + public static ImmutableList of( E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, E e12, E... others) { checkArgument( others.length <= Integer.MAX_VALUE - 12, "the total number of elements must fit in an int"); @@ -225,7 +230,8 @@ public static ImmutableList of( * * @throws NullPointerException if {@code elements} contains a null element */ - public static ImmutableList copyOf(Iterable elements) { + public static ImmutableList copyOf( + Iterable elements) { checkNotNull(elements); // TODO(kevinb): is this here only for GWT? return (elements instanceof Collection) ? copyOf((Collection) elements) @@ -249,7 +255,9 @@ public static ImmutableList copyOf(Iterable elements) { * * @throws NullPointerException if {@code elements} contains a null element */ - public static ImmutableList copyOf(Collection elements) { + @SuppressWarnings("argument.type.incompatible") // arrays + public static ImmutableList copyOf( + Collection elements) { if (elements instanceof ImmutableCollection) { @SuppressWarnings("unchecked") // all supported methods are covariant ImmutableList list = ((ImmutableCollection) elements).asList(); @@ -263,7 +271,8 @@ public static ImmutableList copyOf(Collection elements) { * * @throws NullPointerException if {@code elements} contains a null element */ - public static ImmutableList copyOf(Iterator elements) { + public static ImmutableList copyOf( + Iterator elements) { // We special-case for 0 or 1 elements, but going further is madness. if (!elements.hasNext()) { return of(); @@ -282,7 +291,7 @@ public static ImmutableList copyOf(Iterator elements) { * @throws NullPointerException if {@code elements} contains a null element * @since 3.0 */ - public static ImmutableList copyOf(E[] elements) { + public static ImmutableList copyOf(E[] elements) { switch (elements.length) { case 0: return of(); @@ -331,7 +340,7 @@ public static > ImmutableList sortedCopyOf( * @throws NullPointerException if any element in the input is null * @since 21.0 */ - public static ImmutableList sortedCopyOf( + public static ImmutableList sortedCopyOf( Comparator comparator, Iterable elements) { checkNotNull(comparator); @SuppressWarnings("unchecked") // all supported methods are covariant @@ -342,7 +351,7 @@ public static ImmutableList sortedCopyOf( } /** Views the array as an immutable list. Checks for nulls; does not copy. */ - private static ImmutableList construct(Object... elements) { + private static ImmutableList construct(Object... elements) { return asImmutableList(checkElementsNotNull(elements)); } @@ -351,7 +360,7 @@ private static ImmutableList construct(Object... elements) { * *

    The array must be internally created. */ - static ImmutableList asImmutableList(Object[] elements) { + static ImmutableList asImmutableList(Object[] elements) { return asImmutableList(elements, elements.length); } @@ -359,7 +368,9 @@ static ImmutableList asImmutableList(Object[] elements) { * Views the array as an immutable list. Copies if the specified range does not cover the complete * array. Does not check for nulls. */ - static ImmutableList asImmutableList(Object[] elements, int length) { + @SuppressWarnings("assignment.type.incompatible") // arrays + static ImmutableList asImmutableList( + Object[] elements, int length) { switch (length) { case 0: return of(); @@ -594,7 +605,7 @@ public ImmutableList reverse() { return (size() <= 1) ? this : new ReverseImmutableList(this); } - private static class ReverseImmutableList extends ImmutableList { + private static class ReverseImmutableList extends ImmutableList { private final transient ImmutableList forwardList; ReverseImmutableList(ImmutableList backingList) { @@ -703,7 +714,7 @@ Object writeReplace() { * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder(); } @@ -720,7 +731,7 @@ public static Builder builder() { * @since 23.1 */ @Beta - public static Builder builderWithExpectedSize(int expectedSize) { + public static Builder builderWithExpectedSize(int expectedSize) { checkNonnegative(expectedSize, "expectedSize"); return new ImmutableList.Builder(expectedSize); } @@ -745,7 +756,8 @@ public static Builder builderWithExpectedSize(int expectedSize) { * * @since 2.0 */ - public static final class Builder extends ImmutableCollection.Builder { + public static final class Builder + extends ImmutableCollection.Builder { @VisibleForTesting Object[] contents; private int size; private boolean forceCopy; @@ -763,6 +775,7 @@ public Builder() { this.size = 0; } + @SuppressWarnings("assignment.type.incompatible") // arrays private void getReadyToExpandTo(int minCapacity) { if (contents.length < minCapacity) { this.contents = Arrays.copyOf(contents, expandedCapacity(contents.length, minCapacity)); diff --git a/guava/src/com/google/common/collect/ImmutableListMultimap.java b/guava/src/com/google/common/collect/ImmutableListMultimap.java index 879c71e2b396..7ba58a417253 100644 --- a/guava/src/com/google/common/collect/ImmutableListMultimap.java +++ b/guava/src/com/google/common/collect/ImmutableListMultimap.java @@ -17,6 +17,7 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -37,6 +38,7 @@ import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -50,8 +52,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public class ImmutableListMultimap extends ImmutableMultimap - implements ListMultimap { +public class ImmutableListMultimap + extends ImmutableMultimap implements ListMultimap { /** * Returns a {@link Collector} that accumulates elements into an {@code ImmutableListMultimap} * whose keys and values are the result of applying the provided mapping functions to the input @@ -80,9 +82,10 @@ public class ImmutableListMultimap extends ImmutableMultimap * * @since 21.0 */ - public static Collector> toImmutableListMultimap( - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableListMultimap( + Function keyFunction, + Function valueFunction) { checkNotNull(keyFunction, "keyFunction"); checkNotNull(valueFunction, "valueFunction"); return Collector.of( @@ -123,7 +126,7 @@ public class ImmutableListMultimap extends ImmutableMultimap * * @since 21.0 */ - public static + public static Collector> flatteningToImmutableListMultimap( Function keyFunction, Function> valuesFunction) { @@ -140,19 +143,22 @@ public class ImmutableListMultimap extends ImmutableMultimap /** Returns the empty multimap. */ // Casting is safe because the multimap will never hold any elements. @SuppressWarnings("unchecked") - public static ImmutableListMultimap of() { + public static + ImmutableListMultimap of() { return (ImmutableListMultimap) EmptyImmutableListMultimap.INSTANCE; } /** Returns an immutable multimap containing a single entry. */ - public static ImmutableListMultimap of(K k1, V v1) { + public static + ImmutableListMultimap of(K k1, V v1) { ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); builder.put(k1, v1); return builder.build(); } /** Returns an immutable multimap containing the given entries, in order. */ - public static ImmutableListMultimap of(K k1, V v1, K k2, V v2) { + public static + ImmutableListMultimap of(K k1, V v1, K k2, V v2) { ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -160,7 +166,8 @@ public static ImmutableListMultimap of(K k1, V v1, K k2, V v2) { } /** Returns an immutable multimap containing the given entries, in order. */ - public static ImmutableListMultimap of(K k1, V v1, K k2, V v2, K k3, V v3) { + public static + ImmutableListMultimap of(K k1, V v1, K k2, V v2, K k3, V v3) { ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -169,8 +176,8 @@ public static ImmutableListMultimap of(K k1, V v1, K k2, V v2, K k3 } /** Returns an immutable multimap containing the given entries, in order. */ - public static ImmutableListMultimap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static + ImmutableListMultimap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -180,8 +187,8 @@ public static ImmutableListMultimap of( } /** Returns an immutable multimap containing the given entries, in order. */ - public static ImmutableListMultimap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { + public static + ImmutableListMultimap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -197,7 +204,7 @@ public static ImmutableListMultimap of( * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder<>(); } @@ -220,7 +227,8 @@ public static Builder builder() { * * @since 2.0 */ - public static final class Builder extends ImmutableMultimap.Builder { + public static final class Builder + extends ImmutableMultimap.Builder { /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link * ImmutableListMultimap#builder}. @@ -329,8 +337,8 @@ public ImmutableListMultimap build() { * * @throws NullPointerException if any key or value in {@code multimap} is null */ - public static ImmutableListMultimap copyOf( - Multimap multimap) { + public static + ImmutableListMultimap copyOf(Multimap multimap) { if (multimap.isEmpty()) { return of(); } @@ -356,15 +364,18 @@ public static ImmutableListMultimap copyOf( * @since 19.0 */ @Beta - public static ImmutableListMultimap copyOf( - Iterable> entries) { + public static + ImmutableListMultimap copyOf( + Iterable> entries) { return new Builder().putAll(entries).build(); } /** Creates an ImmutableListMultimap from an asMap.entrySet. */ - static ImmutableListMultimap fromMapEntries( - Collection>> mapEntries, - @Nullable Comparator valueComparator) { + static + ImmutableListMultimap fromMapEntries( + Collection>> + mapEntries, + @Nullable Comparator valueComparator) { if (mapEntries.isEmpty()) { return of(); } @@ -400,13 +411,13 @@ static ImmutableListMultimap fromMapEntries( * parameters used to build this multimap. */ @Override - public ImmutableList get(@Nullable K key) { + public ImmutableList get(K key) { // This cast is safe as its type is known in constructor. ImmutableList list = (ImmutableList) map.get(key); return (list == null) ? ImmutableList.of() : list; } - @LazyInit @RetainedWith private transient ImmutableListMultimap inverse; + @LazyInit @RetainedWith private transient @Nullable ImmutableListMultimap inverse; /** * {@inheritDoc} @@ -442,7 +453,7 @@ private ImmutableListMultimap invert() { @CanIgnoreReturnValue @Deprecated @Override - public ImmutableList removeAll(Object key) { + public ImmutableList removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -488,7 +499,11 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo ImmutableList.Builder valuesBuilder = ImmutableList.builder(); for (int j = 0; j < valueCount; j++) { - valuesBuilder.add(stream.readObject()); + /* + * requireNonNull is safe for valid serialized data, and for invalid data, it produces the + * NullPointerException that we'd want. + */ + valuesBuilder.add(requireNonNull(stream.readObject())); } builder.put(key, valuesBuilder.build()); tmpSize += valueCount; diff --git a/guava/src/com/google/common/collect/ImmutableMap.java b/guava/src/com/google/common/collect/ImmutableMap.java index 646dafeb694b..8cb8bd425b9f 100644 --- a/guava/src/com/google/common/collect/ImmutableMap.java +++ b/guava/src/com/google/common/collect/ImmutableMap.java @@ -25,7 +25,6 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import com.google.errorprone.annotations.concurrent.LazyInit; import com.google.j2objc.annotations.RetainedWith; import com.google.j2objc.annotations.WeakOuter; @@ -47,6 +46,7 @@ import java.util.function.Function; import java.util.stream.Collector; import java.util.stream.Collectors; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -60,10 +60,10 @@ * @author Kevin Bourrillion * @since 2.0 */ -@DoNotMock("Use ImmutableMap.of or another implementation") @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization -public abstract class ImmutableMap implements Map, Serializable { +public abstract class ImmutableMap + implements Map, Serializable { /** * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys @@ -77,9 +77,10 @@ public abstract class ImmutableMap implements Map, Serializable { * * @since 21.0 */ - public static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction) { return CollectCollectors.toImmutableMap(keyFunction, valueFunction); } @@ -93,10 +94,11 @@ public abstract class ImmutableMap implements Map, Serializable { * * @since 21.0 */ - public static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction, - BinaryOperator mergeFunction) { + public static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction, + BinaryOperator mergeFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); checkNotNull(mergeFunction); @@ -111,7 +113,7 @@ public abstract class ImmutableMap implements Map, Serializable { * code. */ @SuppressWarnings("unchecked") - public static ImmutableMap of() { + public static ImmutableMap of() { return (ImmutableMap) RegularImmutableMap.EMPTY; } @@ -120,7 +122,8 @@ public static ImmutableMap of() { * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable * mainly for consistency and maintainability of your code. */ - public static ImmutableMap of(K k1, V v1) { + public static ImmutableMap of( + K k1, V v1) { return ImmutableBiMap.of(k1, v1); } @@ -129,7 +132,8 @@ public static ImmutableMap of(K k1, V v1) { * * @throws IllegalArgumentException if duplicate keys are provided */ - public static ImmutableMap of(K k1, V v1, K k2, V v2) { + public static ImmutableMap of( + K k1, V v1, K k2, V v2) { return RegularImmutableMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2)); } @@ -138,7 +142,8 @@ public static ImmutableMap of(K k1, V v1, K k2, V v2) { * * @throws IllegalArgumentException if duplicate keys are provided */ - public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3) { + public static ImmutableMap of( + K k1, V v1, K k2, V v2, K k3, V v3) { return RegularImmutableMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); } @@ -147,7 +152,8 @@ public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3) { * * @throws IllegalArgumentException if duplicate keys are provided */ - public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static ImmutableMap of( + K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { return RegularImmutableMap.fromEntries( entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); } @@ -157,7 +163,7 @@ public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3, K * * @throws IllegalArgumentException if duplicate keys are provided */ - public static ImmutableMap of( + public static ImmutableMap of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { return RegularImmutableMap.fromEntries( entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); @@ -172,7 +178,8 @@ public static ImmutableMap of( *

    A call to {@link Entry#setValue} on the returned entry will always throw {@link * UnsupportedOperationException}. */ - static Entry entryOf(K key, V value) { + static Entry entryOf( + K key, V value) { checkEntryNotNull(key, value); return new AbstractMap.SimpleImmutableEntry<>(key, value); } @@ -245,8 +252,7 @@ static IllegalArgumentException conflictException( * * @since 2.0 */ - @DoNotMock - public static class Builder { + public static class Builder { @Nullable Comparator valueComparator; Entry[] entries; int size; @@ -267,6 +273,7 @@ public Builder() { this.entriesUsed = false; } + @SuppressWarnings("assignment.type.incompatible") // arrays private void ensureCapacity(int minCapacity) { if (minCapacity > entries.length) { entries = @@ -369,6 +376,7 @@ Builder combine(Builder other) { * * @throws IllegalArgumentException if duplicate keys were added */ + @SuppressWarnings("assignment.type.incompatible") // arrays public ImmutableMap build() { /* * If entries is full, or if hash flooding is detected, then this implementation may end up @@ -423,7 +431,8 @@ ImmutableMap buildJdkBacked() { * * @throws NullPointerException if any key or value in {@code map} is null */ - public static ImmutableMap copyOf(Map map) { + public static ImmutableMap copyOf( + Map map) { if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) { @SuppressWarnings("unchecked") // safe since map is not writable ImmutableMap kvMap = (ImmutableMap) map; @@ -447,7 +456,7 @@ public static ImmutableMap copyOf(Map map * @since 19.0 */ @Beta - public static ImmutableMap copyOf( + public static ImmutableMap copyOf( Iterable> entries) { @SuppressWarnings("unchecked") // we'll only be using getKey and getValue, which are covariant Entry[] entryArray = (Entry[]) Iterables.toArray(entries, EMPTY_ENTRY_ARRAY); @@ -466,10 +475,10 @@ public static ImmutableMap copyOf( } } - private static , V> ImmutableMap copyOfEnumMap( + private static , V extends @NonNull Object> ImmutableMap copyOfEnumMap( EnumMap original) { EnumMap copy = new EnumMap<>(original); - for (Entry entry : copy.entrySet()) { + for (Entry entry : copy.entrySet()) { checkEntryNotNull(entry.getKey(), entry.getValue()); } return ImmutableEnumMap.asImmutable(copy); @@ -477,7 +486,9 @@ private static , V> ImmutableMap copyOfEnumMap( static final Entry[] EMPTY_ENTRY_ARRAY = new Entry[0]; - abstract static class IteratorBasedImmutableMap extends ImmutableMap { + abstract static class IteratorBasedImmutableMap< + K extends @NonNull Object, V extends @NonNull Object> + extends ImmutableMap { abstract UnmodifiableIterator> entryIterator(); Spliterator> entrySpliterator() { @@ -525,7 +536,7 @@ ImmutableCollection createValues() { @CanIgnoreReturnValue @Deprecated @Override - public final V put(K k, V v) { + public final @Nullable V put(K k, V v) { throw new UnsupportedOperationException(); } @@ -562,7 +573,7 @@ public final boolean replace(K key, V oldValue, V newValue) { */ @Deprecated @Override - public final V replace(K key, V value) { + public final @Nullable V replace(K key, V value) { throw new UnsupportedOperationException(); } @@ -574,7 +585,8 @@ public final V replace(K key, V value) { */ @Deprecated @Override - public final V computeIfAbsent(K key, Function mappingFunction) { + public final V computeIfAbsent( + K key, Function mappingFunction) { throw new UnsupportedOperationException(); } @@ -587,7 +599,7 @@ public final V computeIfAbsent(K key, Function mappingFu @Deprecated @Override public final V computeIfPresent( - K key, BiFunction remappingFunction) { + K key, BiFunction remappingFunction) { throw new UnsupportedOperationException(); } @@ -599,7 +611,8 @@ public final V computeIfPresent( */ @Deprecated @Override - public final V compute(K key, BiFunction remappingFunction) { + public final V compute( + K key, BiFunction remappingFunction) { throw new UnsupportedOperationException(); } @@ -612,7 +625,7 @@ public final V compute(K key, BiFunction rema @Deprecated @Override public final V merge( - K key, V value, BiFunction remappingFunction) { + K key, V value, BiFunction remappingFunction) { throw new UnsupportedOperationException(); } @@ -648,7 +661,7 @@ public final void replaceAll(BiFunction funct */ @Deprecated @Override - public final V remove(Object o) { + public final @Nullable V remove(@Nullable Object o) { throw new UnsupportedOperationException(); } @@ -660,7 +673,7 @@ public final V remove(Object o) { */ @Deprecated @Override - public final boolean remove(Object key, Object value) { + public final boolean remove(@Nullable Object key, @Nullable Object value) { throw new UnsupportedOperationException(); } @@ -693,7 +706,7 @@ public boolean containsValue(@Nullable Object value) { // Overriding to mark it Nullable @Override - public abstract V get(@Nullable Object key); + public abstract @Nullable V get(@Nullable Object key); /** * @since 21.0 (but only since 23.5 in the Android > entrySet; + @LazyInit @RetainedWith private transient @Nullable ImmutableSet> entrySet; /** * Returns an immutable set of the mappings in this map. The iteration order is specified by the @@ -720,7 +733,7 @@ public ImmutableSet> entrySet() { abstract ImmutableSet> createEntrySet(); - @LazyInit @RetainedWith private transient ImmutableSet keySet; + @LazyInit @RetainedWith private transient @Nullable ImmutableSet keySet; /** * Returns an immutable set of the keys in this map, in the same order that they appear in {@link @@ -758,7 +771,7 @@ Spliterator keySpliterator() { return CollectSpliterators.map(entrySet().spliterator(), Entry::getKey); } - @LazyInit @RetainedWith private transient ImmutableCollection values; + @LazyInit @RetainedWith private transient @Nullable ImmutableCollection values; /** * Returns an immutable collection of the values in this map, in the same order that they appear @@ -778,7 +791,7 @@ public ImmutableCollection values() { abstract ImmutableCollection createValues(); // cached so that this.multimapView().inverse() only computes inverse once - @LazyInit private transient ImmutableSetMultimap multimapView; + @LazyInit private transient @Nullable ImmutableSetMultimap multimapView; /** * Returns a multimap view of the map. @@ -816,7 +829,7 @@ public boolean containsKey(@Nullable Object key) { } @Override - public ImmutableSet get(@Nullable Object key) { + public @Nullable ImmutableSet get(@Nullable Object key) { V outerValue = ImmutableMap.this.get(key); return (outerValue == null) ? null : ImmutableSet.of(outerValue); } @@ -895,11 +908,15 @@ static class SerializedForm implements Serializable { private final Object[] keys; private final Object[] values; - SerializedForm(ImmutableMap map) { + /* + * "extends @NonNull Object" works around + * https://github.com/typetools/checker-framework/issues/3013 + */ + SerializedForm(ImmutableMap map) { keys = new Object[map.size()]; values = new Object[map.size()]; int i = 0; - for (Entry entry : map.entrySet()) { + for (Entry entry : map.entrySet()) { keys[i] = entry.getKey(); values[i] = entry.getValue(); i++; diff --git a/guava/src/com/google/common/collect/ImmutableMapEntry.java b/guava/src/com/google/common/collect/ImmutableMapEntry.java index d03d4fa0ea81..04681e309a56 100644 --- a/guava/src/com/google/common/collect/ImmutableMapEntry.java +++ b/guava/src/com/google/common/collect/ImmutableMapEntry.java @@ -19,6 +19,7 @@ import static com.google.common.collect.CollectPreconditions.checkEntryNotNull; import com.google.common.annotations.GwtIncompatible; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -33,13 +34,15 @@ * @author Louis Wasserman */ @GwtIncompatible // unnecessary -class ImmutableMapEntry extends ImmutableEntry { +class ImmutableMapEntry + extends ImmutableEntry { /** * Creates an {@code ImmutableMapEntry} array to hold parameterized entries. The result must never * be upcast back to ImmutableMapEntry[] (or Object[], etc.), or allowed to escape the class. */ @SuppressWarnings("unchecked") // Safe as long as the javadocs are followed - static ImmutableMapEntry[] createEntryArray(int size) { + static + ImmutableMapEntry[] createEntryArray(int size) { return new ImmutableMapEntry[size]; } @@ -71,10 +74,18 @@ boolean isReusable() { return true; } - static class NonTerminalImmutableMapEntry extends ImmutableMapEntry { - private final transient ImmutableMapEntry nextInKeyBucket; - - NonTerminalImmutableMapEntry(K key, V value, ImmutableMapEntry nextInKeyBucket) { + static class NonTerminalImmutableMapEntry + extends ImmutableMapEntry { + /* + * Yes, we sometimes set nextInKeyBucket to null, even for this "non-terminal" entry. We don't + * do that with a plain NonTerminalImmutableMapEntry, but we do do it with the BiMap-specific + * subclass below. That's because the Entry might be non-terminal in the key bucket but terminal + * in the value bucket (or vice versa). + */ + private final transient @Nullable ImmutableMapEntry nextInKeyBucket; + + NonTerminalImmutableMapEntry( + K key, V value, @Nullable ImmutableMapEntry nextInKeyBucket) { super(key, value); this.nextInKeyBucket = nextInKeyBucket; } @@ -90,15 +101,16 @@ final boolean isReusable() { } } - static final class NonTerminalImmutableBiMapEntry + static final class NonTerminalImmutableBiMapEntry< + K extends @NonNull Object, V extends @NonNull Object> extends NonTerminalImmutableMapEntry { - private final transient ImmutableMapEntry nextInValueBucket; + private final transient @Nullable ImmutableMapEntry nextInValueBucket; NonTerminalImmutableBiMapEntry( K key, V value, - ImmutableMapEntry nextInKeyBucket, - ImmutableMapEntry nextInValueBucket) { + @Nullable ImmutableMapEntry nextInKeyBucket, + @Nullable ImmutableMapEntry nextInValueBucket) { super(key, value, nextInKeyBucket); this.nextInValueBucket = nextInValueBucket; } diff --git a/guava/src/com/google/common/collect/ImmutableMapEntrySet.java b/guava/src/com/google/common/collect/ImmutableMapEntrySet.java index 830528364d9f..2101cbc9fd56 100644 --- a/guava/src/com/google/common/collect/ImmutableMapEntrySet.java +++ b/guava/src/com/google/common/collect/ImmutableMapEntrySet.java @@ -22,6 +22,7 @@ import java.util.Map.Entry; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -31,8 +32,10 @@ * @author Kevin Bourrillion */ @GwtCompatible(emulated = true) -abstract class ImmutableMapEntrySet extends ImmutableSet> { - static final class RegularEntrySet extends ImmutableMapEntrySet { +abstract class ImmutableMapEntrySet + extends ImmutableSet> { + static final class RegularEntrySet + extends ImmutableMapEntrySet { private final transient ImmutableMap map; private final transient ImmutableList> entries; @@ -89,7 +92,8 @@ public int size() { @Override public boolean contains(@Nullable Object object) { if (object instanceof Entry) { - Entry entry = (Entry) object; + Entry entry = + (Entry) object; V value = map().get(entry.getKey()); return value != null && value.equals(entry.getValue()); } @@ -119,7 +123,8 @@ Object writeReplace() { } @GwtIncompatible // serialization - private static class EntrySetSerializedForm implements Serializable { + private static class EntrySetSerializedForm + implements Serializable { final ImmutableMap map; EntrySetSerializedForm(ImmutableMap map) { diff --git a/guava/src/com/google/common/collect/ImmutableMapKeySet.java b/guava/src/com/google/common/collect/ImmutableMapKeySet.java index 56110a87e774..87d548bb6756 100644 --- a/guava/src/com/google/common/collect/ImmutableMapKeySet.java +++ b/guava/src/com/google/common/collect/ImmutableMapKeySet.java @@ -23,6 +23,7 @@ import java.io.Serializable; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -32,7 +33,8 @@ * @author Kevin Bourrillion */ @GwtCompatible(emulated = true) -final class ImmutableMapKeySet extends IndexedImmutableSet { +final class ImmutableMapKeySet + extends IndexedImmutableSet { private final ImmutableMap map; ImmutableMapKeySet(ImmutableMap map) { @@ -82,7 +84,7 @@ Object writeReplace() { } @GwtIncompatible // serialization - private static class KeySetSerializedForm implements Serializable { + private static class KeySetSerializedForm implements Serializable { final ImmutableMap map; KeySetSerializedForm(ImmutableMap map) { diff --git a/guava/src/com/google/common/collect/ImmutableMapValues.java b/guava/src/com/google/common/collect/ImmutableMapValues.java index 2c13c472c6bd..dfe2d6a34d4f 100644 --- a/guava/src/com/google/common/collect/ImmutableMapValues.java +++ b/guava/src/com/google/common/collect/ImmutableMapValues.java @@ -24,6 +24,7 @@ import java.util.Map.Entry; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -33,7 +34,8 @@ * @author Kevin Bourrillion */ @GwtCompatible(emulated = true) -final class ImmutableMapValues extends ImmutableCollection { +final class ImmutableMapValues + extends ImmutableCollection { private final ImmutableMap map; ImmutableMapValues(ImmutableMap map) { @@ -107,7 +109,7 @@ Object writeReplace() { } @GwtIncompatible // serialization - private static class SerializedForm implements Serializable { + private static class SerializedForm implements Serializable { final ImmutableMap map; SerializedForm(ImmutableMap map) { diff --git a/guava/src/com/google/common/collect/ImmutableMultimap.java b/guava/src/com/google/common/collect/ImmutableMultimap.java index cf785efe2c48..a3450feb23f4 100644 --- a/guava/src/com/google/common/collect/ImmutableMultimap.java +++ b/guava/src/com/google/common/collect/ImmutableMultimap.java @@ -18,12 +18,12 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkEntryNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import com.google.j2objc.annotations.Weak; import com.google.j2objc.annotations.WeakOuter; import java.io.Serializable; @@ -37,6 +37,7 @@ import java.util.Set; import java.util.Spliterator; import java.util.function.BiConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -66,21 +67,24 @@ * @since 2.0 */ @GwtCompatible(emulated = true) -public abstract class ImmutableMultimap extends BaseImmutableMultimap - implements Serializable { +public abstract class ImmutableMultimap + extends BaseImmutableMultimap implements Serializable { /** Returns an empty multimap. */ - public static ImmutableMultimap of() { + public static + ImmutableMultimap of() { return ImmutableListMultimap.of(); } /** Returns an immutable multimap containing a single entry. */ - public static ImmutableMultimap of(K k1, V v1) { + public static ImmutableMultimap of( + K k1, V v1) { return ImmutableListMultimap.of(k1, v1); } /** Returns an immutable multimap containing the given entries, in order. */ - public static ImmutableMultimap of(K k1, V v1, K k2, V v2) { + public static ImmutableMultimap of( + K k1, V v1, K k2, V v2) { return ImmutableListMultimap.of(k1, v1, k2, v2); } @@ -88,7 +92,8 @@ public static ImmutableMultimap of(K k1, V v1, K k2, V v2) { * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion * order described in the class documentation. */ - public static ImmutableMultimap of(K k1, V v1, K k2, V v2, K k3, V v3) { + public static ImmutableMultimap of( + K k1, V v1, K k2, V v2, K k3, V v3) { return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3); } @@ -96,7 +101,8 @@ public static ImmutableMultimap of(K k1, V v1, K k2, V v2, K k3, V * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion * order described in the class documentation. */ - public static ImmutableMultimap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static ImmutableMultimap of( + K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4); } @@ -104,7 +110,7 @@ public static ImmutableMultimap of(K k1, V v1, K k2, V v2, K k3, V * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion * order described in the class documentation. */ - public static ImmutableMultimap of( + public static ImmutableMultimap of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); } @@ -115,7 +121,7 @@ public static ImmutableMultimap of( * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder<>(); } @@ -138,8 +144,7 @@ public static Builder builder() { * * @since 2.0 */ - @DoNotMock - public static class Builder { + public static class Builder { Map> builderMap; @Nullable Comparator keyComparator; @Nullable Comparator valueComparator; @@ -303,7 +308,8 @@ public ImmutableMultimap build() { * * @throws NullPointerException if any key or value in {@code multimap} is null */ - public static ImmutableMultimap copyOf(Multimap multimap) { + public static + ImmutableMultimap copyOf(Multimap multimap) { if (multimap instanceof ImmutableMultimap) { @SuppressWarnings("unchecked") // safe since multimap is not writable ImmutableMultimap kvMultimap = (ImmutableMultimap) multimap; @@ -323,8 +329,8 @@ public static ImmutableMultimap copyOf(Multimap ImmutableMultimap copyOf( - Iterable> entries) { + public static + ImmutableMultimap copyOf(Iterable> entries) { return ImmutableListMultimap.copyOf(entries); } @@ -358,7 +364,7 @@ static class FieldSettersHolder { @CanIgnoreReturnValue @Deprecated @Override - public ImmutableCollection removeAll(Object key) { + public ImmutableCollection removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -451,7 +457,7 @@ public boolean putAll(Multimap multimap) { @CanIgnoreReturnValue @Deprecated @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { throw new UnsupportedOperationException(); } @@ -524,7 +530,8 @@ ImmutableCollection> createEntries() { return new EntryCollection<>(this); } - private static class EntryCollection extends ImmutableCollection> { + private static class EntryCollection + extends ImmutableCollection> { @Weak final ImmutableMultimap multimap; EntryCollection(ImmutableMultimap multimap) { @@ -547,9 +554,10 @@ public int size() { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { if (object instanceof Entry) { - Entry entry = (Entry) object; + Entry entry = + (Entry) object; return multimap.containsEntry(entry.getKey(), entry.getValue()); } return false; @@ -563,7 +571,7 @@ UnmodifiableIterator> entryIterator() { return new UnmodifiableIterator>() { final Iterator>> asMapItr = map.entrySet().iterator(); - K currentKey = null; + @Nullable K currentKey = null; Iterator valueItr = Iterators.emptyIterator(); @Override @@ -578,7 +586,8 @@ public Entry next() { currentKey = entry.getKey(); valueItr = entry.getValue().iterator(); } - return Maps.immutableEntry(currentKey, valueItr.next()); + // requireNonNull is safe because of the hasNext check. + return Maps.immutableEntry(requireNonNull(currentKey), valueItr.next()); } }; } @@ -710,7 +719,8 @@ public V next() { }; } - private static final class Values extends ImmutableCollection { + private static final class Values + extends ImmutableCollection { @Weak private final transient ImmutableMultimap multimap; Values(ImmutableMultimap multimap) { diff --git a/guava/src/com/google/common/collect/ImmutableMultiset.java b/guava/src/com/google/common/collect/ImmutableMultiset.java index 77d6cc5ede4e..9f4fcbb91d68 100644 --- a/guava/src/com/google/common/collect/ImmutableMultiset.java +++ b/guava/src/com/google/common/collect/ImmutableMultiset.java @@ -17,6 +17,7 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -33,6 +34,7 @@ import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -52,8 +54,8 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization -public abstract class ImmutableMultiset extends ImmutableMultisetGwtSerializationDependencies - implements Multiset { +public abstract class ImmutableMultiset + extends ImmutableMultisetGwtSerializationDependencies implements Multiset { /** * Returns a {@code Collector} that accumulates the input elements into a new {@code @@ -62,7 +64,8 @@ public abstract class ImmutableMultiset extends ImmutableMultisetGwtSerializa * * @since 21.0 */ - public static Collector> toImmutableMultiset() { + public static + Collector> toImmutableMultiset() { return toImmutableMultiset(Function.identity(), e -> 1); } @@ -77,8 +80,10 @@ public abstract class ImmutableMultiset extends ImmutableMultisetGwtSerializa * * @since 22.0 */ - public static Collector> toImmutableMultiset( - Function elementFunction, ToIntFunction countFunction) { + public static + Collector> toImmutableMultiset( + Function elementFunction, + ToIntFunction countFunction) { checkNotNull(elementFunction); checkNotNull(countFunction); return Collector.of( @@ -94,7 +99,7 @@ public abstract class ImmutableMultiset extends ImmutableMultisetGwtSerializa /** Returns the empty immutable multiset. */ @SuppressWarnings("unchecked") // all supported methods are covariant - public static ImmutableMultiset of() { + public static ImmutableMultiset of() { return (ImmutableMultiset) RegularImmutableMultiset.EMPTY; } @@ -105,7 +110,7 @@ public static ImmutableMultiset of() { * @since 6.0 (source-compatible since 2.0) */ @SuppressWarnings("unchecked") // generic array created but never written - public static ImmutableMultiset of(E element) { + public static ImmutableMultiset of(E element) { return copyFromElements(element); } @@ -116,7 +121,7 @@ public static ImmutableMultiset of(E element) { * @since 6.0 (source-compatible since 2.0) */ @SuppressWarnings("unchecked") // - public static ImmutableMultiset of(E e1, E e2) { + public static ImmutableMultiset of(E e1, E e2) { return copyFromElements(e1, e2); } @@ -128,7 +133,7 @@ public static ImmutableMultiset of(E e1, E e2) { * @since 6.0 (source-compatible since 2.0) */ @SuppressWarnings("unchecked") // - public static ImmutableMultiset of(E e1, E e2, E e3) { + public static ImmutableMultiset of(E e1, E e2, E e3) { return copyFromElements(e1, e2, e3); } @@ -140,7 +145,7 @@ public static ImmutableMultiset of(E e1, E e2, E e3) { * @since 6.0 (source-compatible since 2.0) */ @SuppressWarnings("unchecked") // - public static ImmutableMultiset of(E e1, E e2, E e3, E e4) { + public static ImmutableMultiset of(E e1, E e2, E e3, E e4) { return copyFromElements(e1, e2, e3, e4); } @@ -152,7 +157,7 @@ public static ImmutableMultiset of(E e1, E e2, E e3, E e4) { * @since 6.0 (source-compatible since 2.0) */ @SuppressWarnings("unchecked") // - public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5) { + public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5) { return copyFromElements(e1, e2, e3, e4, e5); } @@ -164,7 +169,8 @@ public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5) { * @since 6.0 (source-compatible since 2.0) */ @SuppressWarnings("unchecked") // - public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) { + public static ImmutableMultiset of( + E e1, E e2, E e3, E e4, E e5, E e6, E... others) { return new Builder().add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(others).build(); } @@ -175,7 +181,7 @@ public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5, E e6, E. * @throws NullPointerException if any of {@code elements} is null * @since 6.0 */ - public static ImmutableMultiset copyOf(E[] elements) { + public static ImmutableMultiset copyOf(E[] elements) { return copyFromElements(elements); } @@ -185,7 +191,8 @@ public static ImmutableMultiset copyOf(E[] elements) { * * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableMultiset copyOf(Iterable elements) { + public static ImmutableMultiset copyOf( + Iterable elements) { if (elements instanceof ImmutableMultiset) { @SuppressWarnings("unchecked") // all supported methods are covariant ImmutableMultiset result = (ImmutableMultiset) elements; @@ -208,19 +215,20 @@ public static ImmutableMultiset copyOf(Iterable elements) { * * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableMultiset copyOf(Iterator elements) { + public static ImmutableMultiset copyOf( + Iterator elements) { Multiset multiset = LinkedHashMultiset.create(); Iterators.addAll(multiset, elements); return copyFromEntries(multiset.entrySet()); } - private static ImmutableMultiset copyFromElements(E... elements) { + private static ImmutableMultiset copyFromElements(E... elements) { Multiset multiset = LinkedHashMultiset.create(); Collections.addAll(multiset, elements); return copyFromEntries(multiset.entrySet()); } - static ImmutableMultiset copyFromEntries( + static ImmutableMultiset copyFromEntries( Collection> entries) { if (entries.isEmpty()) { return of(); @@ -251,12 +259,16 @@ public E next() { remaining = entry.getCount(); } remaining--; - return element; + /* + * requireNonNull is safe because `element` is always populated with an E on the first + * successful call to next() and then kept or replaced with another E. + */ + return requireNonNull(element); } }; } - @LazyInit private transient ImmutableList asList; + @LazyInit private transient @Nullable ImmutableList asList; @Override public ImmutableList asList() { @@ -291,7 +303,7 @@ public final int add(E element, int occurrences) { @CanIgnoreReturnValue @Deprecated @Override - public final int remove(Object element, int occurrences) { + public final int remove(@Nullable Object element, int occurrences) { throw new UnsupportedOperationException(); } @@ -350,7 +362,7 @@ public String toString() { @Override public abstract ImmutableSet elementSet(); - @LazyInit private transient ImmutableSet> entrySet; + @LazyInit private transient @Nullable ImmutableSet> entrySet; @Override public ImmutableSet> entrySet() { @@ -382,7 +394,7 @@ public int size() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { if (o instanceof Entry) { Entry entry = (Entry) o; if (entry.getCount() <= 0) { @@ -409,7 +421,7 @@ Object writeReplace() { } @GwtIncompatible - static class EntrySetSerializedForm implements Serializable { + static class EntrySetSerializedForm implements Serializable { final ImmutableMultiset multiset; EntrySetSerializedForm(ImmutableMultiset multiset) { @@ -431,7 +443,7 @@ Object writeReplace() { * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder(); } @@ -454,7 +466,7 @@ public static Builder builder() { * * @since 2.0 */ - public static class Builder extends ImmutableCollection.Builder { + public static class Builder extends ImmutableCollection.Builder { final Multiset contents; /** @@ -581,7 +593,7 @@ ImmutableMultiset buildJdkBacked() { } } - static final class ElementSet extends ImmutableSet.Indexed { + static final class ElementSet extends ImmutableSet.Indexed { private final List> entries; // TODO(cpovirk): @Weak? private final Multiset delegate; @@ -616,12 +628,16 @@ static final class SerializedForm implements Serializable { final Object[] elements; final int[] counts; - SerializedForm(Multiset multiset) { + /* + * "extends @NonNull Object" works around + * https://github.com/typetools/checker-framework/issues/3013 + */ + SerializedForm(Multiset multiset) { int distinct = multiset.entrySet().size(); elements = new Object[distinct]; counts = new int[distinct]; int i = 0; - for (Entry entry : multiset.entrySet()) { + for (Entry entry : multiset.entrySet()) { elements[i] = entry.getElement(); counts[i] = entry.getCount(); i++; diff --git a/guava/src/com/google/common/collect/ImmutableMultisetGwtSerializationDependencies.java b/guava/src/com/google/common/collect/ImmutableMultisetGwtSerializationDependencies.java index a8b1899d280c..53df6baa4942 100644 --- a/guava/src/com/google/common/collect/ImmutableMultisetGwtSerializationDependencies.java +++ b/guava/src/com/google/common/collect/ImmutableMultisetGwtSerializationDependencies.java @@ -17,6 +17,7 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A dummy superclass to support GWT serialization of the element type of an {@link @@ -37,4 +38,5 @@ * and make types non-final. */ @GwtCompatible(emulated = true) -abstract class ImmutableMultisetGwtSerializationDependencies extends ImmutableCollection {} +abstract class ImmutableMultisetGwtSerializationDependencies + extends ImmutableCollection {} diff --git a/guava/src/com/google/common/collect/ImmutableRangeMap.java b/guava/src/com/google/common/collect/ImmutableRangeMap.java index f164701ae2e8..b76dc8107dfb 100644 --- a/guava/src/com/google/common/collect/ImmutableRangeMap.java +++ b/guava/src/com/google/common/collect/ImmutableRangeMap.java @@ -23,7 +23,6 @@ import com.google.common.collect.SortedLists.KeyAbsentBehavior; import com.google.common.collect.SortedLists.KeyPresentBehavior; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.io.Serializable; import java.util.Collections; import java.util.List; @@ -33,6 +32,7 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -44,7 +44,8 @@ */ @Beta @GwtIncompatible // NavigableMap -public class ImmutableRangeMap, V> implements RangeMap, Serializable { +public class ImmutableRangeMap, V extends @NonNull Object> + implements RangeMap, Serializable { private static final ImmutableRangeMap, Object> EMPTY = new ImmutableRangeMap<>(ImmutableList.>>of(), ImmutableList.of()); @@ -55,7 +56,8 @@ public class ImmutableRangeMap, V> implements RangeMap, V> + public static < + T, K extends Comparable, V extends @NonNull Object> Collector> toImmutableRangeMap( Function> keyFunction, Function valueFunction) { @@ -64,17 +66,18 @@ public class ImmutableRangeMap, V> implements RangeMap, V> ImmutableRangeMap of() { + public static , V extends @NonNull Object> ImmutableRangeMap of() { return (ImmutableRangeMap) EMPTY; } /** Returns an immutable range map mapping a single range to a single value. */ - public static , V> ImmutableRangeMap of(Range range, V value) { + public static , V extends @NonNull Object> ImmutableRangeMap of( + Range range, V value) { return new ImmutableRangeMap<>(ImmutableList.of(range), ImmutableList.of(value)); } @SuppressWarnings("unchecked") - public static , V> ImmutableRangeMap copyOf( + public static , V extends @NonNull Object> ImmutableRangeMap copyOf( RangeMap rangeMap) { if (rangeMap instanceof ImmutableRangeMap) { return (ImmutableRangeMap) rangeMap; @@ -90,7 +93,7 @@ public static , V> ImmutableRangeMap copyOf( } /** Returns a new builder for an immutable range map. */ - public static , V> Builder builder() { + public static , V extends @NonNull Object> Builder builder() { return new Builder<>(); } @@ -99,8 +102,7 @@ public static , V> Builder builder() { * * @since 14.0 */ - @DoNotMock - public static final class Builder, V> { + public static final class Builder, V extends @NonNull Object> { private final List, V>> entries; public Builder() { @@ -285,7 +287,7 @@ public void remove(Range range) { public void merge( Range range, @Nullable V value, - BiFunction remappingFunction) { + BiFunction remappingFunction) { throw new UnsupportedOperationException(); } @@ -393,7 +395,8 @@ public String toString() { * This class is used to serialize ImmutableRangeMap instances. Serializes the {@link * #asMapOfRanges()} form. */ - private static class SerializedForm, V> implements Serializable { + private static class SerializedForm, V extends @NonNull Object> + implements Serializable { private final ImmutableMap, V> mapOfRanges; diff --git a/guava/src/com/google/common/collect/ImmutableRangeSet.java b/guava/src/com/google/common/collect/ImmutableRangeSet.java index df063a89799a..5c8daacac3f9 100644 --- a/guava/src/com/google/common/collect/ImmutableRangeSet.java +++ b/guava/src/com/google/common/collect/ImmutableRangeSet.java @@ -20,6 +20,7 @@ import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_HIGHER; import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_LOWER; import static com.google.common.collect.SortedLists.KeyPresentBehavior.ANY_PRESENT; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -181,7 +182,7 @@ public boolean encloses(Range otherRange) { } @Override - public Range rangeContaining(C value) { + public @Nullable Range rangeContaining(C value) { int index = SortedLists.binarySearch( ranges, @@ -298,7 +299,7 @@ public ImmutableSet> asDescendingSetOfRanges() { return new RegularImmutableSortedSet<>(ranges.reverse(), Range.rangeLexOrdering().reverse()); } - @LazyInit private transient ImmutableRangeSet complement; + @LazyInit private transient @Nullable ImmutableRangeSet complement; private final class ComplementRanges extends ImmutableList> { // True if the "positive" range set is empty or bounded below. @@ -641,10 +642,10 @@ public boolean contains(@Nullable Object o) { } @Override - int indexOf(Object target) { + int indexOf(@Nullable Object target) { if (contains(target)) { @SuppressWarnings("unchecked") // if it's contained, it's definitely a C - C c = (C) target; + C c = (C) requireNonNull(target); long total = 0; for (Range range : ranges) { if (range.contains(c)) { diff --git a/guava/src/com/google/common/collect/ImmutableSet.java b/guava/src/com/google/common/collect/ImmutableSet.java index fe8a5f2c7b51..5866b918284f 100644 --- a/guava/src/com/google/common/collect/ImmutableSet.java +++ b/guava/src/com/google/common/collect/ImmutableSet.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -40,6 +41,7 @@ import java.util.Spliterator; import java.util.function.Consumer; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -50,7 +52,8 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization -public abstract class ImmutableSet extends ImmutableCollection implements Set { +public abstract class ImmutableSet extends ImmutableCollection + implements Set { static final int SPLITERATOR_CHARACTERISTICS = ImmutableCollection.SPLITERATOR_CHARACTERISTICS | Spliterator.DISTINCT; @@ -62,7 +65,7 @@ public abstract class ImmutableSet extends ImmutableCollection implements * * @since 21.0 */ - public static Collector> toImmutableSet() { + public static Collector> toImmutableSet() { return CollectCollectors.toImmutableSet(); } @@ -71,7 +74,7 @@ public abstract class ImmutableSet extends ImmutableCollection implements * consistency, and because the return type conveys the immutability guarantee. */ @SuppressWarnings({"unchecked"}) // fully variant implementation (never actually produces any Es) - public static ImmutableSet of() { + public static ImmutableSet of() { return (ImmutableSet) RegularImmutableSet.EMPTY; } @@ -80,7 +83,7 @@ public static ImmutableSet of() { * Collections#singleton} for code consistency, {@code null} rejection, and because the return * type conveys the immutability guarantee. */ - public static ImmutableSet of(E element) { + public static ImmutableSet of(E element) { return new SingletonImmutableSet(element); } @@ -89,7 +92,7 @@ public static ImmutableSet of(E element) { * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except * the first are ignored. */ - public static ImmutableSet of(E e1, E e2) { + public static ImmutableSet of(E e1, E e2) { return construct(2, 2, e1, e2); } @@ -98,7 +101,7 @@ public static ImmutableSet of(E e1, E e2) { * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except * the first are ignored. */ - public static ImmutableSet of(E e1, E e2, E e3) { + public static ImmutableSet of(E e1, E e2, E e3) { return construct(3, 3, e1, e2, e3); } @@ -107,7 +110,7 @@ public static ImmutableSet of(E e1, E e2, E e3) { * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except * the first are ignored. */ - public static ImmutableSet of(E e1, E e2, E e3, E e4) { + public static ImmutableSet of(E e1, E e2, E e3, E e4) { return construct(4, 4, e1, e2, e3, e4); } @@ -116,7 +119,7 @@ public static ImmutableSet of(E e1, E e2, E e3, E e4) { * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except * the first are ignored. */ - public static ImmutableSet of(E e1, E e2, E e3, E e4, E e5) { + public static ImmutableSet of(E e1, E e2, E e3, E e4, E e5) { return construct(5, 5, e1, e2, e3, e4, e5); } @@ -130,7 +133,8 @@ public static ImmutableSet of(E e1, E e2, E e3, E e4, E e5) { * @since 3.0 (source-compatible since 2.0) */ @SafeVarargs // For Eclipse. For internal javac we have disabled this pointless type of warning. - public static ImmutableSet of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) { + public static ImmutableSet of( + E e1, E e2, E e3, E e4, E e5, E e6, E... others) { checkArgument( others.length <= Integer.MAX_VALUE - 6, "the total number of elements must fit in an int"); final int paramCount = 6; @@ -160,7 +164,8 @@ public static ImmutableSet of(E e1, E e2, E e3, E e4, E e5, E e6, E... ot * * @throws NullPointerException if any of the first {@code n} elements of {@code elements} is null */ - private static ImmutableSet constructUnknownDuplication(int n, Object... elements) { + private static ImmutableSet constructUnknownDuplication( + int n, Object... elements) { // Guess the size is "halfway between" all duplicates and no duplicates, on a log scale. return construct( n, @@ -184,7 +189,8 @@ private static ImmutableSet constructUnknownDuplication(int n, Object... * * @throws NullPointerException if any of the first {@code n} elements of {@code elements} is null */ - private static ImmutableSet construct(int n, int expectedSize, Object... elements) { + private static ImmutableSet construct( + int n, int expectedSize, Object... elements) { switch (n) { case 0: return of(); @@ -215,7 +221,9 @@ private static ImmutableSet construct(int n, int expectedSize, Object... * @throws NullPointerException if any of {@code elements} is null * @since 7.0 (source-compatible since 2.0) */ - public static ImmutableSet copyOf(Collection elements) { + @SuppressWarnings("assignment.type.incompatible") // arrays + public static ImmutableSet copyOf( + Collection elements) { /* * TODO(lowasser): consider checking for ImmutableAsList here * TODO(lowasser): consider checking for Multiset here @@ -251,7 +259,7 @@ public static ImmutableSet copyOf(Collection elements) { * * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableSet copyOf(Iterable elements) { + public static ImmutableSet copyOf(Iterable elements) { return (elements instanceof Collection) ? copyOf((Collection) elements) : copyOf(elements.iterator()); @@ -263,7 +271,7 @@ public static ImmutableSet copyOf(Iterable elements) { * * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableSet copyOf(Iterator elements) { + public static ImmutableSet copyOf(Iterator elements) { // We special-case for 0 or 1 elements, but anything further is madness. if (!elements.hasNext()) { return of(); @@ -283,7 +291,7 @@ public static ImmutableSet copyOf(Iterator elements) { * @throws NullPointerException if any of {@code elements} is null * @since 3.0 */ - public static ImmutableSet copyOf(E[] elements) { + public static ImmutableSet copyOf(E[] elements) { switch (elements.length) { case 0: return of(); @@ -341,7 +349,7 @@ ImmutableList createAsList() { return new RegularImmutableAsList(this, toArray()); } - abstract static class Indexed extends ImmutableSet { + abstract static class Indexed extends ImmutableSet { abstract E get(int index); @Override @@ -414,7 +422,7 @@ Object writeReplace() { * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ - public static Builder builder() { + public static Builder builder() { return new Builder(); } @@ -431,17 +439,18 @@ public static Builder builder() { * @since 23.1 */ @Beta - public static Builder builderWithExpectedSize(int expectedSize) { + public static Builder builderWithExpectedSize(int expectedSize) { checkNonnegative(expectedSize, "expectedSize"); return new Builder(expectedSize); } /** Builds a new open-addressed hash table from the first n objects in elements. */ - static Object[] rebuildHashTable(int newTableSize, Object[] elements, int n) { - Object[] hashTable = new Object[newTableSize]; + static @Nullable Object[] rebuildHashTable(int newTableSize, @Nullable Object[] elements, int n) { + @Nullable Object[] hashTable = new @Nullable Object[newTableSize]; int mask = hashTable.length - 1; for (int i = 0; i < n; i++) { - Object e = elements[i]; + // requireNonNull is safe because we ensure that the first n elements have been populated. + Object e = requireNonNull(elements[i]); int j0 = Hashing.smear(e.hashCode()); for (int j = j0; ; j++) { int index = j & mask; @@ -472,7 +481,7 @@ static Object[] rebuildHashTable(int newTableSize, Object[] elements, int n) { * * @since 2.0 */ - public static class Builder extends ImmutableCollection.Builder { + public static class Builder extends ImmutableCollection.Builder { private SetBuilderImpl impl; boolean forceCopy; @@ -484,6 +493,7 @@ public Builder() { impl = new RegularSetBuilderImpl(capacity); } + @SuppressWarnings("nullness") // Weird case forced by our inheritance hierarchy. Builder(@SuppressWarnings("unused") boolean subclass) { this.impl = null; // unused } @@ -557,7 +567,7 @@ public ImmutableSet build() { } /** Swappable internal implementation of an ImmutableSet.Builder. */ - private abstract static class SetBuilderImpl { + private abstract static class SetBuilderImpl { E[] dedupedElements; int distinct; @@ -568,6 +578,7 @@ private abstract static class SetBuilderImpl { } /** Initializes this SetBuilderImpl with a copy of the deduped elements array from toCopy. */ + @SuppressWarnings("assignment.type.incompatible") // arrays SetBuilderImpl(SetBuilderImpl toCopy) { this.dedupedElements = Arrays.copyOf(toCopy.dedupedElements, toCopy.dedupedElements.length); this.distinct = toCopy.distinct; @@ -577,6 +588,7 @@ private abstract static class SetBuilderImpl { * Resizes internal data structures if necessary to store the specified number of distinct * elements. */ + @SuppressWarnings("assignment.type.incompatible") // arrays private void ensureCapacity(int minCapacity) { if (minCapacity > dedupedElements.length) { int newCapacity = @@ -693,7 +705,7 @@ static int chooseTableSize(int setSize) { * definitely returns false. In between those constraints, the result of this method is undefined, * subject to the above {@link #HASH_FLOODING_FPP} constraint. */ - static boolean hashFloodingDetected(Object[] hashTable) { + static boolean hashFloodingDetected(@Nullable Object[] hashTable) { int maxRunBeforeFallback = maxRunBeforeFallback(hashTable.length); // Test for a run wrapping around the end of the table of length at least maxRunBeforeFallback. @@ -749,8 +761,9 @@ private static int maxRunBeforeFallback(int tableSize) { *

    This implementation attempts to detect hash flooding, and if it's identified, falls back to * JdkBackedSetBuilderImpl. */ - private static final class RegularSetBuilderImpl extends SetBuilderImpl { - private Object[] hashTable; + private static final class RegularSetBuilderImpl + extends SetBuilderImpl { + private @Nullable Object[] hashTable; private int maxRunBeforeFallback; private int expandTableThreshold; private int hashCode; @@ -820,6 +833,7 @@ SetBuilderImpl review() { } @Override + @SuppressWarnings("assignment.type.incompatible") // arrays ImmutableSet build() { switch (distinct) { case 0: @@ -839,7 +853,8 @@ ImmutableSet build() { /** * SetBuilderImpl version that uses a JDK HashSet, which has built in hash flooding protection. */ - private static final class JdkBackedSetBuilderImpl extends SetBuilderImpl { + private static final class JdkBackedSetBuilderImpl + extends SetBuilderImpl { private final Set delegate; JdkBackedSetBuilderImpl(SetBuilderImpl toCopy) { diff --git a/guava/src/com/google/common/collect/ImmutableSetMultimap.java b/guava/src/com/google/common/collect/ImmutableSetMultimap.java index 9691ef5570f5..ab7a9220aa1d 100644 --- a/guava/src/com/google/common/collect/ImmutableSetMultimap.java +++ b/guava/src/com/google/common/collect/ImmutableSetMultimap.java @@ -40,6 +40,7 @@ import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -53,8 +54,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public class ImmutableSetMultimap extends ImmutableMultimap - implements SetMultimap { +public class ImmutableSetMultimap + extends ImmutableMultimap implements SetMultimap { /** * Returns a {@link Collector} that accumulates elements into an {@code ImmutableSetMultimap} * whose keys and values are the result of applying the provided mapping functions to the input @@ -83,9 +84,10 @@ public class ImmutableSetMultimap extends ImmutableMultimap * * @since 21.0 */ - public static Collector> toImmutableSetMultimap( - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableSetMultimap( + Function keyFunction, + Function valueFunction) { checkNotNull(keyFunction, "keyFunction"); checkNotNull(valueFunction, "valueFunction"); return Collector.of( @@ -135,7 +137,7 @@ public class ImmutableSetMultimap extends ImmutableMultimap * * @since 21.0 */ - public static + public static Collector> flatteningToImmutableSetMultimap( Function keyFunction, Function> valuesFunction) { @@ -152,12 +154,14 @@ public class ImmutableSetMultimap extends ImmutableMultimap /** Returns the empty multimap. */ // Casting is safe because the multimap will never hold any elements. @SuppressWarnings("unchecked") - public static ImmutableSetMultimap of() { + public static + ImmutableSetMultimap of() { return (ImmutableSetMultimap) EmptyImmutableSetMultimap.INSTANCE; } /** Returns an immutable multimap containing a single entry. */ - public static ImmutableSetMultimap of(K k1, V v1) { + public static + ImmutableSetMultimap of(K k1, V v1) { ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); builder.put(k1, v1); return builder.build(); @@ -167,7 +171,8 @@ public static ImmutableSetMultimap of(K k1, V v1) { * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of * an entry (according to {@link Object#equals}) after the first are ignored. */ - public static ImmutableSetMultimap of(K k1, V v1, K k2, V v2) { + public static + ImmutableSetMultimap of(K k1, V v1, K k2, V v2) { ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -178,7 +183,8 @@ public static ImmutableSetMultimap of(K k1, V v1, K k2, V v2) { * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of * an entry (according to {@link Object#equals}) after the first are ignored. */ - public static ImmutableSetMultimap of(K k1, V v1, K k2, V v2, K k3, V v3) { + public static + ImmutableSetMultimap of(K k1, V v1, K k2, V v2, K k3, V v3) { ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -190,8 +196,8 @@ public static ImmutableSetMultimap of(K k1, V v1, K k2, V v2, K k3, * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of * an entry (according to {@link Object#equals}) after the first are ignored. */ - public static ImmutableSetMultimap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static + ImmutableSetMultimap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -204,8 +210,8 @@ public static ImmutableSetMultimap of( * Returns an immutable multimap containing the given entries, in order. Repeated occurrences of * an entry (according to {@link Object#equals}) after the first are ignored. */ - public static ImmutableSetMultimap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { + public static + ImmutableSetMultimap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); builder.put(k1, v1); builder.put(k2, v2); @@ -218,7 +224,7 @@ public static ImmutableSetMultimap of( // looking for of() with > 5 entries? Use the builder instead. /** Returns a new {@link Builder}. */ - public static Builder builder() { + public static Builder builder() { return new Builder<>(); } @@ -241,7 +247,8 @@ public static Builder builder() { * * @since 2.0 */ - public static final class Builder extends ImmutableMultimap.Builder { + public static final class Builder + extends ImmutableMultimap.Builder { /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link * ImmutableSetMultimap#builder}. @@ -371,13 +378,15 @@ public ImmutableSetMultimap build() { * * @throws NullPointerException if any key or value in {@code multimap} is null */ - public static ImmutableSetMultimap copyOf( - Multimap multimap) { + public static + ImmutableSetMultimap copyOf(Multimap multimap) { return copyOf(multimap, null); } - private static ImmutableSetMultimap copyOf( - Multimap multimap, Comparator valueComparator) { + private static + ImmutableSetMultimap copyOf( + Multimap multimap, + @Nullable Comparator valueComparator) { checkNotNull(multimap); // eager for GWT if (multimap.isEmpty() && valueComparator == null) { return of(); @@ -404,15 +413,18 @@ private static ImmutableSetMultimap copyOf( * @since 19.0 */ @Beta - public static ImmutableSetMultimap copyOf( - Iterable> entries) { + public static + ImmutableSetMultimap copyOf( + Iterable> entries) { return new Builder().putAll(entries).build(); } /** Creates an ImmutableSetMultimap from an asMap.entrySet. */ - static ImmutableSetMultimap fromMapEntries( - Collection>> mapEntries, - @Nullable Comparator valueComparator) { + static + ImmutableSetMultimap fromMapEntries( + Collection>> + mapEntries, + @Nullable Comparator valueComparator) { if (mapEntries.isEmpty()) { return of(); } @@ -455,7 +467,7 @@ static ImmutableSetMultimap fromMapEntries( * parameters used to build this multimap. */ @Override - public ImmutableSet get(@Nullable K key) { + public ImmutableSet get(K key) { // This cast is safe as its type is known in constructor. ImmutableSet set = (ImmutableSet) map.get(key); return MoreObjects.firstNonNull(set, emptySet); @@ -495,7 +507,7 @@ private ImmutableSetMultimap invert() { @CanIgnoreReturnValue @Deprecated @Override - public ImmutableSet removeAll(Object key) { + public ImmutableSet removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -524,7 +536,8 @@ public ImmutableSet> entries() { return result == null ? (entries = new EntrySet<>(this)) : result; } - private static final class EntrySet extends ImmutableSet> { + private static final class EntrySet + extends ImmutableSet> { @Weak private final transient ImmutableSetMultimap multimap; EntrySet(ImmutableSetMultimap multimap) { @@ -534,7 +547,8 @@ private static final class EntrySet extends ImmutableSet> { @Override public boolean contains(@Nullable Object object) { if (object instanceof Entry) { - Entry entry = (Entry) object; + Entry entry = + (Entry) object; return multimap.containsEntry(entry.getKey(), entry.getValue()); } return false; @@ -556,20 +570,21 @@ boolean isPartialView() { } } - private static ImmutableSet valueSet( + private static ImmutableSet valueSet( @Nullable Comparator valueComparator, Collection values) { return (valueComparator == null) ? ImmutableSet.copyOf(values) : ImmutableSortedSet.copyOf(valueComparator, values); } - private static ImmutableSet emptySet(@Nullable Comparator valueComparator) { + private static ImmutableSet emptySet( + @Nullable Comparator valueComparator) { return (valueComparator == null) ? ImmutableSet.of() : ImmutableSortedSet.emptySet(valueComparator); } - private static ImmutableSet.Builder valuesBuilder( + private static ImmutableSet.Builder valuesBuilder( @Nullable Comparator valueComparator) { return (valueComparator == null) ? new ImmutableSet.Builder() diff --git a/guava/src/com/google/common/collect/ImmutableSortedAsList.java b/guava/src/com/google/common/collect/ImmutableSortedAsList.java index 91f700ece687..859ce5f71801 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedAsList.java +++ b/guava/src/com/google/common/collect/ImmutableSortedAsList.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtIncompatible; import java.util.Comparator; import java.util.Spliterator; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -28,7 +29,7 @@ */ @GwtCompatible(emulated = true) @SuppressWarnings("serial") -final class ImmutableSortedAsList extends RegularImmutableAsList +final class ImmutableSortedAsList extends RegularImmutableAsList implements SortedIterable { ImmutableSortedAsList(ImmutableSortedSet backingSet, ImmutableList backingList) { super(backingSet, backingList); @@ -67,7 +68,7 @@ public int lastIndexOf(@Nullable Object target) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Necessary for ISS's with comparators inconsistent with equals. return indexOf(target) >= 0; } diff --git a/guava/src/com/google/common/collect/ImmutableSortedMap.java b/guava/src/com/google/common/collect/ImmutableSortedMap.java index ae44fcb38d18..d34a1a16ef97 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedMap.java +++ b/guava/src/com/google/common/collect/ImmutableSortedMap.java @@ -38,6 +38,7 @@ import java.util.function.Function; import java.util.stream.Collector; import java.util.stream.Collectors; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -58,8 +59,8 @@ * @since 2.0 (implements {@code NavigableMap} since 12.0) */ @GwtCompatible(serializable = true, emulated = true) -public final class ImmutableSortedMap extends ImmutableSortedMapFauxverideShim - implements NavigableMap { +public final class ImmutableSortedMap + extends ImmutableSortedMapFauxverideShim implements NavigableMap { /** * Returns a {@link Collector} that accumulates elements into an {@code ImmutableSortedMap} whose * keys and values are the result of applying the provided mapping functions to the input @@ -72,10 +73,11 @@ public final class ImmutableSortedMap extends ImmutableSortedMapFauxveride * * @since 21.0 */ - public static Collector> toImmutableSortedMap( - Comparator comparator, - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableSortedMap( + Comparator comparator, + Function keyFunction, + Function valueFunction) { return CollectCollectors.toImmutableSortedMap(comparator, keyFunction, valueFunction); } @@ -90,11 +92,12 @@ public final class ImmutableSortedMap extends ImmutableSortedMapFauxveride * * @since 21.0 */ - public static Collector> toImmutableSortedMap( - Comparator comparator, - Function keyFunction, - Function valueFunction, - BinaryOperator mergeFunction) { + public static + Collector> toImmutableSortedMap( + Comparator comparator, + Function keyFunction, + Function valueFunction, + BinaryOperator mergeFunction) { checkNotNull(comparator); checkNotNull(keyFunction); checkNotNull(valueFunction); @@ -115,7 +118,8 @@ public final class ImmutableSortedMap extends ImmutableSortedMapFauxveride new ImmutableSortedMap<>( ImmutableSortedSet.emptySet(Ordering.natural()), ImmutableList.of()); - static ImmutableSortedMap emptyMap(Comparator comparator) { + static ImmutableSortedMap emptyMap( + Comparator comparator) { if (Ordering.natural().equals(comparator)) { return of(); } else { @@ -128,17 +132,20 @@ static ImmutableSortedMap emptyMap(Comparator comparator @SuppressWarnings("unchecked") // unsafe, comparator() returns a comparator on the specified type // TODO(kevinb): evaluate whether or not of().comparator() should return null - public static ImmutableSortedMap of() { + public static + ImmutableSortedMap of() { return (ImmutableSortedMap) NATURAL_EMPTY_MAP; } /** Returns an immutable map containing a single entry. */ - public static , V> ImmutableSortedMap of(K k1, V v1) { + public static , V extends @NonNull Object> + ImmutableSortedMap of(K k1, V v1) { return of(Ordering.natural(), k1, v1); } /** Returns an immutable map containing a single entry. */ - private static ImmutableSortedMap of(Comparator comparator, K k1, V v1) { + private static ImmutableSortedMap of( + Comparator comparator, K k1, V v1) { return new ImmutableSortedMap<>( new RegularImmutableSortedSet(ImmutableList.of(k1), checkNotNull(comparator)), ImmutableList.of(v1)); @@ -151,8 +158,8 @@ private static ImmutableSortedMap of(Comparator comparat * @throws IllegalArgumentException if the two keys are equal according to their natural ordering */ @SuppressWarnings("unchecked") - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2) { + public static , V extends @NonNull Object> + ImmutableSortedMap of(K k1, V v1, K k2, V v2) { return ofEntries(entryOf(k1, v1), entryOf(k2, v2)); } @@ -163,8 +170,8 @@ public static , V> ImmutableSortedMap of( * @throws IllegalArgumentException if any two keys are equal according to their natural ordering */ @SuppressWarnings("unchecked") - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2, K k3, V v3) { + public static , V extends @NonNull Object> + ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V v3) { return ofEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3)); } @@ -175,8 +182,8 @@ public static , V> ImmutableSortedMap of( * @throws IllegalArgumentException if any two keys are equal according to their natural ordering */ @SuppressWarnings("unchecked") - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static , V extends @NonNull Object> + ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { return ofEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); } @@ -187,14 +194,14 @@ public static , V> ImmutableSortedMap of( * @throws IllegalArgumentException if any two keys are equal according to their natural ordering */ @SuppressWarnings("unchecked") - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { + public static , V extends @NonNull Object> + ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { return ofEntries( entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5)); } - private static , V> ImmutableSortedMap ofEntries( - Entry... entries) { + private static , V extends @NonNull Object> + ImmutableSortedMap ofEntries(Entry... entries) { return fromEntries(Ordering.natural(), false, entries, entries.length); } @@ -213,7 +220,8 @@ private static , V> ImmutableSortedMap ofE * @throws NullPointerException if any key or value in {@code map} is null * @throws IllegalArgumentException if any two keys are equal according to their natural ordering */ - public static ImmutableSortedMap copyOf(Map map) { + public static + ImmutableSortedMap copyOf(Map map) { // Hack around K not being a subtype of Comparable. // Unsafe, see ImmutableSortedSetFauxverideShim. @SuppressWarnings("unchecked") @@ -232,8 +240,9 @@ public static ImmutableSortedMap copyOf(Map ImmutableSortedMap copyOf( - Map map, Comparator comparator) { + public static + ImmutableSortedMap copyOf( + Map map, Comparator comparator) { return copyOfInternal(map, checkNotNull(comparator)); } @@ -249,8 +258,8 @@ public static ImmutableSortedMap copyOf( * @since 19.0 */ @Beta - public static ImmutableSortedMap copyOf( - Iterable> entries) { + public static + ImmutableSortedMap copyOf(Iterable> entries) { // Hack around K not being a subtype of Comparable. // Unsafe, see ImmutableSortedSetFauxverideShim. @SuppressWarnings("unchecked") @@ -267,9 +276,10 @@ public static ImmutableSortedMap copyOf( * @since 19.0 */ @Beta - public static ImmutableSortedMap copyOf( - Iterable> entries, - Comparator comparator) { + public static + ImmutableSortedMap copyOf( + Iterable> entries, + Comparator comparator) { return fromEntries(checkNotNull(comparator), false, entries); } @@ -284,7 +294,8 @@ public static ImmutableSortedMap copyOf( * @throws NullPointerException if any key or value in {@code map} is null */ @SuppressWarnings("unchecked") - public static ImmutableSortedMap copyOfSorted(SortedMap map) { + public static + ImmutableSortedMap copyOfSorted(SortedMap map) { Comparator comparator = map.comparator(); if (comparator == null) { // If map has a null comparator, the keys should have a natural ordering, @@ -303,11 +314,13 @@ public static ImmutableSortedMap copyOfSorted(SortedMap ImmutableSortedMap copyOfInternal( - Map map, Comparator comparator) { + private static + ImmutableSortedMap copyOfInternal( + Map map, Comparator comparator) { boolean sameComparator = false; if (map instanceof SortedMap) { - SortedMap sortedMap = (SortedMap) map; + SortedMap sortedMap = + (SortedMap) map; Comparator comparator2 = sortedMap.comparator(); sameComparator = (comparator2 == null) ? comparator == NATURAL_ORDER : comparator.equals(comparator2); @@ -329,10 +342,11 @@ private static ImmutableSortedMap copyOfInternal( * Accepts a collection of possibly-null entries. If {@code sameComparator}, then it is assumed * that they do not need to be sorted or checked for dupes. */ - private static ImmutableSortedMap fromEntries( - Comparator comparator, - boolean sameComparator, - Iterable> entries) { + private static + ImmutableSortedMap fromEntries( + Comparator comparator, + boolean sameComparator, + Iterable> entries) { // "adding" type params to an array of a raw type should be safe as // long as no one can ever cast that same array instance back to a // raw type. @@ -341,11 +355,12 @@ private static ImmutableSortedMap fromEntries( return fromEntries(comparator, sameComparator, entryArray, entryArray.length); } - private static ImmutableSortedMap fromEntries( - final Comparator comparator, - boolean sameComparator, - Entry[] entryArray, - int size) { + private static + ImmutableSortedMap fromEntries( + final Comparator comparator, + boolean sameComparator, + Entry[] entryArray, + int size) { switch (size) { case 0: return emptyMap(comparator); @@ -403,7 +418,7 @@ public int compare(Entry e1, Entry e2) { * Returns a builder that creates immutable sorted maps whose keys are ordered by their natural * ordering. The sorted maps use {@link Ordering#natural()} as the comparator. */ - public static , V> Builder naturalOrder() { + public static , V extends @NonNull Object> Builder naturalOrder() { return new Builder<>(Ordering.natural()); } @@ -415,7 +430,8 @@ public static , V> Builder naturalOrder() { * * @throws NullPointerException if {@code comparator} is null */ - public static Builder orderedBy(Comparator comparator) { + public static Builder orderedBy( + Comparator comparator) { return new Builder<>(comparator); } @@ -423,7 +439,7 @@ public static Builder orderedBy(Comparator comparator) { * Returns a builder that creates immutable sorted maps whose keys are ordered by the reverse of * their natural ordering. */ - public static , V> Builder reverseOrder() { + public static , V extends @NonNull Object> Builder reverseOrder() { return new Builder<>(Ordering.natural().reverse()); } @@ -448,7 +464,8 @@ public static , V> Builder reverseOrder() { * * @since 2.0 */ - public static class Builder extends ImmutableMap.Builder { + public static class Builder + extends ImmutableMap.Builder { private final Comparator comparator; /** @@ -557,7 +574,7 @@ public ImmutableSortedMap build() { private final transient RegularImmutableSortedSet keySet; private final transient ImmutableList valueList; - private transient ImmutableSortedMap descendingMap; + private transient @Nullable ImmutableSortedMap descendingMap; ImmutableSortedMap(RegularImmutableSortedSet keySet, ImmutableList valueList) { this(keySet, valueList, null); @@ -566,7 +583,7 @@ public ImmutableSortedMap build() { ImmutableSortedMap( RegularImmutableSortedSet keySet, ImmutableList valueList, - ImmutableSortedMap descendingMap) { + @Nullable ImmutableSortedMap descendingMap) { this.keySet = keySet; this.valueList = valueList; this.descendingMap = descendingMap; @@ -587,7 +604,7 @@ public void forEach(BiConsumer action) { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { int index = keySet.indexOf(key); return (index == -1) ? null : valueList.get(index); } @@ -809,52 +826,52 @@ public ImmutableSortedMap tailMap(K fromKey, boolean inclusive) { } @Override - public Entry lowerEntry(K key) { + public @Nullable Entry lowerEntry(K key) { return headMap(key, false).lastEntry(); } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return keyOrNull(lowerEntry(key)); } @Override - public Entry floorEntry(K key) { + public @Nullable Entry floorEntry(K key) { return headMap(key, true).lastEntry(); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return keyOrNull(floorEntry(key)); } @Override - public Entry ceilingEntry(K key) { + public @Nullable Entry ceilingEntry(K key) { return tailMap(key, true).firstEntry(); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return keyOrNull(ceilingEntry(key)); } @Override - public Entry higherEntry(K key) { + public @Nullable Entry higherEntry(K key) { return tailMap(key, false).firstEntry(); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return keyOrNull(higherEntry(key)); } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return isEmpty() ? null : entrySet().asList().get(0); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return isEmpty() ? null : entrySet().asList().get(size() - 1); } @@ -867,7 +884,7 @@ public Entry lastEntry() { @CanIgnoreReturnValue @Deprecated @Override - public final Entry pollFirstEntry() { + public final @Nullable Entry pollFirstEntry() { throw new UnsupportedOperationException(); } @@ -880,7 +897,7 @@ public final Entry pollFirstEntry() { @CanIgnoreReturnValue @Deprecated @Override - public final Entry pollLastEntry() { + public final @Nullable Entry pollLastEntry() { throw new UnsupportedOperationException(); } @@ -919,8 +936,13 @@ public ImmutableSortedSet descendingKeySet() { private static class SerializedForm extends ImmutableMap.SerializedForm { private final Comparator comparator; + /* + * "extends @NonNull Object" works around + * https://github.com/typetools/checker-framework/issues/3013 + */ @SuppressWarnings("unchecked") - SerializedForm(ImmutableSortedMap sortedMap) { + SerializedForm( + ImmutableSortedMap sortedMap) { super(sortedMap); comparator = (Comparator) sortedMap.comparator(); } diff --git a/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java index 87b83519e1ce..1a5ecd30fcaf 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java +++ b/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java @@ -20,6 +20,8 @@ import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * "Overrides" the {@link ImmutableMap} static methods that lack {@link ImmutableSortedMap} @@ -29,7 +31,9 @@ * @author Chris Povirk */ @GwtIncompatible -abstract class ImmutableSortedMapFauxverideShim extends ImmutableMap { +abstract class ImmutableSortedMapFauxverideShim< + K extends @NonNull Object, V extends @NonNull Object> + extends ImmutableMap { /** * Not supported. Use {@link ImmutableSortedMap#toImmutableSortedMap}, which offers better * type-safety, instead. This method exists only to hide {@link ImmutableMap#toImmutableMap} from @@ -39,9 +43,10 @@ abstract class ImmutableSortedMapFauxverideShim extends ImmutableMap * @deprecated Use {@link ImmutableSortedMap#toImmutableSortedMap}. */ @Deprecated - public static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction) { + public static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction) { throw new UnsupportedOperationException(); } @@ -54,10 +59,11 @@ abstract class ImmutableSortedMapFauxverideShim extends ImmutableMap * @deprecated Use {@link ImmutableSortedMap#toImmutableSortedMap}. */ @Deprecated - public static Collector> toImmutableMap( - Function keyFunction, - Function valueFunction, - BinaryOperator mergeFunction) { + public static + Collector> toImmutableMap( + Function keyFunction, + Function valueFunction, + BinaryOperator mergeFunction) { throw new UnsupportedOperationException(); } @@ -70,7 +76,8 @@ abstract class ImmutableSortedMapFauxverideShim extends ImmutableMap * @deprecated Use {@link ImmutableSortedMap#naturalOrder}, which offers better type-safety. */ @Deprecated - public static ImmutableSortedMap.Builder builder() { + public static + ImmutableSortedMap.Builder builder() { throw new UnsupportedOperationException(); } @@ -81,7 +88,8 @@ public static ImmutableSortedMap.Builder builder() { * @deprecated Not supported for ImmutableSortedMap. */ @Deprecated - public static ImmutableSortedMap.Builder builderWithExpectedSize(int expectedSize) { + public static + ImmutableSortedMap.Builder builderWithExpectedSize(int expectedSize) { throw new UnsupportedOperationException(); } @@ -95,7 +103,8 @@ public static ImmutableSortedMap.Builder builderWithExpectedSize(in * ImmutableSortedMap#of(Comparable, Object)}. */ @Deprecated - public static ImmutableSortedMap of(K k1, V v1) { + public static ImmutableSortedMap of( + K k1, V v1) { throw new UnsupportedOperationException(); } @@ -109,7 +118,8 @@ public static ImmutableSortedMap of(K k1, V v1) { * ImmutableSortedMap#of(Comparable, Object, Comparable, Object)}. */ @Deprecated - public static ImmutableSortedMap of(K k1, V v1, K k2, V v2) { + public static ImmutableSortedMap of( + K k1, V v1, K k2, V v2) { throw new UnsupportedOperationException(); } @@ -123,7 +133,8 @@ public static ImmutableSortedMap of(K k1, V v1, K k2, V v2) { * ImmutableSortedMap#of(Comparable, Object, Comparable, Object, Comparable, Object)}. */ @Deprecated - public static ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V v3) { + public static ImmutableSortedMap of( + K k1, V v1, K k2, V v2, K k3, V v3) { throw new UnsupportedOperationException(); } @@ -138,7 +149,8 @@ public static ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V * Comparable, Object)}. */ @Deprecated - public static ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { + public static ImmutableSortedMap of( + K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { throw new UnsupportedOperationException(); } @@ -153,7 +165,7 @@ public static ImmutableSortedMap of(K k1, V v1, K k2, V v2, K k3, V * Comparable, Object, Comparable, Object)}. */ @Deprecated - public static ImmutableSortedMap of( + public static ImmutableSortedMap of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/collect/ImmutableSortedMultiset.java b/guava/src/com/google/common/collect/ImmutableSortedMultiset.java index ec0206314f57..b4c2b56447f3 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedMultiset.java +++ b/guava/src/com/google/common/collect/ImmutableSortedMultiset.java @@ -30,6 +30,8 @@ import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link SortedMultiset} whose contents will never change, with many other important properties @@ -48,8 +50,8 @@ * @since 12.0 */ @GwtIncompatible // hasn't been tested yet -public abstract class ImmutableSortedMultiset extends ImmutableSortedMultisetFauxverideShim - implements SortedMultiset { +public abstract class ImmutableSortedMultiset + extends ImmutableSortedMultisetFauxverideShim implements SortedMultiset { // TODO(lowasser): GWT compatibility /** @@ -61,8 +63,9 @@ public abstract class ImmutableSortedMultiset extends ImmutableSortedMultiset * * @since 21.0 */ - public static Collector> toImmutableSortedMultiset( - Comparator comparator) { + public static + Collector> toImmutableSortedMultiset( + Comparator comparator) { return toImmutableSortedMultiset(comparator, Function.identity(), e -> 1); } @@ -77,10 +80,11 @@ public abstract class ImmutableSortedMultiset extends ImmutableSortedMultiset * * @since 22.0 */ - public static Collector> toImmutableSortedMultiset( - Comparator comparator, - Function elementFunction, - ToIntFunction countFunction) { + public static + Collector> toImmutableSortedMultiset( + Comparator comparator, + Function elementFunction, + ToIntFunction countFunction) { checkNotNull(comparator); checkNotNull(elementFunction); checkNotNull(countFunction); @@ -97,7 +101,7 @@ public abstract class ImmutableSortedMultiset extends ImmutableSortedMultiset /** Returns the empty immutable sorted multiset. */ @SuppressWarnings("unchecked") - public static ImmutableSortedMultiset of() { + public static ImmutableSortedMultiset of() { return (ImmutableSortedMultiset) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; } @@ -202,7 +206,8 @@ public static > ImmutableSortedMultiset copyO * @throws ClassCastException if the elements are not mutually comparable * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableSortedMultiset copyOf(Iterable elements) { + public static ImmutableSortedMultiset copyOf( + Iterable elements) { // Hack around E not being a subtype of Comparable. // Unsafe, see ImmutableSortedMultisetFauxverideShim. @SuppressWarnings("unchecked") @@ -220,7 +225,8 @@ public static ImmutableSortedMultiset copyOf(Iterable elemen * @throws ClassCastException if the elements are not mutually comparable * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableSortedMultiset copyOf(Iterator elements) { + public static ImmutableSortedMultiset copyOf( + Iterator elements) { // Hack around E not being a subtype of Comparable. // Unsafe, see ImmutableSortedMultisetFauxverideShim. @SuppressWarnings("unchecked") @@ -234,7 +240,7 @@ public static ImmutableSortedMultiset copyOf(Iterator elemen * * @throws NullPointerException if {@code comparator} or any of {@code elements} is null */ - public static ImmutableSortedMultiset copyOf( + public static ImmutableSortedMultiset copyOf( Comparator comparator, Iterator elements) { checkNotNull(comparator); return new Builder(comparator).addAll(elements).build(); @@ -250,7 +256,7 @@ public static ImmutableSortedMultiset copyOf( * * @throws NullPointerException if {@code comparator} or any of {@code elements} is null */ - public static ImmutableSortedMultiset copyOf( + public static ImmutableSortedMultiset copyOf( Comparator comparator, Iterable elements) { if (elements instanceof ImmutableSortedMultiset) { @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts @@ -283,12 +289,13 @@ public static ImmutableSortedMultiset copyOf( * * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null */ - public static ImmutableSortedMultiset copyOfSorted(SortedMultiset sortedMultiset) { + public static ImmutableSortedMultiset copyOfSorted( + SortedMultiset sortedMultiset) { return copyOfSortedEntries( sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet())); } - private static ImmutableSortedMultiset copyOfSortedEntries( + private static ImmutableSortedMultiset copyOfSortedEntries( Comparator comparator, Collection> entries) { if (entries.isEmpty()) { return emptyMultiset(comparator); @@ -309,7 +316,8 @@ private static ImmutableSortedMultiset copyOfSortedEntries( } @SuppressWarnings("unchecked") - static ImmutableSortedMultiset emptyMultiset(Comparator comparator) { + static ImmutableSortedMultiset emptyMultiset( + Comparator comparator) { if (Ordering.natural().equals(comparator)) { return (ImmutableSortedMultiset) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; } else { @@ -327,7 +335,7 @@ public final Comparator comparator() { @Override public abstract ImmutableSortedSet elementSet(); - @LazyInit transient ImmutableSortedMultiset descendingMultiset; + @LazyInit transient @Nullable ImmutableSortedMultiset descendingMultiset; @Override public ImmutableSortedMultiset descendingMultiset() { @@ -352,7 +360,7 @@ public ImmutableSortedMultiset descendingMultiset() { @CanIgnoreReturnValue @Deprecated @Override - public final Entry pollFirstEntry() { + public final @Nullable Entry pollFirstEntry() { throw new UnsupportedOperationException(); } @@ -367,7 +375,7 @@ public final Entry pollFirstEntry() { @CanIgnoreReturnValue @Deprecated @Override - public final Entry pollLastEntry() { + public final @Nullable Entry pollLastEntry() { throw new UnsupportedOperationException(); } @@ -396,7 +404,7 @@ public ImmutableSortedMultiset subMultiset( * * @throws NullPointerException if {@code comparator} is null */ - public static Builder orderedBy(Comparator comparator) { + public static Builder orderedBy(Comparator comparator) { return new Builder(comparator); } @@ -445,7 +453,7 @@ public static > Builder naturalOrder() { * * @since 12.0 */ - public static class Builder extends ImmutableMultiset.Builder { + public static class Builder extends ImmutableMultiset.Builder { /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link * ImmutableSortedMultiset#orderedBy(Comparator)}. @@ -555,7 +563,7 @@ public ImmutableSortedMultiset build() { } } - private static final class SerializedForm implements Serializable { + private static final class SerializedForm implements Serializable { final Comparator comparator; final E[] elements; final int[] counts; diff --git a/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java index e3f45f751f84..b72eb57d720b 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java +++ b/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java @@ -18,6 +18,8 @@ import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * "Overrides" the {@link ImmutableMultiset} static methods that lack {@link @@ -37,7 +39,8 @@ * @author Louis Wasserman */ @GwtIncompatible -abstract class ImmutableSortedMultisetFauxverideShim extends ImmutableMultiset { +abstract class ImmutableSortedMultisetFauxverideShim + extends ImmutableMultiset { /** * Not supported. Use {@link ImmutableSortedMultiset#toImmutableSortedMultiset} instead. This * method exists only to hide {@link ImmutableMultiset#toImmutableMultiset} from consumers of @@ -48,7 +51,8 @@ abstract class ImmutableSortedMultisetFauxverideShim extends ImmutableMultise * @since 21.0 */ @Deprecated - public static Collector> toImmutableMultiset() { + public static + Collector> toImmutableMultiset() { throw new UnsupportedOperationException(); } @@ -62,8 +66,10 @@ abstract class ImmutableSortedMultisetFauxverideShim extends ImmutableMultise * @since 22.0 */ @Deprecated - public static Collector> toImmutableMultiset( - Function elementFunction, ToIntFunction countFunction) { + public static + Collector> toImmutableMultiset( + Function elementFunction, + ToIntFunction countFunction) { throw new UnsupportedOperationException(); } @@ -76,7 +82,7 @@ abstract class ImmutableSortedMultisetFauxverideShim extends ImmutableMultise * @deprecated Use {@link ImmutableSortedMultiset#naturalOrder}, which offers better type-safety. */ @Deprecated - public static ImmutableSortedMultiset.Builder builder() { + public static ImmutableSortedMultiset.Builder builder() { throw new UnsupportedOperationException(); } @@ -90,7 +96,7 @@ public static ImmutableSortedMultiset.Builder builder() { * ImmutableSortedMultiset#of(Comparable)}. */ @Deprecated - public static ImmutableSortedMultiset of(E element) { + public static ImmutableSortedMultiset of(E element) { throw new UnsupportedOperationException(); } @@ -104,7 +110,7 @@ public static ImmutableSortedMultiset of(E element) { * ImmutableSortedMultiset#of(Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedMultiset of(E e1, E e2) { + public static ImmutableSortedMultiset of(E e1, E e2) { throw new UnsupportedOperationException(); } @@ -118,7 +124,7 @@ public static ImmutableSortedMultiset of(E e1, E e2) { * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedMultiset of(E e1, E e2, E e3) { + public static ImmutableSortedMultiset of(E e1, E e2, E e3) { throw new UnsupportedOperationException(); } @@ -132,7 +138,7 @@ public static ImmutableSortedMultiset of(E e1, E e2, E e3) { * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedMultiset of(E e1, E e2, E e3, E e4) { + public static ImmutableSortedMultiset of(E e1, E e2, E e3, E e4) { throw new UnsupportedOperationException(); } @@ -147,7 +153,8 @@ public static ImmutableSortedMultiset of(E e1, E e2, E e3, E e4) { * */ @Deprecated - public static ImmutableSortedMultiset of(E e1, E e2, E e3, E e4, E e5) { + public static ImmutableSortedMultiset of( + E e1, E e2, E e3, E e4, E e5) { throw new UnsupportedOperationException(); } @@ -162,7 +169,7 @@ public static ImmutableSortedMultiset of(E e1, E e2, E e3, E e4, E e5) { * Comparable, Comparable...)} . */ @Deprecated - public static ImmutableSortedMultiset of( + public static ImmutableSortedMultiset of( E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { throw new UnsupportedOperationException(); } @@ -177,7 +184,7 @@ public static ImmutableSortedMultiset of( * ImmutableSortedMultiset#copyOf(Comparable[])}. */ @Deprecated - public static ImmutableSortedMultiset copyOf(E[] elements) { + public static ImmutableSortedMultiset copyOf(E[] elements) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/collect/ImmutableSortedSet.java b/guava/src/com/google/common/collect/ImmutableSortedSet.java index 9a3409cb8e1d..89fe7116f4a7 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedSet.java +++ b/guava/src/com/google/common/collect/ImmutableSortedSet.java @@ -38,6 +38,7 @@ import java.util.Spliterators; import java.util.function.Consumer; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -60,8 +61,8 @@ // TODO(benyu): benchmark and optimize all creation paths, which are a mess now @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization -public abstract class ImmutableSortedSet extends ImmutableSortedSetFauxverideShim - implements NavigableSet, SortedIterable { +public abstract class ImmutableSortedSet + extends ImmutableSortedSetFauxverideShim implements NavigableSet, SortedIterable { static final int SPLITERATOR_CHARACTERISTICS = ImmutableSet.SPLITERATOR_CHARACTERISTICS | Spliterator.SORTED; @@ -74,12 +75,14 @@ public abstract class ImmutableSortedSet extends ImmutableSortedSetFauxveride * * @since 21.0 */ - public static Collector> toImmutableSortedSet( - Comparator comparator) { + public static + Collector> toImmutableSortedSet( + Comparator comparator) { return CollectCollectors.toImmutableSortedSet(comparator); } - static RegularImmutableSortedSet emptySet(Comparator comparator) { + static RegularImmutableSortedSet emptySet( + Comparator comparator) { if (Ordering.natural().equals(comparator)) { return (RegularImmutableSortedSet) RegularImmutableSortedSet.NATURAL_EMPTY_SET; } else { @@ -88,7 +91,7 @@ static RegularImmutableSortedSet emptySet(Comparator comparato } /** Returns the empty immutable sorted set. */ - public static ImmutableSortedSet of() { + public static ImmutableSortedSet of() { return (ImmutableSortedSet) RegularImmutableSortedSet.NATURAL_EMPTY_SET; } @@ -203,7 +206,8 @@ public static > ImmutableSortedSet copyOf(E[] * @throws ClassCastException if the elements are not mutually comparable * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableSortedSet copyOf(Iterable elements) { + public static ImmutableSortedSet copyOf( + Iterable elements) { // Hack around E not being a subtype of Comparable. // Unsafe, see ImmutableSortedSetFauxverideShim. @SuppressWarnings("unchecked") @@ -235,7 +239,8 @@ public static ImmutableSortedSet copyOf(Iterable elements) { * @throws NullPointerException if any of {@code elements} is null * @since 7.0 (source-compatible since 2.0) */ - public static ImmutableSortedSet copyOf(Collection elements) { + public static ImmutableSortedSet copyOf( + Collection elements) { // Hack around E not being a subtype of Comparable. // Unsafe, see ImmutableSortedSetFauxverideShim. @SuppressWarnings("unchecked") @@ -254,7 +259,8 @@ public static ImmutableSortedSet copyOf(Collection elements) * @throws ClassCastException if the elements are not mutually comparable * @throws NullPointerException if any of {@code elements} is null */ - public static ImmutableSortedSet copyOf(Iterator elements) { + public static ImmutableSortedSet copyOf( + Iterator elements) { // Hack around E not being a subtype of Comparable. // Unsafe, see ImmutableSortedSetFauxverideShim. @SuppressWarnings("unchecked") @@ -269,7 +275,7 @@ public static ImmutableSortedSet copyOf(Iterator elements) { * * @throws NullPointerException if {@code comparator} or any of {@code elements} is null */ - public static ImmutableSortedSet copyOf( + public static ImmutableSortedSet copyOf( Comparator comparator, Iterator elements) { return new Builder(comparator).addAll(elements).build(); } @@ -285,7 +291,7 @@ public static ImmutableSortedSet copyOf( * * @throws NullPointerException if {@code comparator} or any of {@code elements} is null */ - public static ImmutableSortedSet copyOf( + public static ImmutableSortedSet copyOf( Comparator comparator, Iterable elements) { checkNotNull(comparator); boolean hasSameComparator = SortedIterables.hasSameComparator(comparator, elements); @@ -317,7 +323,7 @@ public static ImmutableSortedSet copyOf( * @throws NullPointerException if {@code comparator} or any of {@code elements} is null * @since 7.0 (source-compatible since 2.0) */ - public static ImmutableSortedSet copyOf( + public static ImmutableSortedSet copyOf( Comparator comparator, Collection elements) { return copyOf(comparator, (Iterable) elements); } @@ -336,7 +342,8 @@ public static ImmutableSortedSet copyOf( * * @throws NullPointerException if {@code sortedSet} or any of its elements is null */ - public static ImmutableSortedSet copyOfSorted(SortedSet sortedSet) { + public static ImmutableSortedSet copyOfSorted( + SortedSet sortedSet) { Comparator comparator = SortedIterables.comparator(sortedSet); ImmutableList list = ImmutableList.copyOf(sortedSet); if (list.isEmpty()) { @@ -357,7 +364,7 @@ public static ImmutableSortedSet copyOfSorted(SortedSet sortedSet) { * * @throws NullPointerException if any of the first {@code n} elements of {@code contents} is null */ - static ImmutableSortedSet construct( + static ImmutableSortedSet construct( Comparator comparator, int n, E... contents) { if (n == 0) { return emptySet(comparator); @@ -385,7 +392,7 @@ static ImmutableSortedSet construct( * * @throws NullPointerException if {@code comparator} is null */ - public static Builder orderedBy(Comparator comparator) { + public static Builder orderedBy(Comparator comparator) { return new Builder(comparator); } @@ -424,7 +431,7 @@ public static > Builder naturalOrder() { * * @since 2.0 */ - public static final class Builder extends ImmutableSet.Builder { + public static final class Builder extends ImmutableSet.Builder { private final Comparator comparator; private E[] elements; private int n; @@ -441,6 +448,7 @@ public Builder(Comparator comparator) { } @Override + @SuppressWarnings("assignment.type.incompatible") // arrays void copy() { elements = Arrays.copyOf(elements, elements.length); } @@ -475,6 +483,7 @@ private void sortAndDedup() { */ @CanIgnoreReturnValue @Override + @SuppressWarnings("assignment.type.incompatible") // arrays public Builder add(E element) { checkNotNull(element); copyIfNecessary(); @@ -570,16 +579,16 @@ public ImmutableSortedSet build() { } } - int unsafeCompare(Object a, Object b) { + int unsafeCompare(Object a, @Nullable Object b) { return unsafeCompare(comparator, a, b); } - static int unsafeCompare(Comparator comparator, Object a, Object b) { + static int unsafeCompare(Comparator comparator, Object a, @Nullable Object b) { // Pretend the comparator can compare anything. If it turns out it can't - // compare a and b, we should get a CCE on the subsequent line. Only methods - // that are spec'd to throw CCE should call this. - @SuppressWarnings("unchecked") - Comparator unsafeComparator = (Comparator) comparator; + // compare a and b, we should get a CCE or NPE on the subsequent line. Only methods + // that are spec'd to throw CCE and NPE should call this. + @SuppressWarnings({"unchecked", "nullness"}) + Comparator<@Nullable Object> unsafeComparator = (Comparator<@Nullable Object>) comparator; return unsafeComparator.compare(a, b); } @@ -686,27 +695,28 @@ abstract ImmutableSortedSet subSetImpl( /** @since 12.0 */ @GwtIncompatible // NavigableSet @Override - public E lower(E e) { - return Iterators.getNext(headSet(e, false).descendingIterator(), null); + public @Nullable E lower(E e) { + // TODO(cpovirk): Why does our prototype checker (but not stock CF) need <@Nullable E>? + return Iterators.<@Nullable E>getNext(headSet(e, false).descendingIterator(), null); } /** @since 12.0 */ @Override - public E floor(E e) { - return Iterators.getNext(headSet(e, true).descendingIterator(), null); + public @Nullable E floor(E e) { + return Iterators.<@Nullable E>getNext(headSet(e, true).descendingIterator(), null); } /** @since 12.0 */ @Override - public E ceiling(E e) { - return Iterables.getFirst(tailSet(e, true), null); + public @Nullable E ceiling(E e) { + return Iterables.<@Nullable E>getFirst(tailSet(e, true), null); } /** @since 12.0 */ @GwtIncompatible // NavigableSet @Override - public E higher(E e) { - return Iterables.getFirst(tailSet(e, false), null); + public @Nullable E higher(E e) { + return Iterables.<@Nullable E>getFirst(tailSet(e, false), null); } @Override @@ -730,7 +740,7 @@ public E last() { @Deprecated @GwtIncompatible // NavigableSet @Override - public final E pollFirst() { + public final @Nullable E pollFirst() { throw new UnsupportedOperationException(); } @@ -745,13 +755,13 @@ public final E pollFirst() { @Deprecated @GwtIncompatible // NavigableSet @Override - public final E pollLast() { + public final @Nullable E pollLast() { throw new UnsupportedOperationException(); } @GwtIncompatible // NavigableSet @LazyInit - transient ImmutableSortedSet descendingSet; + transient @Nullable ImmutableSortedSet descendingSet; /** @since 12.0 */ @GwtIncompatible // NavigableSet @@ -809,7 +819,7 @@ public Comparator getComparator() { * only. This is necessary to ensure that the existence of a particular * implementation type is an implementation detail. */ - private static class SerializedForm implements Serializable { + private static class SerializedForm implements Serializable { final Comparator comparator; final Object[] elements; diff --git a/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java index 9a49fcbe22e2..3d60e2a53238 100644 --- a/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java +++ b/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtIncompatible; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; /** * "Overrides" the {@link ImmutableSet} static methods that lack {@link ImmutableSortedSet} @@ -37,7 +38,7 @@ * @author Chris Povirk */ @GwtIncompatible -abstract class ImmutableSortedSetFauxverideShim extends ImmutableSet { +abstract class ImmutableSortedSetFauxverideShim extends ImmutableSet { /** * Not supported. Use {@link ImmutableSortedSet#toImmutableSortedSet} instead. This method exists * only to hide {@link ImmutableSet#toImmutableSet} from consumers of {@code ImmutableSortedSet}. @@ -47,7 +48,7 @@ abstract class ImmutableSortedSetFauxverideShim extends ImmutableSet { * @since 21.0 */ @Deprecated - public static Collector> toImmutableSet() { + public static Collector> toImmutableSet() { throw new UnsupportedOperationException(); } @@ -60,7 +61,7 @@ abstract class ImmutableSortedSetFauxverideShim extends ImmutableSet { * @deprecated Use {@link ImmutableSortedSet#naturalOrder}, which offers better type-safety. */ @Deprecated - public static ImmutableSortedSet.Builder builder() { + public static ImmutableSortedSet.Builder builder() { throw new UnsupportedOperationException(); } @@ -72,7 +73,8 @@ public static ImmutableSortedSet.Builder builder() { * @deprecated Not supported by ImmutableSortedSet. */ @Deprecated - public static ImmutableSortedSet.Builder builderWithExpectedSize(int expectedSize) { + public static ImmutableSortedSet.Builder builderWithExpectedSize( + int expectedSize) { throw new UnsupportedOperationException(); } @@ -86,7 +88,7 @@ public static ImmutableSortedSet.Builder builderWithExpectedSize(int expe * ImmutableSortedSet#of(Comparable)}. */ @Deprecated - public static ImmutableSortedSet of(E element) { + public static ImmutableSortedSet of(E element) { throw new UnsupportedOperationException(); } @@ -100,7 +102,7 @@ public static ImmutableSortedSet of(E element) { * ImmutableSortedSet#of(Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedSet of(E e1, E e2) { + public static ImmutableSortedSet of(E e1, E e2) { throw new UnsupportedOperationException(); } @@ -114,7 +116,7 @@ public static ImmutableSortedSet of(E e1, E e2) { * ImmutableSortedSet#of(Comparable, Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedSet of(E e1, E e2, E e3) { + public static ImmutableSortedSet of(E e1, E e2, E e3) { throw new UnsupportedOperationException(); } @@ -128,7 +130,7 @@ public static ImmutableSortedSet of(E e1, E e2, E e3) { * ImmutableSortedSet#of(Comparable, Comparable, Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedSet of(E e1, E e2, E e3, E e4) { + public static ImmutableSortedSet of(E e1, E e2, E e3, E e4) { throw new UnsupportedOperationException(); } @@ -142,7 +144,7 @@ public static ImmutableSortedSet of(E e1, E e2, E e3, E e4) { * ImmutableSortedSet#of( Comparable, Comparable, Comparable, Comparable, Comparable)}. */ @Deprecated - public static ImmutableSortedSet of(E e1, E e2, E e3, E e4, E e5) { + public static ImmutableSortedSet of(E e1, E e2, E e3, E e4, E e5) { throw new UnsupportedOperationException(); } @@ -157,7 +159,8 @@ public static ImmutableSortedSet of(E e1, E e2, E e3, E e4, E e5) { * Comparable, Comparable...)}. */ @Deprecated - public static ImmutableSortedSet of(E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { + public static ImmutableSortedSet of( + E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { throw new UnsupportedOperationException(); } @@ -171,7 +174,7 @@ public static ImmutableSortedSet of(E e1, E e2, E e3, E e4, E e5, E e6, E * ImmutableSortedSet#copyOf(Comparable[])}. */ @Deprecated - public static ImmutableSortedSet copyOf(E[] elements) { + public static ImmutableSortedSet copyOf(E[] elements) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/collect/ImmutableTable.java b/guava/src/com/google/common/collect/ImmutableTable.java index bdaddc3d3fc7..2bfaa2762838 100644 --- a/guava/src/com/google/common/collect/ImmutableTable.java +++ b/guava/src/com/google/common/collect/ImmutableTable.java @@ -22,7 +22,6 @@ import com.google.common.base.MoreObjects; import com.google.common.collect.Tables.AbstractCell; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.io.Serializable; import java.util.ArrayList; import java.util.Comparator; @@ -34,6 +33,7 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -47,8 +47,9 @@ * @since 11.0 */ @GwtCompatible -public abstract class ImmutableTable extends AbstractTable - implements Serializable { +public abstract class ImmutableTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends AbstractTable implements Serializable { /** * Returns a {@code Collector} that accumulates elements into an {@code ImmutableTable}. Each @@ -60,10 +61,15 @@ public abstract class ImmutableTable extends AbstractTable * * @since 21.0 */ - public static Collector> toImmutableTable( - Function rowFunction, - Function columnFunction, - Function valueFunction) { + public static < + T, + R extends @NonNull Object, + C extends @NonNull Object, + V extends @NonNull Object> + Collector> toImmutableTable( + Function rowFunction, + Function columnFunction, + Function valueFunction) { checkNotNull(rowFunction, "rowFunction"); checkNotNull(columnFunction, "columnFunction"); checkNotNull(valueFunction, "valueFunction"); @@ -86,11 +92,16 @@ public abstract class ImmutableTable extends AbstractTable * * @since 21.0 */ - public static Collector> toImmutableTable( - Function rowFunction, - Function columnFunction, - Function valueFunction, - BinaryOperator mergeFunction) { + public static < + T, + R extends @NonNull Object, + C extends @NonNull Object, + V extends @NonNull Object> + Collector> toImmutableTable( + Function rowFunction, + Function columnFunction, + Function valueFunction, + BinaryOperator mergeFunction) { checkNotNull(rowFunction, "rowFunction"); checkNotNull(columnFunction, "columnFunction"); @@ -116,7 +127,8 @@ public abstract class ImmutableTable extends AbstractTable state -> state.toTable()); } - private static final class CollectorState { + private static final class CollectorState< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> { final List> insertionOrder = new ArrayList<>(); final Table> table = HashBasedTable.create(); @@ -143,7 +155,9 @@ ImmutableTable toTable() { } } - private static final class MutableCell extends AbstractCell { + private static final class MutableCell< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends AbstractCell { private final R row; private final C column; private V value; @@ -177,12 +191,14 @@ void merge(V value, BinaryOperator mergeFunction) { /** Returns an empty immutable table. */ @SuppressWarnings("unchecked") - public static ImmutableTable of() { + public static + ImmutableTable of() { return (ImmutableTable) SparseImmutableTable.EMPTY; } /** Returns an immutable table containing a single cell. */ - public static ImmutableTable of(R rowKey, C columnKey, V value) { + public static + ImmutableTable of(R rowKey, C columnKey, V value) { return new SingletonImmutableTable<>(rowKey, columnKey, value); } @@ -199,8 +215,8 @@ public static ImmutableTable of(R rowKey, C columnKey, V valu * safe to do so. The exact circumstances under which a copy will or will not be performed are * undocumented and subject to change. */ - public static ImmutableTable copyOf( - Table table) { + public static + ImmutableTable copyOf(Table table) { if (table instanceof ImmutableTable) { @SuppressWarnings("unchecked") ImmutableTable parameterizedTable = (ImmutableTable) table; @@ -210,8 +226,9 @@ public static ImmutableTable copyOf( } } - private static ImmutableTable copyOf( - Iterable> cells) { + private static + ImmutableTable copyOf( + Iterable> cells) { ImmutableTable.Builder builder = ImmutableTable.builder(); for (Cell cell : cells) { builder.put(cell); @@ -223,7 +240,8 @@ private static ImmutableTable copyOf( * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder#Builder() ImmutableTable.Builder()} constructor. */ - public static Builder builder() { + public static + Builder builder() { return new Builder<>(); } @@ -231,7 +249,8 @@ public static Builder builder() { * Verifies that {@code rowKey}, {@code columnKey} and {@code value} are non-null, and returns a * new entry with those values. */ - static Cell cellOf(R rowKey, C columnKey, V value) { + static + Cell cellOf(R rowKey, C columnKey, V value) { return Tables.immutableCell( checkNotNull(rowKey, "rowKey"), checkNotNull(columnKey, "columnKey"), @@ -264,11 +283,11 @@ static Cell cellOf(R rowKey, C columnKey, V value) { * * @since 11.0 */ - @DoNotMock - public static final class Builder { + public static final class Builder< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> { private final List> cells = Lists.newArrayList(); - private @Nullable Comparator rowComparator; - private @Nullable Comparator columnComparator; + @Nullable private Comparator rowComparator; + @Nullable private Comparator columnComparator; /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link @@ -472,7 +491,7 @@ public final void clear() { @CanIgnoreReturnValue @Deprecated @Override - public final V put(R rowKey, C columnKey, V value) { + public final @Nullable V put(R rowKey, C columnKey, V value) { throw new UnsupportedOperationException(); } @@ -497,7 +516,7 @@ public final void putAll(Table table) { @CanIgnoreReturnValue @Deprecated @Override - public final V remove(Object rowKey, Object columnKey) { + public final @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/collect/IndexedImmutableSet.java b/guava/src/com/google/common/collect/IndexedImmutableSet.java index 0168913893b0..c34fff32ccb3 100644 --- a/guava/src/com/google/common/collect/IndexedImmutableSet.java +++ b/guava/src/com/google/common/collect/IndexedImmutableSet.java @@ -22,9 +22,10 @@ import com.google.common.annotations.GwtIncompatible; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; @GwtCompatible(emulated = true) -abstract class IndexedImmutableSet extends ImmutableSet { +abstract class IndexedImmutableSet extends ImmutableSet { abstract E get(int index); @Override diff --git a/guava/src/com/google/common/collect/Interner.java b/guava/src/com/google/common/collect/Interner.java index 10d395d5024b..b392fb5371da 100644 --- a/guava/src/com/google/common/collect/Interner.java +++ b/guava/src/com/google/common/collect/Interner.java @@ -19,7 +19,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Provides equivalent behavior to {@link String#intern} for other immutable types. Common @@ -29,9 +29,8 @@ * @since 3.0 */ @Beta -@DoNotMock("Use Interners.new*Interner") @GwtIncompatible -public interface Interner { +public interface Interner { /** * Chooses and returns the representative instance for any of a collection of instances that are * equal to each other. If two {@linkplain Object#equals equal} inputs are given to this method, diff --git a/guava/src/com/google/common/collect/Interners.java b/guava/src/com/google/common/collect/Interners.java index 061a1cfc7c73..4021f5fe76d1 100644 --- a/guava/src/com/google/common/collect/Interners.java +++ b/guava/src/com/google/common/collect/Interners.java @@ -23,6 +23,8 @@ import com.google.common.base.Function; import com.google.common.collect.MapMaker.Dummy; import com.google.common.collect.MapMakerInternalMap.InternalEntry; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Contains static methods pertaining to instances of {@link Interner}. @@ -77,7 +79,7 @@ public InternerBuilder concurrencyLevel(int concurrencyLevel) { return this; } - public Interner build() { + public Interner build() { if (!strong) { mapMaker.weakKeys(); } @@ -95,7 +97,7 @@ public static InternerBuilder newBuilder() { * interned, thus preventing these instances from being garbage-collected. If this retention is * acceptable, this implementation may perform better than {@link #newWeakInterner}. */ - public static Interner newStrongInterner() { + public static Interner newStrongInterner() { return newBuilder().strong().build(); } @@ -106,12 +108,12 @@ public static Interner newStrongInterner() { * the memory usage of that implementation is unacceptable. */ @GwtIncompatible("java.lang.ref.WeakReference") - public static Interner newWeakInterner() { + public static Interner newWeakInterner() { return newBuilder().weak().build(); } @VisibleForTesting - static final class InternerImpl implements Interner { + static final class InternerImpl implements Interner { // MapMaker is our friend, we know about this type @VisibleForTesting final MapMakerInternalMap map; @@ -153,11 +155,11 @@ public E intern(E sample) { * * @since 8.0 */ - public static Function asFunction(Interner interner) { + public static Function asFunction(Interner interner) { return new InternerFunction(checkNotNull(interner)); } - private static class InternerFunction implements Function { + private static class InternerFunction implements Function { private final Interner interner; @@ -176,7 +178,7 @@ public int hashCode() { } @Override - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (other instanceof InternerFunction) { InternerFunction that = (InternerFunction) other; return interner.equals(that.interner); diff --git a/guava/src/com/google/common/collect/Iterables.java b/guava/src/com/google/common/collect/Iterables.java index 5313b49e9111..eb6dc86f1f62 100644 --- a/guava/src/com/google/common/collect/Iterables.java +++ b/guava/src/com/google/common/collect/Iterables.java @@ -39,6 +39,7 @@ import java.util.Spliterator; import java.util.function.Consumer; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -68,7 +69,8 @@ public final class Iterables { private Iterables() {} /** Returns an unmodifiable view of {@code iterable}. */ - public static Iterable unmodifiableIterable(final Iterable iterable) { + public static Iterable unmodifiableIterable( + final Iterable iterable) { checkNotNull(iterable); if (iterable instanceof UnmodifiableIterable || iterable instanceof ImmutableCollection) { @SuppressWarnings("unchecked") // Since it's unmodifiable, the covariant cast is safe @@ -85,11 +87,13 @@ public static Iterable unmodifiableIterable(final Iterable i * @since 10.0 */ @Deprecated - public static Iterable unmodifiableIterable(ImmutableCollection iterable) { + public static Iterable unmodifiableIterable( + ImmutableCollection iterable) { return checkNotNull(iterable); } - private static final class UnmodifiableIterable extends FluentIterable { + private static final class UnmodifiableIterable + extends FluentIterable { private final Iterable iterable; private UnmodifiableIterable(Iterable iterable) { @@ -132,9 +136,11 @@ public static int size(Iterable iterable) { * cases where {@link Collection#contains} might throw {@link NullPointerException} or {@link * ClassCastException}. */ - public static boolean contains(Iterable iterable, @Nullable Object element) { + public static boolean contains( + Iterable iterable, @Nullable Object element) { if (iterable instanceof Collection) { - Collection collection = (Collection) iterable; + Collection collection = + (Collection) iterable; return Collections2.safeContains(collection, element); } return Iterators.contains(iterable.iterator(), element); @@ -151,9 +157,12 @@ public static boolean contains(Iterable iterable, @Nullable Object element) { * @return {@code true} if any element was removed from {@code iterable} */ @CanIgnoreReturnValue - public static boolean removeAll(Iterable removeFrom, Collection elementsToRemove) { + public static boolean removeAll( + Iterable removeFrom, + Collection elementsToRemove) { return (removeFrom instanceof Collection) - ? ((Collection) removeFrom).removeAll(checkNotNull(elementsToRemove)) + ? ((Collection) removeFrom) + .removeAll(checkNotNull(elementsToRemove)) : Iterators.removeAll(removeFrom.iterator(), elementsToRemove); } @@ -168,9 +177,12 @@ public static boolean removeAll(Iterable removeFrom, Collection elementsTo * @return {@code true} if any element was removed from {@code iterable} */ @CanIgnoreReturnValue - public static boolean retainAll(Iterable removeFrom, Collection elementsToRetain) { + public static boolean retainAll( + Iterable removeFrom, + Collection elementsToRetain) { return (removeFrom instanceof Collection) - ? ((Collection) removeFrom).retainAll(checkNotNull(elementsToRetain)) + ? ((Collection) removeFrom) + .retainAll(checkNotNull(elementsToRetain)) : Iterators.retainAll(removeFrom.iterator(), elementsToRetain); } @@ -191,7 +203,8 @@ public static boolean retainAll(Iterable removeFrom, Collection elementsTo * @since 2.0 */ @CanIgnoreReturnValue - public static boolean removeIf(Iterable removeFrom, Predicate predicate) { + public static boolean removeIf( + Iterable removeFrom, Predicate predicate) { if (removeFrom instanceof Collection) { return ((Collection) removeFrom).removeIf(predicate); } @@ -219,10 +232,14 @@ public static boolean removeIf(Iterable removeFrom, Predicate * number of elements and every element of {@code iterable1} is equal to the corresponding element * of {@code iterable2}. */ - public static boolean elementsEqual(Iterable iterable1, Iterable iterable2) { + public static boolean elementsEqual( + Iterable iterable1, + Iterable iterable2) { if (iterable1 instanceof Collection && iterable2 instanceof Collection) { - Collection collection1 = (Collection) iterable1; - Collection collection2 = (Collection) iterable2; + Collection collection1 = + (Collection) iterable1; + Collection collection2 = + (Collection) iterable2; if (collection1.size() != collection2.size()) { return false; } @@ -263,8 +280,8 @@ public static T getOnlyElement(Iterable iterable) { * * @throws IllegalArgumentException if the iterator contains multiple elements */ - public static @Nullable T getOnlyElement( - Iterable iterable, @Nullable T defaultValue) { + public static T getOnlyElement( + Iterable iterable, T defaultValue) { return Iterators.getOnlyElement(iterable.iterator(), defaultValue); } @@ -276,10 +293,12 @@ public static T getOnlyElement(Iterable iterable) { * @return a newly-allocated array into which all the elements of the iterable have been copied */ @GwtIncompatible // Array.newInstance(Class, int) +@SuppressWarnings("nullness") public static T[] toArray(Iterable iterable, Class type) { return toArray(iterable, ObjectArrays.newArray(type, 0)); } + @SuppressWarnings("return.type.incompatible") // arrays static T[] toArray(Iterable iterable, T[] array) { Collection collection = castOrCopyToCollection(iterable); return collection.toArray(array); @@ -291,6 +310,7 @@ static T[] toArray(Iterable iterable, T[] array) { * @param iterable the iterable to copy * @return a newly-allocated array into which all the elements of the iterable have been copied */ + @SuppressWarnings("return.type.incompatible") // arrays static Object[] toArray(Iterable iterable) { return castOrCopyToCollection(iterable).toArray(); } @@ -300,7 +320,8 @@ static Object[] toArray(Iterable iterable) { * returned. Otherwise, an {@link java.util.ArrayList} is created with the contents of the * iterable in the same iteration order. */ - private static Collection castOrCopyToCollection(Iterable iterable) { + private static Collection castOrCopyToCollection( + Iterable iterable) { return (iterable instanceof Collection) ? (Collection) iterable : Lists.newArrayList(iterable.iterator()); @@ -312,7 +333,8 @@ private static Collection castOrCopyToCollection(Iterable iterable) { * @return {@code true} if {@code collection} was modified as a result of this operation. */ @CanIgnoreReturnValue - public static boolean addAll(Collection addTo, Iterable elementsToAdd) { + public static boolean addAll( + Collection addTo, Iterable elementsToAdd) { if (elementsToAdd instanceof Collection) { Collection c = Collections2.cast(elementsToAdd); return addTo.addAll(c); @@ -331,7 +353,8 @@ public static boolean addAll(Collection addTo, Iterable elem * @see java.util.Collections#frequency(Collection, Object) Collections.frequency(Collection, * Object) */ - public static int frequency(Iterable iterable, @Nullable Object element) { + public static int frequency( + Iterable iterable, @Nullable Object element) { if ((iterable instanceof Multiset)) { return ((Multiset) iterable).count(element); } else if ((iterable instanceof Set)) { @@ -414,7 +437,8 @@ public static Iterable cycle(T... elements) { *

    Java 8 users: The {@code Stream} equivalent of this method is {@code Stream.concat(a, * b)}. */ - public static Iterable concat(Iterable a, Iterable b) { + public static Iterable concat( + Iterable a, Iterable b) { return FluentIterable.concat(a, b); } @@ -484,7 +508,8 @@ public static Iterable concat(Iterable... inputs) { *

    Java 8 users: The {@code Stream} equivalent of this method is {@code * streamOfStreams.flatMap(s -> s)}. */ - public static Iterable concat(Iterable> inputs) { + public static Iterable concat( + Iterable> inputs) { return FluentIterable.concat(inputs); } @@ -506,7 +531,8 @@ public static Iterable concat(Iterable> i * into partitions * @throws IllegalArgumentException if {@code size} is nonpositive */ - public static Iterable> partition(final Iterable iterable, final int size) { + public static Iterable> partition( + final Iterable iterable, final int size) { checkNotNull(iterable); checkArgument(size > 0); return new FluentIterable>() { @@ -532,7 +558,8 @@ public Iterator> iterator() { * into partitions (the final iterable may have trailing null elements) * @throws IllegalArgumentException if {@code size} is nonpositive */ - public static Iterable> paddedPartition(final Iterable iterable, final int size) { + public static Iterable> paddedPartition( + final Iterable iterable, final int size) { checkNotNull(iterable); checkArgument(size > 0); return new FluentIterable>() { @@ -593,7 +620,8 @@ public Spliterator spliterator() { */ @SuppressWarnings("unchecked") @GwtIncompatible // Class.isInstance - public static Iterable filter(final Iterable unfiltered, final Class desiredType) { + public static Iterable filter( + final Iterable unfiltered, final Class desiredType) { checkNotNull(unfiltered); checkNotNull(desiredType); return (Iterable) filter(unfiltered, Predicates.instanceOf(desiredType)); @@ -604,7 +632,8 @@ public static Iterable filter(final Iterable unfiltered, final Class{@code Stream} equivalent: {@link Stream#anyMatch}. */ - public static boolean any(Iterable iterable, Predicate predicate) { + public static boolean any( + Iterable iterable, Predicate predicate) { return Iterators.any(iterable.iterator(), predicate); } @@ -614,7 +643,8 @@ public static boolean any(Iterable iterable, Predicate predica * *

    {@code Stream} equivalent: {@link Stream#allMatch}. */ - public static boolean all(Iterable iterable, Predicate predicate) { + public static boolean all( + Iterable iterable, Predicate predicate) { return Iterators.all(iterable.iterator(), predicate); } @@ -627,7 +657,8 @@ public static boolean all(Iterable iterable, Predicate predica * * @throws NoSuchElementException if no element in {@code iterable} matches the given predicate */ - public static T find(Iterable iterable, Predicate predicate) { + public static T find( + Iterable iterable, Predicate predicate) { return Iterators.find(iterable.iterator(), predicate); } @@ -641,8 +672,8 @@ public static T find(Iterable iterable, Predicate predicate) { * * @since 7.0 */ - public static @Nullable T find( - Iterable iterable, Predicate predicate, @Nullable T defaultValue) { + public static T find( + Iterable iterable, Predicate predicate, T defaultValue) { return Iterators.find(iterable.iterator(), predicate, defaultValue); } @@ -657,7 +688,8 @@ public static T find(Iterable iterable, Predicate predicate) { * * @since 11.0 */ - public static Optional tryFind(Iterable iterable, Predicate predicate) { + public static Optional tryFind( + Iterable iterable, Predicate predicate) { return Iterators.tryFind(iterable.iterator(), predicate); } @@ -671,7 +703,8 @@ public static Optional tryFind(Iterable iterable, Predicate * * @since 2.0 */ - public static int indexOf(Iterable iterable, Predicate predicate) { + public static int indexOf( + Iterable iterable, Predicate predicate) { return Iterators.indexOf(iterable.iterator(), predicate); } @@ -744,8 +777,8 @@ public static T get(Iterable iterable, int position) { * @throws IndexOutOfBoundsException if {@code position} is negative * @since 4.0 */ - public static @Nullable T get( - Iterable iterable, int position, @Nullable T defaultValue) { + public static T get( + Iterable iterable, int position, T defaultValue) { checkNotNull(iterable); Iterators.checkNonnegative(position); if (iterable instanceof List) { @@ -775,7 +808,8 @@ public static T get(Iterable iterable, int position) { * @return the first element of {@code iterable} or the default value * @since 7.0 */ - public static @Nullable T getFirst(Iterable iterable, @Nullable T defaultValue) { + public static T getFirst( + Iterable iterable, T defaultValue) { return Iterators.getNext(iterable.iterator(), defaultValue); } @@ -812,7 +846,8 @@ public static T getLast(Iterable iterable) { * @return the last element of {@code iterable} or the default value * @since 3.0 */ - public static @Nullable T getLast(Iterable iterable, @Nullable T defaultValue) { + public static T getLast( + Iterable iterable, T defaultValue) { if (iterable instanceof Collection) { Collection c = Collections2.cast(iterable); if (c.isEmpty()) { @@ -848,7 +883,8 @@ private static T getLastInNonemptyList(List list) { * * @since 3.0 */ - public static Iterable skip(final Iterable iterable, final int numberToSkip) { + public static Iterable skip( + final Iterable iterable, final int numberToSkip) { checkNotNull(iterable); checkArgument(numberToSkip >= 0, "number to skip cannot be negative"); @@ -918,7 +954,8 @@ public Spliterator spliterator() { * @throws IllegalArgumentException if {@code limitSize} is negative * @since 3.0 */ - public static Iterable limit(final Iterable iterable, final int limitSize) { + public static Iterable limit( + final Iterable iterable, final int limitSize) { checkNotNull(iterable); checkArgument(limitSize >= 0, "limit is negative"); return new FluentIterable() { @@ -950,7 +987,8 @@ public Spliterator spliterator() { * @see Iterators#consumingIterator(Iterator) * @since 2.0 */ - public static Iterable consumingIterable(final Iterable iterable) { + public static Iterable consumingIterable( + final Iterable iterable) { checkNotNull(iterable); return new FluentIterable() { @@ -1019,7 +1057,8 @@ public Iterator iterator() { // TODO(user): Is this the best place for this? Move to fluent functions? // Useful as a public method? - static Function, Iterator> toIterator() { + static + Function, Iterator> toIterator() { return new Function, Iterator>() { @Override public Iterator apply(Iterable iterable) { diff --git a/guava/src/com/google/common/collect/Iterators.java b/guava/src/com/google/common/collect/Iterators.java index f655c279de53..8be24bbcc579 100644 --- a/guava/src/com/google/common/collect/Iterators.java +++ b/guava/src/com/google/common/collect/Iterators.java @@ -20,7 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Predicates.instanceOf; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -45,6 +45,7 @@ import java.util.NoSuchElementException; import java.util.PriorityQueue; import java.util.Queue; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -107,7 +108,7 @@ public Object next() { @Override public void remove() { - checkRemove(false); + throw noCallsToNextSinceLastRemove(); } } @@ -116,7 +117,7 @@ public void remove() { * UnsupportedOperationException} on a call to {@link Iterator#remove()}. */ // Casting to any type is safe since there are no actual elements. - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "nullness"}) static Iterator emptyModifiableIterator() { return (Iterator) EmptyModifiableIterator.INSTANCE; } @@ -150,7 +151,8 @@ public T next() { * @since 10.0 */ @Deprecated - public static UnmodifiableIterator unmodifiableIterator(UnmodifiableIterator iterator) { + public static UnmodifiableIterator unmodifiableIterator( + UnmodifiableIterator iterator) { return checkNotNull(iterator); } @@ -168,7 +170,8 @@ public static int size(Iterator iterator) { } /** Returns {@code true} if {@code iterator} contains {@code element}. */ - public static boolean contains(Iterator iterator, @Nullable Object element) { + public static boolean contains( + Iterator iterator, @Nullable Object element) { if (element == null) { while (iterator.hasNext()) { if (iterator.next() == null) { @@ -194,7 +197,9 @@ public static boolean contains(Iterator iterator, @Nullable Object element) { * @return {@code true} if any element was removed from {@code iterator} */ @CanIgnoreReturnValue - public static boolean removeAll(Iterator removeFrom, Collection elementsToRemove) { + public static boolean removeAll( + Iterator removeFrom, + Collection elementsToRemove) { checkNotNull(elementsToRemove); boolean result = false; while (removeFrom.hasNext()) { @@ -216,7 +221,8 @@ public static boolean removeAll(Iterator removeFrom, Collection elementsTo * @since 2.0 */ @CanIgnoreReturnValue - public static boolean removeIf(Iterator removeFrom, Predicate predicate) { + public static boolean removeIf( + Iterator removeFrom, Predicate predicate) { checkNotNull(predicate); boolean modified = false; while (removeFrom.hasNext()) { @@ -238,7 +244,9 @@ public static boolean removeIf(Iterator removeFrom, Predicate * @return {@code true} if any element was removed from {@code iterator} */ @CanIgnoreReturnValue - public static boolean retainAll(Iterator removeFrom, Collection elementsToRetain) { + public static boolean retainAll( + Iterator removeFrom, + Collection elementsToRetain) { checkNotNull(elementsToRetain); boolean result = false; while (removeFrom.hasNext()) { @@ -259,7 +267,9 @@ public static boolean retainAll(Iterator removeFrom, Collection elementsTo *

    Note that this will modify the supplied iterators, since they will have been advanced some * number of elements forward. */ - public static boolean elementsEqual(Iterator iterator1, Iterator iterator2) { + public static boolean elementsEqual( + Iterator iterator1, + Iterator iterator2) { while (iterator1.hasNext()) { if (!iterator2.hasNext()) { return false; @@ -322,8 +332,8 @@ public static T getOnlyElement(Iterator iterator) { * @throws IllegalArgumentException if the iterator contains multiple elements. The state of the * iterator is unspecified. */ - public static @Nullable T getOnlyElement( - Iterator iterator, @Nullable T defaultValue) { + public static T getOnlyElement( + Iterator iterator, T defaultValue) { return iterator.hasNext() ? getOnlyElement(iterator) : defaultValue; } @@ -336,6 +346,7 @@ public static T getOnlyElement(Iterator iterator) { * @return a newly-allocated array into which all the elements of the iterator have been copied */ @GwtIncompatible // Array.newInstance(Class, int) +@SuppressWarnings("nullness") public static T[] toArray(Iterator iterator, Class type) { List list = Lists.newArrayList(iterator); return Iterables.toArray(list, type); @@ -348,7 +359,8 @@ public static T[] toArray(Iterator iterator, Class type) { * @return {@code true} if {@code collection} was modified as a result of this operation */ @CanIgnoreReturnValue - public static boolean addAll(Collection addTo, Iterator iterator) { + public static boolean addAll( + Collection addTo, Iterator iterator) { checkNotNull(addTo); checkNotNull(iterator); boolean wasModified = false; @@ -364,7 +376,8 @@ public static boolean addAll(Collection addTo, Iterator iter * * @see Collections#frequency */ - public static int frequency(Iterator iterator, @Nullable Object element) { + public static int frequency( + Iterator iterator, @Nullable Object element) { int count = 0; while (contains(iterator, element)) { // Since it lives in the same class, we know contains gets to the element and then stops, @@ -461,13 +474,23 @@ public T next() { throw new NoSuchElementException(); } T result = elements[index]; - elements[index] = null; + /* + * Safe because we never access this index again. (consumingForArray doesn't do so + * internally, and its callers all either make copies of a user-specified array or construct + * one that they hand off without retaining a reference.) + */ + elements[index] = unsafeNull(); index++; return result; } }; } + @SuppressWarnings("nullness") + private static T unsafeNull() { + return null; + } + /** * Combines two iterators into a single iterator. The returned iterator iterates across the * elements in {@code a}, followed by the elements in {@code b}. The source iterators are not @@ -476,7 +499,8 @@ public T next() { *

    The returned iterator supports {@code remove()} when the corresponding input iterator * supports it. */ - public static Iterator concat(Iterator a, Iterator b) { + public static Iterator concat( + Iterator a, Iterator b) { checkNotNull(a); checkNotNull(b); return concat(consumingForArray(a, b)); @@ -542,12 +566,14 @@ public static Iterator concat(Iterator... inputs) { * supports it. The methods of the returned iterator may throw {@code NullPointerException} if any * of the input iterators is null. */ - public static Iterator concat(Iterator> inputs) { + public static Iterator concat( + Iterator> inputs) { return new ConcatenatedIterator(inputs); } /** Concats a varargs array of iterators without making a defensive copy of the array. */ - static Iterator concatNoDefensiveCopy(Iterator... inputs) { + static Iterator concatNoDefensiveCopy( + Iterator... inputs) { for (Iterator input : checkNotNull(inputs)) { checkNotNull(input); } @@ -568,7 +594,8 @@ static Iterator concatNoDefensiveCopy(Iterator... inputs) { * partitions * @throws IllegalArgumentException if {@code size} is nonpositive */ - public static UnmodifiableIterator> partition(Iterator iterator, int size) { + public static UnmodifiableIterator> partition( + Iterator iterator, int size) { return partitionImpl(iterator, size, false); } @@ -586,7 +613,8 @@ public static UnmodifiableIterator> partition(Iterator iterator, * partitions (the final iterable may have trailing null elements) * @throws IllegalArgumentException if {@code size} is nonpositive */ - public static UnmodifiableIterator> paddedPartition(Iterator iterator, int size) { + public static UnmodifiableIterator> paddedPartition( + Iterator iterator, int size) { return partitionImpl(iterator, size, true); } @@ -605,7 +633,7 @@ public List next() { if (!hasNext()) { throw new NoSuchElementException(); } - Object[] array = new Object[size]; + @Nullable Object[] array = new Object[size]; int count = 0; for (; count < size && iterator.hasNext(); count++) { array[count] = iterator.next(); @@ -649,7 +677,8 @@ protected T computeNext() { */ @SuppressWarnings("unchecked") // can cast to because non-Ts are removed @GwtIncompatible // Class.isInstance - public static UnmodifiableIterator filter(Iterator unfiltered, Class desiredType) { + public static UnmodifiableIterator filter( + Iterator unfiltered, Class desiredType) { return (UnmodifiableIterator) filter(unfiltered, instanceOf(desiredType)); } @@ -657,7 +686,8 @@ public static UnmodifiableIterator filter(Iterator unfiltered, Class boolean any(Iterator iterator, Predicate predicate) { + public static boolean any( + Iterator iterator, Predicate predicate) { return indexOf(iterator, predicate) != -1; } @@ -665,7 +695,8 @@ public static boolean any(Iterator iterator, Predicate predica * Returns {@code true} if every element returned by {@code iterator} satisfies the given * predicate. If {@code iterator} is empty, {@code true} is returned. */ - public static boolean all(Iterator iterator, Predicate predicate) { + public static boolean all( + Iterator iterator, Predicate predicate) { checkNotNull(predicate); while (iterator.hasNext()) { T element = iterator.next(); @@ -685,7 +716,8 @@ public static boolean all(Iterator iterator, Predicate predica * * @throws NoSuchElementException if no element in {@code iterator} matches the given predicate */ - public static T find(Iterator iterator, Predicate predicate) { + public static T find( + Iterator iterator, Predicate predicate) { checkNotNull(iterator); checkNotNull(predicate); while (iterator.hasNext()) { @@ -705,8 +737,8 @@ public static T find(Iterator iterator, Predicate predicate) { * * @since 7.0 */ - public static @Nullable T find( - Iterator iterator, Predicate predicate, @Nullable T defaultValue) { + public static T find( + Iterator iterator, Predicate predicate, T defaultValue) { checkNotNull(iterator); checkNotNull(predicate); while (iterator.hasNext()) { @@ -729,7 +761,8 @@ public static T find(Iterator iterator, Predicate predicate) { * * @since 11.0 */ - public static Optional tryFind(Iterator iterator, Predicate predicate) { + public static Optional tryFind( + Iterator iterator, Predicate predicate) { checkNotNull(iterator); checkNotNull(predicate); while (iterator.hasNext()) { @@ -755,7 +788,8 @@ public static Optional tryFind(Iterator iterator, Predicate * * @since 2.0 */ - public static int indexOf(Iterator iterator, Predicate predicate) { + public static int indexOf( + Iterator iterator, Predicate predicate) { checkNotNull(predicate, "predicate"); for (int i = 0; iterator.hasNext(); i++) { T current = iterator.next(); @@ -820,8 +854,8 @@ public static T get(Iterator iterator, int position) { * @throws IndexOutOfBoundsException if {@code position} is negative * @since 4.0 */ - public static @Nullable T get( - Iterator iterator, int position, @Nullable T defaultValue) { + public static T get( + Iterator iterator, int position, T defaultValue) { checkNonnegative(position); advance(iterator, position); return getNext(iterator, defaultValue); @@ -841,7 +875,8 @@ static void checkNonnegative(int position) { * @return the next element of {@code iterator} or the default value * @since 7.0 */ - public static @Nullable T getNext(Iterator iterator, @Nullable T defaultValue) { + public static T getNext( + Iterator iterator, T defaultValue) { return iterator.hasNext() ? iterator.next() : defaultValue; } @@ -868,7 +903,8 @@ public static T getLast(Iterator iterator) { * @return the last element of {@code iterator} * @since 3.0 */ - public static @Nullable T getLast(Iterator iterator, @Nullable T defaultValue) { + public static T getLast( + Iterator iterator, T defaultValue) { return iterator.hasNext() ? getLast(iterator) : defaultValue; } @@ -901,7 +937,8 @@ public static int advance(Iterator iterator, int numberToAdvance) { * @throws IllegalArgumentException if {@code limitSize} is negative * @since 3.0 */ - public static Iterator limit(final Iterator iterator, final int limitSize) { + public static Iterator limit( + final Iterator iterator, final int limitSize) { checkNotNull(iterator); checkArgument(limitSize >= 0, "limit is negative"); return new Iterator() { @@ -939,7 +976,8 @@ public void remove() { * @return an iterator that removes and returns elements from the supplied iterator * @since 2.0 */ - public static Iterator consumingIterator(final Iterator iterator) { + public static Iterator consumingIterator( + final Iterator iterator) { checkNotNull(iterator); return new UnmodifiableIterator() { @Override @@ -1022,7 +1060,8 @@ static UnmodifiableListIterator forArray( return new ArrayItr(array, offset, length, index); } - private static final class ArrayItr extends AbstractIndexedListIterator { + private static final class ArrayItr + extends AbstractIndexedListIterator { static final UnmodifiableListIterator EMPTY = new ArrayItr<>(new Object[0], 0, 0, 0); private final T[] array; @@ -1045,7 +1084,8 @@ protected T get(int index) { * *

    The {@link Iterable} equivalent of this method is {@link Collections#singleton}. */ - public static UnmodifiableIterator singletonIterator(final @Nullable T value) { + public static UnmodifiableIterator singletonIterator( + final T value) { return new UnmodifiableIterator() { boolean done; @@ -1075,7 +1115,8 @@ public T next() { *

    Java 9 users: use {@code enumeration.asIterator()} instead, unless it is important to * return an {@code UnmodifiableIterator} instead of a plain {@code Iterator}. */ - public static UnmodifiableIterator forEnumeration(final Enumeration enumeration) { + public static UnmodifiableIterator forEnumeration( + final Enumeration enumeration) { checkNotNull(enumeration); return new UnmodifiableIterator() { @Override @@ -1096,7 +1137,8 @@ public T next() { *

    The {@code Iterable} equivalent of this method is either {@link Collections#enumeration} (if * you have a {@link Collection}), or {@code Iterators.asEnumeration(collection.iterator())}. */ - public static Enumeration asEnumeration(final Iterator iterator) { + public static Enumeration asEnumeration( + final Iterator iterator) { checkNotNull(iterator); return new Enumeration() { @Override @@ -1135,6 +1177,18 @@ public E next() { E result = peekedElement; hasPeeked = false; peekedElement = null; + // The cast is safe because of the hasPeeked check. + return uncheckedCastNullableEToE(result); + } + + @SuppressWarnings("nullness") + private static E uncheckedCastNullableEToE(@Nullable E result) { + /* + * We can't use requireNonNull because `result` might be null. Specifically, it can be null + * because the iterator might contain a null element to be returned to the user. This is in + * contrast to the other way for `result` to be null, which is for the iterator not to have a + * next value computed yet. + */ return result; } @@ -1150,7 +1204,8 @@ public E peek() { peekedElement = iterator.next(); hasPeeked = true; } - return peekedElement; + // The cast is safe because of the hasPeeked check. + return uncheckedCastNullableEToE(peekedElement); } } @@ -1190,7 +1245,8 @@ public E peek() { * @return a peeking iterator backed by that iterator. Apart from the additional {@link * PeekingIterator#peek()} method, this iterator behaves exactly the same as {@code iterator}. */ - public static PeekingIterator peekingIterator(Iterator iterator) { + public static PeekingIterator peekingIterator( + Iterator iterator) { if (iterator instanceof PeekingImpl) { // Safe to cast to because PeekingImpl only uses T // covariantly (and cannot be subclassed to add non-covariant uses). @@ -1208,7 +1264,8 @@ public static PeekingIterator peekingIterator(Iterator itera * @since 10.0 */ @Deprecated - public static PeekingIterator peekingIterator(PeekingIterator iterator) { + public static PeekingIterator peekingIterator( + PeekingIterator iterator) { return checkNotNull(iterator); } @@ -1297,7 +1354,7 @@ private static class ConcatenatedIterator implements Iterator { * operation O(1). */ - private Iterator> topMetaIterator; + private @Nullable Iterator> topMetaIterator; // Only becomes nonnull if we encounter nested concatenations. private @Nullable Deque>> metaIterators; @@ -1369,7 +1426,9 @@ public T next() { @Override public void remove() { - CollectPreconditions.checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } toRemove.remove(); toRemove = null; } diff --git a/guava/src/com/google/common/collect/JdkBackedImmutableBiMap.java b/guava/src/com/google/common/collect/JdkBackedImmutableBiMap.java index 6fceaa91f2bf..ae15b8b92601 100644 --- a/guava/src/com/google/common/collect/JdkBackedImmutableBiMap.java +++ b/guava/src/com/google/common/collect/JdkBackedImmutableBiMap.java @@ -21,6 +21,7 @@ import com.google.j2objc.annotations.RetainedWith; import com.google.j2objc.annotations.WeakOuter; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -28,9 +29,11 @@ * protecting against hash flooding. */ @GwtCompatible(emulated = true) -final class JdkBackedImmutableBiMap extends ImmutableBiMap { +final class JdkBackedImmutableBiMap + extends ImmutableBiMap { @VisibleForTesting - static ImmutableBiMap create(int n, Entry[] entryArray) { + static ImmutableBiMap create( + int n, Entry[] entryArray) { Map forwardDelegate = Maps.newHashMapWithExpectedSize(n); Map backwardDelegate = Maps.newHashMapWithExpectedSize(n); for (int i = 0; i < n; i++) { @@ -65,7 +68,7 @@ public int size() { return entries.size(); } - @LazyInit @RetainedWith private transient JdkBackedImmutableBiMap inverse; + @LazyInit @RetainedWith private transient @Nullable JdkBackedImmutableBiMap inverse; @Override public ImmutableBiMap inverse() { @@ -100,7 +103,7 @@ public int size() { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { return forwardDelegate.get(key); } diff --git a/guava/src/com/google/common/collect/JdkBackedImmutableMap.java b/guava/src/com/google/common/collect/JdkBackedImmutableMap.java index ffbd1892aaa7..8465677b71b2 100644 --- a/guava/src/com/google/common/collect/JdkBackedImmutableMap.java +++ b/guava/src/com/google/common/collect/JdkBackedImmutableMap.java @@ -22,6 +22,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Map; import java.util.function.BiConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -29,13 +30,15 @@ * hash flooding. */ @GwtCompatible(emulated = true) -final class JdkBackedImmutableMap extends ImmutableMap { +final class JdkBackedImmutableMap + extends ImmutableMap { /** * Creates an {@code ImmutableMap} backed by a JDK HashMap. Used when probable hash flooding is * detected. This implementation may replace the entries in entryArray with its own entry objects * (though they will have the same key/value contents), and will take ownership of entryArray. */ - static ImmutableMap create(int n, Entry[] entryArray) { + static ImmutableMap create( + int n, Entry[] entryArray) { Map delegateMap = Maps.newHashMapWithExpectedSize(n); for (int i = 0; i < n; i++) { entryArray[i] = makeImmutable(entryArray[i]); @@ -61,7 +64,7 @@ public int size() { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { return delegateMap.get(key); } diff --git a/guava/src/com/google/common/collect/JdkBackedImmutableMultiset.java b/guava/src/com/google/common/collect/JdkBackedImmutableMultiset.java index f2f196b6b3fa..7fe7b74b30ab 100644 --- a/guava/src/com/google/common/collect/JdkBackedImmutableMultiset.java +++ b/guava/src/com/google/common/collect/JdkBackedImmutableMultiset.java @@ -20,6 +20,7 @@ import com.google.common.primitives.Ints; import java.util.Collection; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -29,12 +30,13 @@ * @author Louis Wasserman */ @GwtCompatible -final class JdkBackedImmutableMultiset extends ImmutableMultiset { +final class JdkBackedImmutableMultiset extends ImmutableMultiset { private final Map delegateMap; private final ImmutableList> entries; private final long size; - static ImmutableMultiset create(Collection> entries) { + static ImmutableMultiset create( + Collection> entries) { @SuppressWarnings("unchecked") Entry[] entriesArray = entries.toArray(new Entry[0]); Map delegateMap = Maps.newHashMapWithExpectedSize(entriesArray.length); @@ -65,7 +67,7 @@ public int count(@Nullable Object element) { return delegateMap.getOrDefault(element, 0); } - private transient ImmutableSet elementSet; + private transient @Nullable ImmutableSet elementSet; @Override public ImmutableSet elementSet() { diff --git a/guava/src/com/google/common/collect/JdkBackedImmutableSet.java b/guava/src/com/google/common/collect/JdkBackedImmutableSet.java index fa2c615e2ca8..1aa359dccf44 100644 --- a/guava/src/com/google/common/collect/JdkBackedImmutableSet.java +++ b/guava/src/com/google/common/collect/JdkBackedImmutableSet.java @@ -16,6 +16,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -26,7 +27,7 @@ * @author Louis Wasserman */ @GwtCompatible(serializable = true) -final class JdkBackedImmutableSet extends IndexedImmutableSet { +final class JdkBackedImmutableSet extends IndexedImmutableSet { private final Set delegate; private final ImmutableList delegateList; diff --git a/guava/src/com/google/common/collect/LexicographicalOrdering.java b/guava/src/com/google/common/collect/LexicographicalOrdering.java index 5e00eb439e4e..1e163c50d8f1 100644 --- a/guava/src/com/google/common/collect/LexicographicalOrdering.java +++ b/guava/src/com/google/common/collect/LexicographicalOrdering.java @@ -24,7 +24,8 @@ /** An ordering which sorts iterables by comparing corresponding elements pairwise. */ @GwtCompatible(serializable = true) -final class LexicographicalOrdering extends Ordering> implements Serializable { +final class LexicographicalOrdering extends Ordering> + implements Serializable { final Comparator elementOrder; LexicographicalOrdering(Comparator elementOrder) { @@ -56,7 +57,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof LexicographicalOrdering) { - LexicographicalOrdering that = (LexicographicalOrdering) object; + LexicographicalOrdering that = + (LexicographicalOrdering) object; return this.elementOrder.equals(that.elementOrder); } return false; diff --git a/guava/src/com/google/common/collect/LinkedHashMultimap.java b/guava/src/com/google/common/collect/LinkedHashMultimap.java index f4a1c65eb15d..ba0e2b5d445a 100644 --- a/guava/src/com/google/common/collect/LinkedHashMultimap.java +++ b/guava/src/com/google/common/collect/LinkedHashMultimap.java @@ -18,7 +18,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -82,7 +83,8 @@ public final class LinkedHashMultimap extends LinkedHashMultimapGwtSerializationDependencies { /** Creates a new, empty {@code LinkedHashMultimap} with the default initial capacities. */ - public static LinkedHashMultimap create() { + public static + LinkedHashMultimap create() { return new LinkedHashMultimap<>(DEFAULT_KEY_CAPACITY, DEFAULT_VALUE_SET_CAPACITY); } @@ -95,7 +97,8 @@ public static LinkedHashMultimap create() { * @throws IllegalArgumentException if {@code expectedKeys} or {@code expectedValuesPerKey} is * negative */ - public static LinkedHashMultimap create(int expectedKeys, int expectedValuesPerKey) { + public static + LinkedHashMultimap create(int expectedKeys, int expectedValuesPerKey) { return new LinkedHashMultimap<>( Maps.capacity(expectedKeys), Maps.capacity(expectedValuesPerKey)); } @@ -108,8 +111,8 @@ public static LinkedHashMultimap create(int expectedKeys, int expec * * @param multimap the multimap whose contents are copied to this multimap */ - public static LinkedHashMultimap create( - Multimap multimap) { + public static + LinkedHashMultimap create(Multimap multimap) { LinkedHashMultimap result = create(multimap.keySet().size(), DEFAULT_VALUE_SET_CAPACITY); result.putAll(multimap); return result; @@ -125,21 +128,25 @@ private interface ValueSetLink { void setSuccessorInValueSet(ValueSetLink entry); } - private static void succeedsInValueSet(ValueSetLink pred, ValueSetLink succ) { + private static void succeedsInValueSet( + ValueSetLink pred, ValueSetLink succ) { pred.setSuccessorInValueSet(succ); succ.setPredecessorInValueSet(pred); } - private static void succeedsInMultimap(ValueEntry pred, ValueEntry succ) { + private static void succeedsInMultimap( + ValueEntry pred, ValueEntry succ) { pred.setSuccessorInMultimap(succ); succ.setPredecessorInMultimap(pred); } - private static void deleteFromValueSet(ValueSetLink entry) { + private static void deleteFromValueSet( + ValueSetLink entry) { succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet()); } - private static void deleteFromMultimap(ValueEntry entry) { + private static void deleteFromMultimap( + ValueEntry entry) { succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap()); } @@ -150,22 +157,28 @@ private static void deleteFromMultimap(ValueEntry entry) { * whole. */ @VisibleForTesting - static final class ValueEntry extends ImmutableEntry implements ValueSetLink { + static final class ValueEntry + extends ImmutableEntry implements ValueSetLink { final int smearedValueHash; @Nullable ValueEntry nextInValueBucket; - @Nullable ValueSetLink predecessorInValueSet; - @Nullable ValueSetLink successorInValueSet; + /* + * The 4 predecessor/successor fields below are null after construction, but we always call + * succeedsIn*() to initialize them immediately thereafter. + * + * The only exception is multimapHeaderEntry, whose *InValueSet fields are never set. That's OK + * as long as we continue to be careful not to try delete them or iterate past them. + */ - @Nullable ValueEntry predecessorInMultimap; - @Nullable ValueEntry successorInMultimap; + ValueSetLink predecessorInValueSet; + ValueSetLink successorInValueSet; - ValueEntry( - @Nullable K key, - @Nullable V value, - int smearedValueHash, - @Nullable ValueEntry nextInValueBucket) { + ValueEntry predecessorInMultimap; + ValueEntry successorInMultimap; + + @SuppressWarnings("nullness") // See the comment on the fields. + ValueEntry(K key, V value, int smearedValueHash, @Nullable ValueEntry nextInValueBucket) { super(key, value); this.smearedValueHash = smearedValueHash; this.nextInValueBucket = nextInValueBucket; @@ -224,7 +237,8 @@ private LinkedHashMultimap(int keyCapacity, int valueSetCapacity) { checkNonnegative(valueSetCapacity, "expectedValuesPerKey"); this.valueSetCapacity = valueSetCapacity; - this.multimapHeaderEntry = new ValueEntry<>(null, null, 0, null); + // We are careful never to read the key or value of the header entry. + this.multimapHeaderEntry = new ValueEntry<>(unsafeNull(), unsafeNull(), 0, null); succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry); } @@ -263,7 +277,7 @@ Collection createCollection(K key) { */ @CanIgnoreReturnValue @Override - public Set replaceValues(@Nullable K key, Iterable values) { + public Set replaceValues(K key, Iterable values) { return super.replaceValues(key, values); } @@ -319,7 +333,7 @@ final class ValueSet extends Sets.ImprovedAbstractSet implements ValueSetLink */ private final K key; - @VisibleForTesting ValueEntry[] hashTable; + @VisibleForTesting @Nullable ValueEntry[] hashTable; private int size = 0; private int modCount = 0; @@ -328,6 +342,8 @@ final class ValueSet extends Sets.ImprovedAbstractSet implements ValueSetLink private ValueSetLink firstEntry; private ValueSetLink lastEntry; + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) ValueSet(K key, int expectedValues) { this.key = key; this.firstEntry = this; @@ -336,7 +352,8 @@ final class ValueSet extends Sets.ImprovedAbstractSet implements ValueSetLink int tableSize = Hashing.closedTableSize(expectedValues, VALUE_SET_LOAD_FACTOR); @SuppressWarnings("unchecked") - ValueEntry[] hashTable = new ValueEntry[tableSize]; + @Nullable + ValueEntry[] hashTable = new @Nullable ValueEntry[tableSize]; this.hashTable = hashTable; } @@ -398,7 +415,9 @@ public V next() { @Override public void remove() { checkForComodification(); - checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } ValueSet.this.remove(toRemove.getValue()); expectedModCount = modCount; toRemove = null; @@ -435,7 +454,7 @@ public boolean contains(@Nullable Object o) { } @Override - public boolean add(@Nullable V value) { + public boolean add(V value) { int smearedHash = Hashing.smearedHash(value); int bucket = smearedHash & mask(); ValueEntry rowHead = hashTable[bucket]; @@ -539,7 +558,9 @@ public Entry next() { @Override public void remove() { - checkRemove(toRemove != null); + if (toRemove == null) { + throw noCallsToNextSinceLastRemove(); + } LinkedHashMultimap.this.remove(toRemove.getKey(), toRemove.getValue()); toRemove = null; } @@ -588,7 +609,8 @@ private void writeObject(ObjectOutputStream stream) throws IOException { @GwtIncompatible // java.io.ObjectInputStream private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); - multimapHeaderEntry = new ValueEntry<>(null, null, 0, null); + // We are careful never to read the key or value of the header entry. + multimapHeaderEntry = new ValueEntry<>(unsafeNull(), unsafeNull(), 0, null); succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry); valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY; int distinctKeys = stream.readInt(); @@ -604,11 +626,17 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo K key = (K) stream.readObject(); @SuppressWarnings("unchecked") V value = (V) stream.readObject(); - map.get(key).add(value); + // requireNonNull is safe for a properly serialized multimap. + requireNonNull(map.get(key)).add(value); } setMap(map); } + @SuppressWarnings("nullness") + private static T unsafeNull() { + return null; + } + @GwtIncompatible // java serialization not supported private static final long serialVersionUID = 1; } diff --git a/guava/src/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java b/guava/src/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java index bb4a2e490e45..1cd7c7b13a38 100644 --- a/guava/src/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java +++ b/guava/src/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Collection; import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A dummy superclass to support GWT serialization of the element types of a {@link @@ -30,7 +31,8 @@ *

    TODO(cpovirk): Consider applying this subclass approach to our other types. */ @GwtCompatible(emulated = true) -abstract class LinkedHashMultimapGwtSerializationDependencies +abstract class LinkedHashMultimapGwtSerializationDependencies< + K, V> extends AbstractSetMultimap { LinkedHashMultimapGwtSerializationDependencies(Map> map) { super(map); diff --git a/guava/src/com/google/common/collect/LinkedHashMultiset.java b/guava/src/com/google/common/collect/LinkedHashMultiset.java index 87c2ad24a745..9718f27488df 100644 --- a/guava/src/com/google/common/collect/LinkedHashMultiset.java +++ b/guava/src/com/google/common/collect/LinkedHashMultiset.java @@ -22,6 +22,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.LinkedHashMap; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@code Multiset} implementation with predictable iteration order. Its iterator orders elements @@ -39,7 +40,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public final class LinkedHashMultiset extends AbstractMapBasedMultiset { +public final class LinkedHashMultiset + extends AbstractMapBasedMultiset { /** Creates a new, empty {@code LinkedHashMultiset} using the default initial capacity. */ public static LinkedHashMultiset create() { @@ -64,7 +66,8 @@ public static LinkedHashMultiset create(int distinctElements) { * * @param elements the elements that the multiset should contain */ - public static LinkedHashMultiset create(Iterable elements) { + public static LinkedHashMultiset create( + Iterable elements) { LinkedHashMultiset multiset = create(Multisets.inferDistinctElements(elements)); Iterables.addAll(multiset, elements); return multiset; diff --git a/guava/src/com/google/common/collect/LinkedListMultimap.java b/guava/src/com/google/common/collect/LinkedListMultimap.java index b93a9a30cbfc..b4b975e836a6 100644 --- a/guava/src/com/google/common/collect/LinkedListMultimap.java +++ b/guava/src/com/google/common/collect/LinkedListMultimap.java @@ -18,9 +18,9 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndex; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; import static java.util.Collections.unmodifiableList; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -96,8 +96,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public class LinkedListMultimap extends AbstractMultimap - implements ListMultimap, Serializable { +public class LinkedListMultimap + extends AbstractMultimap implements ListMultimap, Serializable { /* * Order is maintained using a linked list containing all key-value pairs. In * addition, a series of disjoint linked lists of "siblings", each containing @@ -105,15 +105,16 @@ public class LinkedListMultimap extends AbstractMultimap * ValueForKeyIterator} in constant time. */ - private static final class Node extends AbstractMapEntry { - final @Nullable K key; - @Nullable V value; + private static final class Node + extends AbstractMapEntry { + final K key; + V value; @Nullable Node next; // the next node (with any key) @Nullable Node previous; // the previous node (with any key) @Nullable Node nextSibling; // the next node with the same key @Nullable Node previousSibling; // the previous node with the same key - Node(@Nullable K key, @Nullable V value) { + Node(K key, V value) { this.key = key; this.value = value; } @@ -129,7 +130,7 @@ public V getValue() { } @Override - public V setValue(@Nullable V newValue) { + public V setValue(V newValue) { V result = value; this.value = newValue; return result; @@ -163,7 +164,8 @@ private static class KeyList { private transient int modCount; /** Creates a new, empty {@code LinkedListMultimap} with the default initial capacity. */ - public static LinkedListMultimap create() { + public static + LinkedListMultimap create() { return new LinkedListMultimap<>(); } @@ -174,7 +176,8 @@ public static LinkedListMultimap create() { * @param expectedKeys the expected number of distinct keys * @throws IllegalArgumentException if {@code expectedKeys} is negative */ - public static LinkedListMultimap create(int expectedKeys) { + public static + LinkedListMultimap create(int expectedKeys) { return new LinkedListMultimap<>(expectedKeys); } @@ -185,8 +188,8 @@ public static LinkedListMultimap create(int expectedKeys) { * * @param multimap the multimap whose contents are copied to this multimap */ - public static LinkedListMultimap create( - Multimap multimap) { + public static + LinkedListMultimap create(Multimap multimap) { return new LinkedListMultimap<>(multimap); } @@ -209,14 +212,15 @@ private LinkedListMultimap(Multimap multimap) { * is specified, it MUST be for an node for the same {@code key}! */ @CanIgnoreReturnValue - private Node addNode(@Nullable K key, @Nullable V value, @Nullable Node nextSibling) { + private Node addNode(K key, V value, @Nullable Node nextSibling) { Node node = new Node<>(key, value); if (head == null) { // empty list head = tail = node; keyToKeyList.put(key, new KeyList(node)); modCount++; } else if (nextSibling == null) { // non-empty list, add to tail - tail.next = node; + // requireNonNull is safe because the list is non-empty. + requireNonNull(tail).next = node; node.previous = tail; tail = node; KeyList keyList = keyToKeyList.get(key); @@ -231,14 +235,19 @@ private Node addNode(@Nullable K key, @Nullable V value, @Nullable Node keyList = keyToKeyList.get(key); + /* + * requireNonNull is safe as long as callers pass a nextSibling that (a) has the same key and + * (b) is present in the multimap. (And they do, except maybe in case of concurrent + * modification, in which case all bets are off.) + */ + KeyList keyList = requireNonNull(keyToKeyList.get(key)); keyList.count++; node.previous = nextSibling.previous; node.previousSibling = nextSibling.previousSibling; node.next = nextSibling; node.nextSibling = nextSibling; if (nextSibling.previousSibling == null) { // nextSibling was key head - keyToKeyList.get(key).head = node; + keyList.head = node; } else { nextSibling.previousSibling.nextSibling = node; } @@ -270,21 +279,29 @@ private void removeNode(Node node) { tail = node.previous; } if (node.previousSibling == null && node.nextSibling == null) { - KeyList keyList = keyToKeyList.remove(node.key); + /* + * requireNonNull is safe as long as we call removeNode only for nodes that are still in the + * Multimap. This should be the case (except in case of concurrent modification, when all bets + * are off). + */ + KeyList keyList = requireNonNull(keyToKeyList.remove(node.key)); keyList.count = 0; modCount++; } else { - KeyList keyList = keyToKeyList.get(node.key); + // requireNonNull should be safe. See the comment in the branch above. + KeyList keyList = requireNonNull(keyToKeyList.get(node.key)); keyList.count--; if (node.previousSibling == null) { - keyList.head = node.nextSibling; + // requireNonNull is safe because we checked that not *both* siblings were null. + keyList.head = requireNonNull(node.nextSibling); } else { node.previousSibling.nextSibling = node.nextSibling; } if (node.nextSibling == null) { - keyList.tail = node.previousSibling; + // requireNonNull is safe because we checked that not *both* siblings were null. + keyList.tail = requireNonNull(node.previousSibling); } else { node.nextSibling.previousSibling = node.previousSibling; } @@ -293,17 +310,10 @@ private void removeNode(Node node) { } /** Removes all nodes for the specified key. */ - private void removeAllNodes(@Nullable Object key) { + private void removeAllNodes(K key) { Iterators.clear(new ValueForKeyIterator(key)); } - /** Helper method for verifying that an iterator element is present. */ - private static void checkElement(@Nullable Object node) { - if (node == null) { - throw new NoSuchElementException(); - } - } - /** An {@code Iterator} over all nodes. */ private class NodeIterator implements ListIterator> { int nextIndex; @@ -346,7 +356,9 @@ public boolean hasNext() { @Override public Node next() { checkForConcurrentModification(); - checkElement(next); + if (next == null) { + throw new NoSuchElementException(); + } previous = current = next; next = next.next; nextIndex++; @@ -356,7 +368,9 @@ public Node next() { @Override public void remove() { checkForConcurrentModification(); - checkRemove(current != null); + if (current == null) { + throw noCallsToNextSinceLastRemove(); + } if (current != next) { // after call to next() previous = current.previous; nextIndex--; @@ -378,7 +392,9 @@ public boolean hasPrevious() { @Override public Node previous() { checkForConcurrentModification(); - checkElement(previous); + if (previous == null) { + throw new NoSuchElementException(); + } next = current = previous; previous = previous.previous; nextIndex--; @@ -406,7 +422,9 @@ public void add(Entry e) { } void setValue(V value) { - checkState(current != null); + if (current == null) { + throw new IllegalStateException(); + } current.value = value; } } @@ -414,7 +432,7 @@ void setValue(V value) { /** An {@code Iterator} over distinct keys in key head order. */ private class DistinctKeyIterator implements Iterator { final Set seenKeys = Sets.newHashSetWithExpectedSize(keySet().size()); - Node next = head; + @Nullable Node next = head; @Nullable Node current; int expectedModCount = modCount; @@ -433,7 +451,9 @@ public boolean hasNext() { @Override public K next() { checkForConcurrentModification(); - checkElement(next); + if (next == null) { + throw new NoSuchElementException(); + } current = next; seenKeys.add(current.key); do { // skip ahead to next unseen key @@ -445,7 +465,9 @@ public K next() { @Override public void remove() { checkForConcurrentModification(); - checkRemove(current != null); + if (current == null) { + throw noCallsToNextSinceLastRemove(); + } removeAllNodes(current.key); current = null; expectedModCount = modCount; @@ -454,14 +476,14 @@ public void remove() { /** A {@code ListIterator} over values for a specified key. */ private class ValueForKeyIterator implements ListIterator { - final @Nullable Object key; + final K key; int nextIndex; @Nullable Node next; @Nullable Node current; @Nullable Node previous; /** Constructs a new iterator over all values for the specified key. */ - ValueForKeyIterator(@Nullable Object key) { + ValueForKeyIterator(K key) { this.key = key; KeyList keyList = keyToKeyList.get(key); next = (keyList == null) ? null : keyList.head; @@ -475,7 +497,7 @@ private class ValueForKeyIterator implements ListIterator { * * @throws IndexOutOfBoundsException if index is invalid */ - public ValueForKeyIterator(@Nullable Object key, int index) { + public ValueForKeyIterator(K key, int index) { KeyList keyList = keyToKeyList.get(key); int size = (keyList == null) ? 0 : keyList.count; checkPositionIndex(index, size); @@ -503,7 +525,9 @@ public boolean hasNext() { @CanIgnoreReturnValue @Override public V next() { - checkElement(next); + if (next == null) { + throw new NoSuchElementException(); + } previous = current = next; next = next.nextSibling; nextIndex++; @@ -518,7 +542,9 @@ public boolean hasPrevious() { @CanIgnoreReturnValue @Override public V previous() { - checkElement(previous); + if (previous == null) { + throw new NoSuchElementException(); + } next = current = previous; previous = previous.previousSibling; nextIndex--; @@ -537,7 +563,9 @@ public int previousIndex() { @Override public void remove() { - checkRemove(current != null); + if (current == null) { + throw noCallsToNextSinceLastRemove(); + } if (current != next) { // after call to next() previous = current.previousSibling; nextIndex--; @@ -550,14 +578,15 @@ public void remove() { @Override public void set(V value) { - checkState(current != null); + if (current == null) { + throw new IllegalStateException(); + } current.value = value; } @Override - @SuppressWarnings("unchecked") public void add(V value) { - previous = addNode((K) key, value, next); + previous = addNode(key, value, next); nextIndex++; current = null; } @@ -596,7 +625,7 @@ public boolean containsValue(@Nullable Object value) { */ @CanIgnoreReturnValue @Override - public boolean put(@Nullable K key, @Nullable V value) { + public boolean put(K key, V value) { addNode(key, value, null); return true; } @@ -613,7 +642,7 @@ public boolean put(@Nullable K key, @Nullable V value) { */ @CanIgnoreReturnValue @Override - public List replaceValues(@Nullable K key, Iterable values) { + public List replaceValues(K key, Iterable values) { List oldValues = getCopy(key); ListIterator keyValues = new ValueForKeyIterator(key); Iterator newValues = values.iterator(); @@ -638,7 +667,7 @@ public List replaceValues(@Nullable K key, Iterable values) { return oldValues; } - private List getCopy(@Nullable Object key) { + private List getCopy(K key) { return unmodifiableList(Lists.newArrayList(new ValueForKeyIterator(key))); } @@ -650,8 +679,15 @@ private List getCopy(@Nullable Object key) { @CanIgnoreReturnValue @Override public List removeAll(@Nullable Object key) { - List oldValues = getCopy(key); - removeAllNodes(key); + /* + * Safe because all we do is remove values for the key, not add them. (If we wanted to call + * getCopy and removeAllNodes only with a true K, then we could check containsKey first. But + * that check wouldn't eliminate the warnings.) + */ + @SuppressWarnings({"unchecked", "nullness"}) + K castKey = (K) key; + List oldValues = getCopy(castKey); + removeAllNodes(castKey); return oldValues; } @@ -676,7 +712,7 @@ public void clear() { *

    The returned list is not serializable and does not have random access. */ @Override - public List get(final @Nullable K key) { + public List get(final K key) { return new AbstractSequentialList() { @Override public int size() { @@ -706,12 +742,12 @@ public Iterator iterator() { } @Override - public boolean contains(Object key) { // for performance + public boolean contains(@Nullable Object key) { // for performance return containsKey(key); } @Override - public boolean remove(Object o) { // for performance + public boolean remove(@Nullable Object o) { // for performance return !LinkedListMultimap.this.removeAll(o).isEmpty(); } } diff --git a/guava/src/com/google/common/collect/ListMultimap.java b/guava/src/com/google/common/collect/ListMultimap.java index 967c9a0c403c..3d11fcfa6d5a 100644 --- a/guava/src/com/google/common/collect/ListMultimap.java +++ b/guava/src/com/google/common/collect/ListMultimap.java @@ -40,7 +40,8 @@ * @since 2.0 */ @GwtCompatible -public interface ListMultimap extends Multimap { +public interface ListMultimap + extends Multimap { /** * {@inheritDoc} * @@ -49,7 +50,7 @@ public interface ListMultimap extends Multimap { * the {@link Multimap} interface. */ @Override - List get(@Nullable K key); + List get(K key); /** * {@inheritDoc} diff --git a/guava/src/com/google/common/collect/Lists.java b/guava/src/com/google/common/collect/Lists.java index b0b37102a5af..f8f860cdf9e1 100644 --- a/guava/src/com/google/common/collect/Lists.java +++ b/guava/src/com/google/common/collect/Lists.java @@ -49,6 +49,7 @@ import java.util.RandomAccess; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -122,7 +123,8 @@ public static ArrayList newArrayList(E... elements) { * syntax. */ @GwtCompatible(serializable = true) - public static ArrayList newArrayList(Iterable elements) { + public static ArrayList newArrayList( + Iterable elements) { checkNotNull(elements); // for GWT // Let ArrayList's sizing logic work, if possible return (elements instanceof Collection) @@ -138,7 +140,8 @@ public static ArrayList newArrayList(Iterable elements) { * ImmutableList#copyOf(Iterator)} instead. */ @GwtCompatible(serializable = true) - public static ArrayList newArrayList(Iterator elements) { + public static ArrayList newArrayList( + Iterator elements) { ArrayList list = newArrayList(); Iterators.addAll(list, elements); return list; @@ -169,7 +172,8 @@ static int computeArrayListCapacity(int arraySize) { * @throws IllegalArgumentException if {@code initialArraySize} is negative */ @GwtCompatible(serializable = true) - public static ArrayList newArrayListWithCapacity(int initialArraySize) { + public static ArrayList newArrayListWithCapacity( + int initialArraySize) { checkNonnegative(initialArraySize, "initialArraySize"); // for GWT. return new ArrayList<>(initialArraySize); } @@ -188,7 +192,8 @@ public static ArrayList newArrayListWithCapacity(int initialArraySize) { * @throws IllegalArgumentException if {@code estimatedSize} is negative */ @GwtCompatible(serializable = true) - public static ArrayList newArrayListWithExpectedSize(int estimatedSize) { + public static ArrayList newArrayListWithExpectedSize( + int estimatedSize) { return new ArrayList<>(computeArrayListCapacity(estimatedSize)); } @@ -232,7 +237,8 @@ public static LinkedList newLinkedList() { * syntax. */ @GwtCompatible(serializable = true) - public static LinkedList newLinkedList(Iterable elements) { + public static LinkedList newLinkedList( + Iterable elements) { LinkedList list = newLinkedList(); Iterables.addAll(list, elements); return list; @@ -283,7 +289,7 @@ public static CopyOnWriteArrayList newCopyOnWriteArrayList( * @param rest an array of additional elements, possibly empty * @return an unmodifiable list containing the specified elements */ - public static List asList(@Nullable E first, E[] rest) { + public static List asList(E first, E[] rest) { return new OnePlusArrayList<>(first, rest); } @@ -303,17 +309,17 @@ public static List asList(@Nullable E first, E[] rest) { * @param rest an array of additional elements, possibly empty * @return an unmodifiable list containing the specified elements */ - public static List asList(@Nullable E first, @Nullable E second, E[] rest) { + public static List asList(E first, E second, E[] rest) { return new TwoPlusArrayList<>(first, second, rest); } /** @see Lists#asList(Object, Object[]) */ private static class OnePlusArrayList extends AbstractList implements Serializable, RandomAccess { - final @Nullable E first; + final E first; final E[] rest; - OnePlusArrayList(@Nullable E first, E[] rest) { + OnePlusArrayList(E first, E[] rest) { this.first = first; this.rest = checkNotNull(rest); } @@ -336,11 +342,11 @@ public E get(int index) { /** @see Lists#asList(Object, Object, Object[]) */ private static class TwoPlusArrayList extends AbstractList implements Serializable, RandomAccess { - final @Nullable E first; - final @Nullable E second; + final E first; + final E second; final E[] rest; - TwoPlusArrayList(@Nullable E first, @Nullable E second, E[] rest) { + TwoPlusArrayList(E first, E second, E[] rest) { this.first = first; this.second = second; this.rest = checkNotNull(rest); @@ -422,7 +428,8 @@ public E get(int index) { * a provided list is null * @since 19.0 */ - public static List> cartesianProduct(List> lists) { + public static List> cartesianProduct( + List> lists) { return CartesianList.create(lists); } @@ -481,7 +488,8 @@ public static List> cartesianProduct(List List> cartesianProduct(List... lists) { + public static List> cartesianProduct( + List... lists) { return cartesianProduct(Arrays.asList(lists)); } @@ -529,8 +537,9 @@ public static List transform( * * @see Lists#transform */ - private static class TransformingSequentialList extends AbstractSequentialList - implements Serializable { + private static class TransformingSequentialList< + F, T> + extends AbstractSequentialList implements Serializable { final List fromList; final Function function; @@ -579,8 +588,9 @@ public boolean removeIf(Predicate filter) { * * @see Lists#transform */ - private static class TransformingRandomAccessList extends AbstractList - implements RandomAccess, Serializable { + private static class TransformingRandomAccessList< + F, T> + extends AbstractList implements RandomAccess, Serializable { final List fromList; final Function function; @@ -689,7 +699,8 @@ public boolean isEmpty() { } } - private static class RandomAccessPartition extends Partition implements RandomAccess { + private static class RandomAccessPartition extends Partition + implements RandomAccess { RandomAccessPartition(List list, int size) { super(list, size); } @@ -826,7 +837,7 @@ private int reversePosition(int index) { } @Override - public void add(int index, @Nullable T element) { + public void add(int index, T element) { forwardList.add(reversePosition(index), element); } @@ -846,7 +857,7 @@ protected void removeRange(int fromIndex, int toIndex) { } @Override - public T set(int index, @Nullable T element) { + public T set(int index, T element) { return forwardList.set(reverseIndex(index), element); } @@ -940,7 +951,8 @@ public void set(T e) { } } - private static class RandomAccessReverseList extends ReverseList implements RandomAccess { + private static class RandomAccessReverseList extends ReverseList + implements RandomAccess { RandomAccessReverseList(List forwardList) { super(forwardList); } @@ -986,7 +998,8 @@ static boolean equalsImpl(List thisList, @Nullable Object other) { } /** An implementation of {@link List#addAll(int, Collection)}. */ - static boolean addAllImpl(List list, int index, Iterable elements) { + static boolean addAllImpl( + List list, int index, Iterable elements) { boolean changed = false; ListIterator listIterator = list.listIterator(index); for (E e : elements) { @@ -1011,7 +1024,8 @@ static int indexOfImpl(List list, @Nullable Object element) { } } - private static int indexOfRandomAccess(List list, @Nullable Object element) { + private static int indexOfRandomAccess( + List list, @Nullable Object element) { int size = list.size(); if (element == null) { for (int i = 0; i < size; i++) { @@ -1044,7 +1058,8 @@ static int lastIndexOfImpl(List list, @Nullable Object element) { } } - private static int lastIndexOfRandomAccess(List list, @Nullable Object element) { + private static int lastIndexOfRandomAccess( + List list, @Nullable Object element) { if (element == null) { for (int i = list.size() - 1; i >= 0; i--) { if (list.get(i) == null) { @@ -1067,7 +1082,8 @@ static ListIterator listIteratorImpl(List list, int index) { } /** An implementation of {@link List#subList(int, int)}. */ - static List subListImpl(final List list, int fromIndex, int toIndex) { + static List subListImpl( + final List list, int fromIndex, int toIndex) { List wrapper; if (list instanceof RandomAccess) { wrapper = @@ -1126,7 +1142,7 @@ public E set(int index, E element) { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return backingList.contains(o); } @@ -1136,8 +1152,8 @@ public int size() { } } - private static class RandomAccessListWrapper extends AbstractListWrapper - implements RandomAccess { + private static class RandomAccessListWrapper + extends AbstractListWrapper implements RandomAccess { RandomAccessListWrapper(List backingList) { super(backingList); } diff --git a/guava/src/com/google/common/collect/MapDifference.java b/guava/src/com/google/common/collect/MapDifference.java index 066aebf02496..760473f5e507 100644 --- a/guava/src/com/google/common/collect/MapDifference.java +++ b/guava/src/com/google/common/collect/MapDifference.java @@ -17,7 +17,6 @@ package com.google.common.collect; import com.google.common.annotations.GwtCompatible; -import com.google.errorprone.annotations.DoNotMock; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; @@ -27,7 +26,6 @@ * @author Kevin Bourrillion * @since 2.0 */ -@DoNotMock("Use Maps.difference") @GwtCompatible public interface MapDifference { /** @@ -86,7 +84,6 @@ public interface MapDifference { * * @since 2.0 */ - @DoNotMock("Use Maps.difference") interface ValueDifference { /** Returns the value from the left map (possibly null). */ V leftValue(); diff --git a/guava/src/com/google/common/collect/MapMaker.java b/guava/src/com/google/common/collect/MapMaker.java index 1cbe4a42c7f9..c64e519d8fac 100644 --- a/guava/src/com/google/common/collect/MapMaker.java +++ b/guava/src/com/google/common/collect/MapMaker.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -276,7 +277,7 @@ Strength getValueStrength() { * * @return a serializable concurrent map having the requested features */ - public ConcurrentMap makeMap() { + public ConcurrentMap makeMap() { if (!useCustomMap) { return new ConcurrentHashMap<>(getInitialCapacity(), 0.75f, getConcurrencyLevel()); } diff --git a/guava/src/com/google/common/collect/MapMakerInternalMap.java b/guava/src/com/google/common/collect/MapMakerInternalMap.java index 6cf5a26a309c..f4a13edd3da7 100644 --- a/guava/src/com/google/common/collect/MapMakerInternalMap.java +++ b/guava/src/com/google/common/collect/MapMakerInternalMap.java @@ -15,7 +15,7 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.VisibleForTesting; @@ -47,6 +47,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.concurrent.locks.ReentrantLock; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -65,10 +66,13 @@ */ // TODO(kak/cpovirk): Consider removing @CanIgnoreReturnValue from this class. @GwtIncompatible -@SuppressWarnings("GuardedBy") // TODO(b/35466881): Fix or suppress. +@SuppressWarnings({ + "GuardedBy", // TODO(b/35466881): Fix or suppress. + "nullness", // too much effort for the payoff +}) class MapMakerInternalMap< - K, - V, + K extends @NonNull Object, + V extends @NonNull Object, E extends MapMakerInternalMap.InternalEntry, S extends MapMakerInternalMap.Segment> extends AbstractMap implements ConcurrentMap, Serializable { @@ -194,8 +198,8 @@ private MapMakerInternalMap(MapMaker builder, InternalEntryHelper en } /** Returns a fresh {@link MapMakerInternalMap} as specified by the given {@code builder}. */ - static MapMakerInternalMap, ?> create( - MapMaker builder) { + static + MapMakerInternalMap, ?> create(MapMaker builder) { if (builder.getKeyStrength() == Strength.STRONG && builder.getValueStrength() == Strength.STRONG) { return new MapMakerInternalMap<>(builder, StrongKeyStrongValueEntry.Helper.instance()); @@ -224,7 +228,7 @@ private MapMakerInternalMap(MapMaker builder, InternalEntryHelper en *

    This method is intended to only be used by the internal implementation of {@link Interners}, * since a map of dummy values is the exact use case there. */ - static + static MapMakerInternalMap, ?> createWithDummyValues( MapMaker builder) { if (builder.getKeyStrength() == Strength.STRONG @@ -278,7 +282,10 @@ Equivalence defaultEquivalence() { * @param the type of the {@link Segment} entry implementation */ interface InternalEntryHelper< - K, V, E extends InternalEntry, S extends Segment> { + K extends @NonNull Object, + V extends @NonNull Object, + E extends InternalEntry, + S extends Segment> { /** The strength of the key type in each entry. */ Strength keyStrength(); @@ -315,7 +322,8 @@ interface InternalEntryHelper< * *

    Invalid: - Collected: key/value was partially collected, but not yet cleaned up */ - interface InternalEntry> { + interface InternalEntry< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> { /** Gets the next entry in the chain. */ E getNext(); @@ -335,7 +343,8 @@ interface InternalEntry> { */ /** Base class for {@link InternalEntry} implementations for strong keys. */ - abstract static class AbstractStrongKeyEntry> + abstract static class AbstractStrongKeyEntry< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> implements InternalEntry { final K key; final int hash; @@ -364,11 +373,14 @@ public E getNext() { } /** Marker interface for {@link InternalEntry} implementations for strong values. */ - interface StrongValueEntry> + interface StrongValueEntry< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> extends InternalEntry {} /** Marker interface for {@link InternalEntry} implementations for weak values. */ - interface WeakValueEntry> extends InternalEntry { + interface WeakValueEntry< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> + extends InternalEntry { /** Gets the weak value reference held by entry. */ WeakValueReference getValueReference(); @@ -380,13 +392,13 @@ interface WeakValueEntry> extends Interna } @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value - static > + static > WeakValueReference unsetWeakValueReference() { return (WeakValueReference) UNSET_WEAK_VALUE_REFERENCE; } /** Concrete implementation of {@link InternalEntry} for strong keys and strong values. */ - static final class StrongKeyStrongValueEntry + static final class StrongKeyStrongValueEntry extends AbstractStrongKeyEntry> implements StrongValueEntry> { private volatile @Nullable V value = null; @@ -412,13 +424,13 @@ StrongKeyStrongValueEntry copy(StrongKeyStrongValueEntry newNext) { } /** Concrete implementation of {@link InternalEntryHelper} for strong keys and strong values. */ - static final class Helper + static final class Helper implements InternalEntryHelper< K, V, StrongKeyStrongValueEntry, StrongKeyStrongValueSegment> { private static final Helper INSTANCE = new Helper<>(); @SuppressWarnings("unchecked") - static Helper instance() { + static Helper instance() { return (Helper) INSTANCE; } @@ -470,7 +482,7 @@ public StrongKeyStrongValueEntry newEntry( } /** Concrete implementation of {@link InternalEntry} for strong keys and weak values. */ - static final class StrongKeyWeakValueEntry + static final class StrongKeyWeakValueEntry extends AbstractStrongKeyEntry> implements WeakValueEntry> { private volatile WeakValueReference> valueReference = @@ -509,7 +521,7 @@ public WeakValueReference> getValueReference } /** Concrete implementation of {@link InternalEntryHelper} for strong keys and weak values. */ - static final class Helper + static final class Helper implements InternalEntryHelper< K, V, StrongKeyWeakValueEntry, StrongKeyWeakValueSegment> { private static final Helper INSTANCE = new Helper<>(); @@ -567,7 +579,7 @@ public StrongKeyWeakValueEntry newEntry( } /** Concrete implementation of {@link InternalEntry} for strong keys and {@link Dummy} values. */ - static final class StrongKeyDummyValueEntry + static final class StrongKeyDummyValueEntry extends AbstractStrongKeyEntry> implements StrongValueEntry> { StrongKeyDummyValueEntry(K key, int hash, @Nullable StrongKeyDummyValueEntry next) { @@ -589,7 +601,7 @@ StrongKeyDummyValueEntry copy(StrongKeyDummyValueEntry newNext) { * Concrete implementation of {@link InternalEntryHelper} for strong keys and {@link Dummy} * values. */ - static final class Helper + static final class Helper implements InternalEntryHelper< K, Dummy, StrongKeyDummyValueEntry, StrongKeyDummyValueSegment> { private static final Helper INSTANCE = new Helper<>(); @@ -642,7 +654,8 @@ public StrongKeyDummyValueEntry newEntry( } /** Base class for {@link InternalEntry} implementations for weak keys. */ - abstract static class AbstractWeakKeyEntry> + abstract static class AbstractWeakKeyEntry< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> extends WeakReference implements InternalEntry { final int hash; final @Nullable E next; @@ -670,7 +683,7 @@ public E getNext() { } /** Concrete implementation of {@link InternalEntry} for weak keys and {@link Dummy} values. */ - static final class WeakKeyDummyValueEntry + static final class WeakKeyDummyValueEntry extends AbstractWeakKeyEntry> implements StrongValueEntry> { WeakKeyDummyValueEntry( @@ -694,7 +707,7 @@ WeakKeyDummyValueEntry copy( * Concrete implementation of {@link InternalEntryHelper} for weak keys and {@link Dummy} * values. */ - static final class Helper + static final class Helper implements InternalEntryHelper< K, Dummy, WeakKeyDummyValueEntry, WeakKeyDummyValueSegment> { private static final Helper INSTANCE = new Helper<>(); @@ -750,7 +763,7 @@ public WeakKeyDummyValueEntry newEntry( } /** Concrete implementation of {@link InternalEntry} for weak keys and strong values. */ - static final class WeakKeyStrongValueEntry + static final class WeakKeyStrongValueEntry extends AbstractWeakKeyEntry> implements StrongValueEntry> { private volatile @Nullable V value = null; @@ -778,7 +791,7 @@ WeakKeyStrongValueEntry copy( } /** Concrete implementation of {@link InternalEntryHelper} for weak keys and strong values. */ - static final class Helper + static final class Helper implements InternalEntryHelper< K, V, WeakKeyStrongValueEntry, WeakKeyStrongValueSegment> { private static final Helper INSTANCE = new Helper<>(); @@ -837,7 +850,7 @@ public WeakKeyStrongValueEntry newEntry( } /** Concrete implementation of {@link InternalEntry} for weak keys and weak values. */ - static final class WeakKeyWeakValueEntry + static final class WeakKeyWeakValueEntry extends AbstractWeakKeyEntry> implements WeakValueEntry> { private volatile WeakValueReference> valueReference = @@ -880,7 +893,7 @@ public WeakValueReference> getValueReference() } /** Concrete implementation of {@link InternalEntryHelper} for weak keys and weak values. */ - static final class Helper + static final class Helper implements InternalEntryHelper< K, V, WeakKeyWeakValueEntry, WeakKeyWeakValueSegment> { private static final Helper INSTANCE = new Helper<>(); @@ -941,7 +954,8 @@ public WeakKeyWeakValueEntry newEntry( } /** A weakly referenced value that also has a reference to its containing entry. */ - interface WeakValueReference> { + interface WeakValueReference< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> { /** * Returns the current value being referenced, or {@code null} if there is none (e.g. because * either it got collected, or {@link #clear} was called, or it wasn't set in the first place). @@ -1020,7 +1034,8 @@ public WeakValueReference copyFor( }; /** Concrete implementation of {@link WeakValueReference}. */ - static final class WeakValueReferenceImpl> + static final class WeakValueReferenceImpl< + K extends @NonNull Object, V extends @NonNull Object, E extends InternalEntry> extends WeakReference implements WeakValueReference { @Weak final E entry; @@ -1134,7 +1149,10 @@ final Segment[] newSegmentArray(int ssize) { */ @SuppressWarnings("serial") // This class is never serialized. abstract static class Segment< - K, V, E extends InternalEntry, S extends Segment> + K extends @NonNull Object, + V extends @NonNull Object, + E extends InternalEntry, + S extends Segment> extends ReentrantLock { /* @@ -1444,7 +1462,7 @@ boolean containsKey(Object key, int hash) { * MapMakerInternalMap#containsValue} directly. */ @VisibleForTesting - boolean containsValue(Object value) { + boolean containsValue(@Nullable Object value) { try { if (count != 0) { // read-volatile AtomicReferenceArray table = this.table; @@ -1931,7 +1949,8 @@ boolean removeEntryForTesting(E entry) { * Returns {@code true} if the value has been partially collected, meaning that the value is * null. */ - static > boolean isCollected(E entry) { + static > + boolean isCollected(E entry) { return entry.getValue() == null; } @@ -1991,7 +2010,8 @@ void runLockedCleanup() { } /** Concrete implementation of {@link Segment} for strong keys and strong values. */ - static final class StrongKeyStrongValueSegment + static final class StrongKeyStrongValueSegment< + K extends @NonNull Object, V extends @NonNull Object> extends Segment, StrongKeyStrongValueSegment> { StrongKeyStrongValueSegment( MapMakerInternalMap< @@ -2015,7 +2035,7 @@ public StrongKeyStrongValueEntry castForTesting(InternalEntry ent } /** Concrete implementation of {@link Segment} for strong keys and weak values. */ - static final class StrongKeyWeakValueSegment + static final class StrongKeyWeakValueSegment extends Segment, StrongKeyWeakValueSegment> { private final ReferenceQueue queueForValues = new ReferenceQueue(); @@ -2080,7 +2100,7 @@ void maybeClearReferenceQueues() { } /** Concrete implementation of {@link Segment} for strong keys and {@link Dummy} values. */ - static final class StrongKeyDummyValueSegment + static final class StrongKeyDummyValueSegment extends Segment, StrongKeyDummyValueSegment> { StrongKeyDummyValueSegment( MapMakerInternalMap, StrongKeyDummyValueSegment> @@ -2103,7 +2123,7 @@ public StrongKeyDummyValueEntry castForTesting(InternalEntry ent } /** Concrete implementation of {@link Segment} for weak keys and strong values. */ - static final class WeakKeyStrongValueSegment + static final class WeakKeyStrongValueSegment extends Segment, WeakKeyStrongValueSegment> { private final ReferenceQueue queueForKeys = new ReferenceQueue(); @@ -2143,7 +2163,7 @@ void maybeClearReferenceQueues() { } /** Concrete implementation of {@link Segment} for weak keys and weak values. */ - static final class WeakKeyWeakValueSegment + static final class WeakKeyWeakValueSegment extends Segment, WeakKeyWeakValueSegment> { private final ReferenceQueue queueForKeys = new ReferenceQueue(); private final ReferenceQueue queueForValues = new ReferenceQueue(); @@ -2214,7 +2234,7 @@ void maybeClearReferenceQueues() { } /** Concrete implementation of {@link Segment} for weak keys and {@link Dummy} values. */ - static final class WeakKeyDummyValueSegment + static final class WeakKeyDummyValueSegment extends Segment, WeakKeyDummyValueSegment> { private final ReferenceQueue queueForKeys = new ReferenceQueue(); @@ -2330,7 +2350,7 @@ public int size() { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { if (key == null) { return null; } @@ -2399,7 +2419,7 @@ public boolean containsValue(@Nullable Object value) { @CanIgnoreReturnValue @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { checkNotNull(key); checkNotNull(value); int hash = hash(key); @@ -2424,7 +2444,7 @@ public void putAll(Map m) { @CanIgnoreReturnValue @Override - public V remove(@Nullable Object key) { + public @Nullable V remove(@Nullable Object key) { if (key == null) { return null; } @@ -2456,7 +2476,7 @@ public boolean replace(K key, @Nullable V oldValue, V newValue) { @CanIgnoreReturnValue @Override - public V replace(K key, V value) { + public @Nullable V replace(K key, V value) { checkNotNull(key); checkNotNull(value); int hash = hash(key); @@ -2598,7 +2618,9 @@ WriteThroughEntry nextEntry() { @Override public void remove() { - checkRemove(lastReturned != null); + if (lastReturned == null) { + throw noCallsToNextSinceLastRemove(); + } MapMakerInternalMap.this.remove(lastReturned.getKey()); lastReturned = null; } @@ -2647,7 +2669,8 @@ public V getValue() { public boolean equals(@Nullable Object object) { // Cannot use key and value equivalence if (object instanceof Entry) { - Entry that = (Entry) object; + Entry that = + (Entry) object; return key.equals(that.getKey()) && value.equals(that.getValue()); } return false; @@ -2694,12 +2717,12 @@ public boolean isEmpty() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return MapMakerInternalMap.this.containsKey(o); } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { return MapMakerInternalMap.this.remove(o) != null; } @@ -2728,7 +2751,7 @@ public boolean isEmpty() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return MapMakerInternalMap.this.containsValue(o); } @@ -2741,11 +2764,13 @@ public void clear() { // https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508 @Override +@SuppressWarnings("nullness") public Object[] toArray() { return toArrayList(this).toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { return toArrayList(this).toArray(a); } @@ -2760,11 +2785,12 @@ public Iterator> iterator() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { if (!(o instanceof Entry)) { return false; } - Entry e = (Entry) o; + Entry e = + (Entry) o; Object key = e.getKey(); if (key == null) { return false; @@ -2775,11 +2801,12 @@ public boolean contains(Object o) { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (!(o instanceof Entry)) { return false; } - Entry e = (Entry) o; + Entry e = + (Entry) o; Object key = e.getKey(); return key != null && MapMakerInternalMap.this.remove(key, e.getValue()); } @@ -2805,11 +2832,13 @@ private abstract static class SafeToArraySet extends AbstractSet { // https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508 @Override +@SuppressWarnings("nullness") public Object[] toArray() { return toArrayList(this).toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { return toArrayList(this).toArray(a); } @@ -2840,8 +2869,9 @@ Object writeReplace() { * The actual object that gets serialized. Unfortunately, readResolve() doesn't get called when a * circular dependency is present, so the proxy must be able to behave as the map itself. */ - abstract static class AbstractSerializationProxy extends ForwardingConcurrentMap - implements Serializable { + abstract static class AbstractSerializationProxy< + K extends @NonNull Object, V extends @NonNull Object> + extends ForwardingConcurrentMap implements Serializable { private static final long serialVersionUID = 3; final Strength keyStrength; @@ -2909,7 +2939,9 @@ void readEntries(ObjectInputStream in) throws IOException, ClassNotFoundExceptio * The actual object that gets serialized. Unfortunately, readResolve() doesn't get called when a * circular dependency is present, so the proxy must be able to behave as the map itself. */ - private static final class SerializationProxy extends AbstractSerializationProxy { + private static final class SerializationProxy< + K extends @NonNull Object, V extends @NonNull Object> + extends AbstractSerializationProxy { private static final long serialVersionUID = 3; SerializationProxy( diff --git a/guava/src/com/google/common/collect/Maps.java b/guava/src/com/google/common/collect/Maps.java index 3dad65762312..6430f182786e 100644 --- a/guava/src/com/google/common/collect/Maps.java +++ b/guava/src/com/google/common/collect/Maps.java @@ -21,6 +21,7 @@ import static com.google.common.base.Predicates.compose; import static com.google.common.collect.CollectPreconditions.checkEntryNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -68,6 +69,7 @@ import java.util.function.BinaryOperator; import java.util.function.Consumer; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -88,7 +90,7 @@ public final class Maps { private Maps() {} - private enum EntryFunction implements Function, Object> { + private enum EntryFunction implements Function, @Nullable Object> { KEY { @Override public @Nullable Object apply(Entry entry) { @@ -103,17 +105,20 @@ private enum EntryFunction implements Function, Object> { }; } - @SuppressWarnings("unchecked") - static Function, K> keyFunction() { + @SuppressWarnings({"unchecked", "nullness"}) + static + Function, K> keyFunction() { return (Function) EntryFunction.KEY; } - @SuppressWarnings("unchecked") - static Function, V> valueFunction() { + @SuppressWarnings({"unchecked", "nullness"}) + static + Function, V> valueFunction() { return (Function) EntryFunction.VALUE; } - static Iterator keyIterator(Iterator> entryIterator) { + static Iterator keyIterator( + Iterator> entryIterator) { return new TransformedIterator, K>(entryIterator) { @Override K transform(Entry entry) { @@ -122,7 +127,8 @@ K transform(Entry entry) { }; } - static Iterator valueIterator(Iterator> entryIterator) { + static Iterator valueIterator( + Iterator> entryIterator) { return new TransformedIterator, V>(entryIterator) { @Override V transform(Entry entry) { @@ -143,7 +149,7 @@ V transform(Entry entry) { * @since 14.0 */ @GwtCompatible(serializable = true) - public static , V> ImmutableMap immutableEnumMap( + public static , V extends @NonNull Object> ImmutableMap immutableEnumMap( Map map) { if (map instanceof ImmutableEnumMap) { @SuppressWarnings("unchecked") // safe covariant cast @@ -171,9 +177,9 @@ public static , V> ImmutableMap immutableEnumMap( return ImmutableEnumMap.asImmutable(enumMap); } - private static class Accumulator, V> { + private static class Accumulator, V extends @NonNull Object> { private final BinaryOperator mergeFunction; - private EnumMap map = null; + private @Nullable EnumMap map = null; Accumulator(BinaryOperator mergeFunction) { this.mergeFunction = mergeFunction; @@ -216,9 +222,10 @@ ImmutableMap toImmutableMap() { * * @since 21.0 */ - public static , V> Collector> toImmutableEnumMap( - java.util.function.Function keyFunction, - java.util.function.Function valueFunction) { + public static , V extends @NonNull Object> + Collector> toImmutableEnumMap( + java.util.function.Function keyFunction, + java.util.function.Function valueFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); return Collector.of( @@ -228,8 +235,9 @@ ImmutableMap toImmutableMap() { throw new IllegalArgumentException("Multiple values for key: " + v1 + ", " + v2); }), (accum, t) -> { - K key = checkNotNull(keyFunction.apply(t), "Null key for input %s", t); - V newValue = checkNotNull(valueFunction.apply(t), "Null value for input %s", t); + // TODO(cpovirk): Why does our prototype checker (but not stock CF) need and ? + K key = Preconditions.checkNotNull(keyFunction.apply(t), "Null key for input %s", t); + V newValue = Preconditions.checkNotNull(valueFunction.apply(t), "Null value for input %s", t); accum.put(key, newValue); }, Accumulator::combine, @@ -248,10 +256,11 @@ ImmutableMap toImmutableMap() { * * @since 21.0 */ - public static , V> Collector> toImmutableEnumMap( - java.util.function.Function keyFunction, - java.util.function.Function valueFunction, - BinaryOperator mergeFunction) { + public static , V extends @NonNull Object> + Collector> toImmutableEnumMap( + java.util.function.Function keyFunction, + java.util.function.Function valueFunction, + BinaryOperator mergeFunction) { checkNotNull(keyFunction); checkNotNull(valueFunction); checkNotNull(mergeFunction); @@ -259,8 +268,9 @@ ImmutableMap toImmutableMap() { return Collector.of( () -> new Accumulator(mergeFunction), (accum, t) -> { - K key = checkNotNull(keyFunction.apply(t), "Null key for input %s", t); - V newValue = checkNotNull(valueFunction.apply(t), "Null value for input %s", t); + // TODO(cpovirk): Why does our prototype checker (but not stock CF) need and ? + K key = Preconditions.checkNotNull(keyFunction.apply(t), "Null key for input %s", t); + V newValue = Preconditions.checkNotNull(valueFunction.apply(t), "Null value for input %s", t); accum.put(key, newValue); }, Accumulator::combine, @@ -280,7 +290,8 @@ ImmutableMap toImmutableMap() { * * @return a new, empty {@code HashMap} */ - public static HashMap newHashMap() { + public static + HashMap newHashMap() { return new HashMap<>(); } @@ -298,7 +309,8 @@ public static HashMap newHashMap() { * @param map the mappings to be placed in the new map * @return a new {@code HashMap} initialized with the mappings from {@code map} */ - public static HashMap newHashMap(Map map) { + public static HashMap newHashMap( + Map map) { return new HashMap<>(map); } @@ -313,7 +325,8 @@ public static HashMap newHashMap(Map map) * without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ - public static HashMap newHashMapWithExpectedSize(int expectedSize) { + public static + HashMap newHashMapWithExpectedSize(int expectedSize) { return new HashMap<>(capacity(expectedSize)); } @@ -346,7 +359,8 @@ static int capacity(int expectedSize) { * * @return a new, empty {@code LinkedHashMap} */ - public static LinkedHashMap newLinkedHashMap() { + public static + LinkedHashMap newLinkedHashMap() { return new LinkedHashMap<>(); } @@ -363,7 +377,8 @@ public static LinkedHashMap newLinkedHashMap() { * @param map the mappings to be placed in the new map * @return a new, {@code LinkedHashMap} initialized with the mappings from {@code map} */ - public static LinkedHashMap newLinkedHashMap(Map map) { + public static + LinkedHashMap newLinkedHashMap(Map map) { return new LinkedHashMap<>(map); } @@ -379,7 +394,8 @@ public static LinkedHashMap newLinkedHashMap(Map LinkedHashMap newLinkedHashMapWithExpectedSize(int expectedSize) { + public static + LinkedHashMap newLinkedHashMapWithExpectedSize(int expectedSize) { return new LinkedHashMap<>(capacity(expectedSize)); } @@ -388,7 +404,8 @@ public static LinkedHashMap newLinkedHashMapWithExpectedSize(int ex * * @since 3.0 */ - public static ConcurrentMap newConcurrentMap() { + public static + ConcurrentMap newConcurrentMap() { return new ConcurrentHashMap<>(); } @@ -424,7 +441,8 @@ public static TreeMap newTreeMap() { * @return a new {@code TreeMap} initialized with the mappings from {@code map} and using the * comparator of {@code map} */ - public static TreeMap newTreeMap(SortedMap map) { + public static TreeMap newTreeMap( + SortedMap map) { return new TreeMap<>(map); } @@ -441,13 +459,14 @@ public static TreeMap newTreeMap(SortedMap map) { * @param comparator the comparator to sort the keys with * @return a new, empty {@code TreeMap} */ - public static TreeMap newTreeMap(@Nullable Comparator comparator) { + public static + TreeMap newTreeMap(@Nullable Comparator comparator) { // Ideally, the extra type parameter "C" shouldn't be necessary. It is a // work-around of a compiler type inference quirk that prevents the // following code from being compiled: // Comparator> comparator = null; // Map, String> map = newTreeMap(comparator); - return new TreeMap<>(comparator); + return new TreeMap(comparator); } /** @@ -456,7 +475,8 @@ public static TreeMap newTreeMap(@Nullable Comparator< * @param type the key type for this map * @return a new, empty {@code EnumMap} */ - public static , V> EnumMap newEnumMap(Class type) { + public static , V> EnumMap newEnumMap( + Class type) { return new EnumMap<>(checkNotNull(type)); } @@ -472,7 +492,8 @@ public static , V> EnumMap newEnumMap(Class type) { * @throws IllegalArgumentException if {@code m} is not an {@code EnumMap} instance and contains * no mappings */ - public static , V> EnumMap newEnumMap(Map map) { + public static , V> EnumMap newEnumMap( + Map map) { return new EnumMap<>(map); } @@ -485,7 +506,8 @@ public static , V> EnumMap newEnumMap(Map IdentityHashMap newIdentityHashMap() { + public static + IdentityHashMap newIdentityHashMap() { return new IdentityHashMap<>(); } @@ -505,13 +527,27 @@ public static IdentityHashMap newIdentityHashMap() { * @return the difference between the two maps */ @SuppressWarnings("unchecked") - public static MapDifference difference( - Map left, Map right) { + public static + MapDifference difference( + Map left, Map right) { if (left instanceof SortedMap) { SortedMap sortedLeft = (SortedMap) left; return difference(sortedLeft, right); } - return difference(left, right, Equivalence.equals()); + /* + * This cast is safe: The Equivalence-accepting overload of difference() (which we call below) + * has a weird signature because Equivalence is itself a little weird. Still, we know that + * Equivalence.equals() can handle all inputs, and we know that the resulting MapDifference will + * contain only Ks and Vs (as opposed to possibly containing @Nullable objects even when K and V + * are *not* @Nullable). + * + * An alternative to suppressing the warning would be to inline the body of the other + * difference() method into this one. + */ + @SuppressWarnings("nullness") + MapDifference result = + (MapDifference) difference(left, right, Equivalence.equals()); + return result; } /** @@ -528,17 +564,28 @@ public static MapDifference difference( * @return the difference between the two maps * @since 10.0 */ - public static MapDifference difference( - Map left, - Map right, - Equivalence valueEquivalence) { + /* + * This should really accept maps with @Nullable value types. To make that work with Equivalence, + * though, we'd need to introduce a new type parameter, like on doDifference (or support + * something like Equivalence). Without that, we have + * to either requires non-null inputs and outputs or require nullable inputs and outputs. Non-null + * seems more likely to be useful. + */ + public static + MapDifference difference( + Map left, + Map right, + Equivalence valueEquivalence) { Preconditions.checkNotNull(valueEquivalence); Map onlyOnLeft = newLinkedHashMap(); Map onlyOnRight = new LinkedHashMap<>(right); // will whittle it down Map onBoth = newLinkedHashMap(); Map> differences = newLinkedHashMap(); - doDifference(left, right, valueEquivalence, onlyOnLeft, onlyOnRight, onBoth, differences); + // This cast works around https://github.com/typetools/checker-framework/issues/3025 + @SuppressWarnings("unchecked") // safe because Equivalence is contravariant + Equivalence castEquivalence = (Equivalence) valueEquivalence; + doDifference(left, right, castEquivalence, onlyOnLeft, onlyOnRight, onBoth, differences); return new MapDifferenceImpl<>(onlyOnLeft, onlyOnRight, onBoth, differences); } @@ -559,8 +606,9 @@ public static MapDifference difference( * @return the difference between the two maps * @since 11.0 */ - public static SortedMapDifference difference( - SortedMap left, Map right) { + public static + SortedMapDifference difference( + SortedMap left, Map right) { checkNotNull(left); checkNotNull(right); Comparator comparator = orNaturalOrder(left.comparator()); @@ -573,23 +621,27 @@ public static SortedMapDifference difference( return new SortedMapDifferenceImpl<>(onlyOnLeft, onlyOnRight, onBoth, differences); } - private static void doDifference( - Map left, - Map right, - Equivalence valueEquivalence, - Map onlyOnLeft, - Map onlyOnRight, - Map onBoth, - Map> differences) { - for (Entry entry : left.entrySet()) { + // The L parameter works around https://github.com/typetools/checker-framework/issues/3027 + private static < + K, E extends @NonNull Object, V extends @Nullable E, L extends V> + void doDifference( + Map left, + Map right, + Equivalence valueEquivalence, + Map onlyOnLeft, + Map onlyOnRight, + Map onBoth, + Map> differences) { + for (Entry entry : left.entrySet()) { K leftKey = entry.getKey(); - V leftValue = entry.getValue(); + L leftValue = entry.getValue(); if (right.containsKey(leftKey)) { - V rightValue = onlyOnRight.remove(leftKey); + // The cast is safe because of the containsKey check. + V rightValue = uncheckedCastNullableVToV(onlyOnRight.remove(leftKey)); if (valueEquivalence.equivalent(leftValue, rightValue)) { onBoth.put(leftKey, leftValue); } else { - differences.put(leftKey, ValueDifferenceImpl.create(leftValue, rightValue)); + differences.put(leftKey, ValueDifferenceImpl.create(leftValue, rightValue)); } } else { onlyOnLeft.put(leftKey, leftValue); @@ -597,7 +649,8 @@ private static void doDifference( } } - private static Map unmodifiableMap(Map map) { + private static Map unmodifiableMap( + Map map) { if (map instanceof SortedMap) { return Collections.unmodifiableSortedMap((SortedMap) map); } else { @@ -605,7 +658,8 @@ private static Map unmodifiableMap(Map map) { } } - static class MapDifferenceImpl implements MapDifference { + static class MapDifferenceImpl + implements MapDifference { final Map onlyOnLeft; final Map onlyOnRight; final Map onBoth; @@ -648,12 +702,13 @@ public Map> entriesDiffering() { } @Override - public boolean equals(Object object) { + public boolean equals(@Nullable Object object) { if (object == this) { return true; } if (object instanceof MapDifference) { - MapDifference other = (MapDifference) object; + MapDifference other = + (MapDifference) object; return entriesOnlyOnLeft().equals(other.entriesOnlyOnLeft()) && entriesOnlyOnRight().equals(other.entriesOnlyOnRight()) && entriesInCommon().equals(other.entriesInCommon()) @@ -688,15 +743,16 @@ public String toString() { } } - static class ValueDifferenceImpl implements MapDifference.ValueDifference { - private final @Nullable V left; - private final @Nullable V right; + static class ValueDifferenceImpl + implements MapDifference.ValueDifference { + private final V left; + private final V right; - static ValueDifference create(@Nullable V left, @Nullable V right) { + static ValueDifference create(V left, V right) { return new ValueDifferenceImpl(left, right); } - private ValueDifferenceImpl(@Nullable V left, @Nullable V right) { + private ValueDifferenceImpl(V left, V right) { this.left = left; this.right = right; } @@ -714,7 +770,8 @@ public V rightValue() { @Override public boolean equals(@Nullable Object object) { if (object instanceof MapDifference.ValueDifference) { - MapDifference.ValueDifference that = (MapDifference.ValueDifference) object; + MapDifference.ValueDifference that = + (MapDifference.ValueDifference) object; return Objects.equal(this.left, that.leftValue()) && Objects.equal(this.right, that.rightValue()); } @@ -732,8 +789,8 @@ public String toString() { } } - static class SortedMapDifferenceImpl extends MapDifferenceImpl - implements SortedMapDifference { + static class SortedMapDifferenceImpl + extends MapDifferenceImpl implements SortedMapDifference { SortedMapDifferenceImpl( SortedMap onlyOnLeft, SortedMap onlyOnRight, @@ -769,7 +826,8 @@ public SortedMap entriesOnlyOnRight() { * ugly type-casting in one place. */ @SuppressWarnings("unchecked") - static Comparator orNaturalOrder(@Nullable Comparator comparator) { + static Comparator orNaturalOrder( + @Nullable Comparator comparator) { if (comparator != null) { // can't use ? : because of javac bug 5080917 return comparator; } @@ -800,7 +858,8 @@ static Comparator orNaturalOrder(@Nullable Comparator * * @since 14.0 */ - public static Map asMap(Set set, Function function) { + public static Map asMap( + Set set, Function function) { return new AsMapView<>(set, function); } @@ -827,7 +886,8 @@ public static Map asMap(Set set, Function function * * @since 14.0 */ - public static SortedMap asMap(SortedSet set, Function function) { + public static SortedMap asMap( + SortedSet set, Function function) { return new SortedAsMapView<>(set, function); } @@ -860,7 +920,8 @@ public static NavigableMap asMap( return new NavigableAsMapView<>(set, function); } - private static class AsMapView extends ViewCachingAbstractMap { + private static class AsMapView + extends ViewCachingAbstractMap { private final Set set; final Function function; @@ -895,12 +956,16 @@ public boolean containsKey(@Nullable Object key) { } @Override - public V get(@Nullable Object key) { - return getOrDefault(key, null); + public @Nullable V get(@Nullable Object key) { + /* + * unsafeNull is safe because all getOrDefault does with a null defaultValue is return null, + * and all get() does with that is return it. + */ + return getOrDefault(key, unsafeNull()); } @Override - public V getOrDefault(@Nullable Object key, @Nullable V defaultValue) { + public V getOrDefault(@Nullable Object key, V defaultValue) { if (Collections2.safeContains(backingSet(), key)) { @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it K k = (K) key; @@ -911,7 +976,7 @@ public V getOrDefault(@Nullable Object key, @Nullable V defaultValue) { } @Override - public V remove(@Nullable Object key) { + public @Nullable V remove(@Nullable Object key) { if (backingSet().remove(key)) { @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it K k = (K) key; @@ -951,8 +1016,8 @@ public void forEach(BiConsumer action) { } } - static Iterator> asMapEntryIterator( - Set set, final Function function) { + static + Iterator> asMapEntryIterator(Set set, final Function function) { return new TransformedIterator>(set.iterator()) { @Override Entry transform(final K key) { @@ -961,7 +1026,8 @@ Entry transform(final K key) { }; } - private static class SortedAsMapView extends AsMapView implements SortedMap { + private static class SortedAsMapView + extends AsMapView implements SortedMap { SortedAsMapView(SortedSet set, Function function) { super(set, function); @@ -973,7 +1039,7 @@ SortedSet backingSet() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return backingSet().comparator(); } @@ -1009,7 +1075,9 @@ public K lastKey() { } @GwtIncompatible // NavigableMap - private static final class NavigableAsMapView extends AbstractNavigableMap { + private static final class NavigableAsMapView< + K, V> + extends AbstractNavigableMap { /* * Using AbstractNavigableMap is simpler than extending SortedAsMapView and rewriting all the * NavigableMap methods. @@ -1040,17 +1108,21 @@ public NavigableMap tailMap(K fromKey, boolean inclusive) { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return set.comparator(); } @Override public @Nullable V get(@Nullable Object key) { - return getOrDefault(key, null); + /* + * unsafeNull is safe because all getOrDefault does with a null defaultValue is return null, + * and all get() does with that is return it. + */ + return getOrDefault(key, unsafeNull()); } @Override - public @Nullable V getOrDefault(@Nullable Object key, @Nullable V defaultValue) { + public V getOrDefault(@Nullable Object key, V defaultValue) { if (Collections2.safeContains(set, key)) { @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it K k = (K) key; @@ -1120,7 +1192,8 @@ public boolean addAll(Collection es) { }; } - private static SortedSet removeOnlySortedSet(final SortedSet set) { + private static SortedSet removeOnlySortedSet( + final SortedSet set) { return new ForwardingSortedSet() { @Override protected SortedSet delegate() { @@ -1155,7 +1228,8 @@ public SortedSet tailSet(E fromElement) { } @GwtIncompatible // NavigableSet - private static NavigableSet removeOnlyNavigableSet(final NavigableSet set) { + private static NavigableSet removeOnlyNavigableSet( + final NavigableSet set) { return new ForwardingNavigableSet() { @Override protected NavigableSet delegate() { @@ -1227,7 +1301,7 @@ public NavigableSet descendingSet() { * valueFunction} produces {@code null} for any key * @since 14.0 */ - public static ImmutableMap toMap( + public static ImmutableMap toMap( Iterable keys, Function valueFunction) { return toMap(keys.iterator(), valueFunction); } @@ -1245,7 +1319,7 @@ public static ImmutableMap toMap( * valueFunction} produces {@code null} for any key * @since 14.0 */ - public static ImmutableMap toMap( + public static ImmutableMap toMap( Iterator keys, Function valueFunction) { checkNotNull(valueFunction); // Using LHM instead of a builder so as not to fail on duplicate keys @@ -1286,8 +1360,8 @@ public static ImmutableMap toMap( * keyFunction} produces {@code null} for any value */ @CanIgnoreReturnValue - public static ImmutableMap uniqueIndex( - Iterable values, Function keyFunction) { + public static + ImmutableMap uniqueIndex(Iterable values, Function keyFunction) { // TODO(lowasser): consider presizing the builder if values is a Collection return uniqueIndex(values.iterator(), keyFunction); } @@ -1322,8 +1396,8 @@ public static ImmutableMap uniqueIndex( * @since 10.0 */ @CanIgnoreReturnValue - public static ImmutableMap uniqueIndex( - Iterator values, Function keyFunction) { + public static + ImmutableMap uniqueIndex(Iterator values, Function keyFunction) { checkNotNull(keyFunction); ImmutableMap.Builder builder = ImmutableMap.builder(); while (values.hasNext()) { @@ -1353,9 +1427,14 @@ public static ImmutableMap uniqueIndex( public static ImmutableMap fromProperties(Properties properties) { ImmutableMap.Builder builder = ImmutableMap.builder(); - for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) { - String key = (String) e.nextElement(); - builder.put(key, properties.getProperty(key)); + for (Enumeration e = properties.propertyNames(); + e.hasMoreElements(); ) { + /* + * requireNonNull is safe with a typical Properties instance, but it's possible for users to + * put null keys and values in if they want. If they do, this method will throw. + */ + String key = (String) requireNonNull(e.nextElement()); + builder.put(key, requireNonNull(properties.getProperty(key))); } return builder.build(); @@ -1374,7 +1453,8 @@ public static ImmutableMap fromProperties(Properties properties) * @param value the value to be associated with the returned entry */ @GwtCompatible(serializable = true) - public static Entry immutableEntry(@Nullable K key, @Nullable V value) { + public static Entry immutableEntry( + K key, V value) { return new ImmutableEntry<>(key, value); } @@ -1386,7 +1466,8 @@ public static Entry immutableEntry(@Nullable K key, @Nullable V val * @param entrySet the entries for which to return an unmodifiable view * @return an unmodifiable view of the entries */ - static Set> unmodifiableEntrySet(Set> entrySet) { + static + Set> unmodifiableEntrySet(Set> entrySet) { return new UnmodifiableEntrySet<>(Collections.unmodifiableSet(entrySet)); } @@ -1399,7 +1480,8 @@ static Set> unmodifiableEntrySet(Set> entrySet) { * @param entry the entry for which to return an unmodifiable view * @return an unmodifiable view of the entry */ - static Entry unmodifiableEntry(final Entry entry) { + static Entry unmodifiableEntry( + final Entry entry) { checkNotNull(entry); return new AbstractMapEntry() { @Override @@ -1414,8 +1496,9 @@ public V getValue() { }; } - static UnmodifiableIterator> unmodifiableEntryIterator( - final Iterator> entryIterator) { + static + UnmodifiableIterator> unmodifiableEntryIterator( + final Iterator> entryIterator) { return new UnmodifiableIterator>() { @Override public boolean hasNext() { @@ -1430,7 +1513,8 @@ public Entry next() { } /** @see Multimaps#unmodifiableEntries */ - static class UnmodifiableEntries extends ForwardingCollection> { + static class UnmodifiableEntries + extends ForwardingCollection> { private final Collection> entries; UnmodifiableEntries(Collection> entries) { @@ -1450,19 +1534,21 @@ public Iterator> iterator() { // See java.util.Collections.UnmodifiableEntrySet for details on attacks. @Override +@SuppressWarnings("nullness") public Object[] toArray() { return standardToArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return standardToArray(array); } } /** @see Maps#unmodifiableEntrySet(Set) */ - static class UnmodifiableEntrySet extends UnmodifiableEntries - implements Set> { + static class UnmodifiableEntrySet + extends UnmodifiableEntries implements Set> { UnmodifiableEntrySet(Set> entries) { super(entries); } @@ -1490,11 +1576,13 @@ public int hashCode() { * * @since 16.0 */ - public static Converter asConverter(final BiMap bimap) { + public static Converter asConverter( + final BiMap bimap) { return new BiMapConverter<>(bimap); } - private static final class BiMapConverter extends Converter implements Serializable { + private static final class BiMapConverter + extends Converter implements Serializable { private final BiMap bimap; BiMapConverter(BiMap bimap) { @@ -1511,9 +1599,12 @@ protected A doBackward(B b) { return convert(bimap.inverse(), b); } - private static Y convert(BiMap bimap, X input) { + private static Y convert( + BiMap bimap, X input) { Y output = bimap.get(input); - checkArgument(output != null, "No non-null mapping present for input: %s", input); + if (output == null) { + throw new IllegalArgumentException("No non-null mapping present for input: " + input); + } return output; } @@ -1569,7 +1660,8 @@ public String toString() { * @param bimap the bimap to be wrapped in a synchronized view * @return a synchronized view of the specified bimap */ - public static BiMap synchronizedBiMap(BiMap bimap) { + public static + BiMap synchronizedBiMap(BiMap bimap) { return Synchronized.biMap(bimap, null); } @@ -1584,13 +1676,14 @@ public static BiMap synchronizedBiMap(BiMap bimap) { * @param bimap the bimap for which an unmodifiable view is to be returned * @return an unmodifiable view of the specified bimap */ - public static BiMap unmodifiableBiMap(BiMap bimap) { + public static + BiMap unmodifiableBiMap(BiMap bimap) { return new UnmodifiableBiMap<>(bimap, null); } /** @see Maps#unmodifiableBiMap(BiMap) */ - private static class UnmodifiableBiMap extends ForwardingMap - implements BiMap, Serializable { + private static class UnmodifiableBiMap + extends ForwardingMap implements BiMap, Serializable { final Map unmodifiableMap; final BiMap delegate; @RetainedWith @Nullable BiMap inverse; @@ -1608,7 +1701,7 @@ protected Map delegate() { } @Override - public V forcePut(K key, V value) { + public @Nullable V forcePut(K key, V value) { throw new UnsupportedOperationException(); } @@ -1662,8 +1755,9 @@ public Set values() { * function} should be fast. To avoid lazy evaluation when the returned map doesn't need to be a * view, copy the returned map into a new map of your choosing. */ - public static Map transformValues( - Map fromMap, Function function) { + public static < + K, V1, V2> + Map transformValues(Map fromMap, Function function) { return transformEntries(fromMap, asEntryTransformer(function)); } @@ -1703,8 +1797,10 @@ public static Map transformValues( * * @since 11.0 */ - public static SortedMap transformValues( - SortedMap fromMap, Function function) { + public static < + K, V1, V2> + SortedMap transformValues( + SortedMap fromMap, Function function) { return transformEntries(fromMap, asEntryTransformer(function)); } @@ -1747,8 +1843,10 @@ public static SortedMap transformValues( * @since 13.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap transformValues( - NavigableMap fromMap, Function function) { + public static < + K, V1, V2> + NavigableMap transformValues( + NavigableMap fromMap, Function function) { return transformEntries(fromMap, asEntryTransformer(function)); } @@ -1799,8 +1897,10 @@ public static NavigableMap transformValues( * * @since 7.0 */ - public static Map transformEntries( - Map fromMap, EntryTransformer transformer) { + public static < + K, V1, V2> + Map transformEntries( + Map fromMap, EntryTransformer transformer) { return new TransformedEntriesMap<>(fromMap, transformer); } @@ -1851,8 +1951,10 @@ public static Map transformEntries( * * @since 11.0 */ - public static SortedMap transformEntries( - SortedMap fromMap, EntryTransformer transformer) { + public static < + K, V1, V2> + SortedMap transformEntries( + SortedMap fromMap, EntryTransformer transformer) { return new TransformedEntriesSortedMap<>(fromMap, transformer); } @@ -1905,8 +2007,11 @@ public static SortedMap transformEntries( * @since 13.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap transformEntries( - final NavigableMap fromMap, EntryTransformer transformer) { + public static < + K, V1, V2> + NavigableMap transformEntries( + final NavigableMap fromMap, + EntryTransformer transformer) { return new TransformedEntriesNavigableMap<>(fromMap, transformer); } @@ -1920,7 +2025,8 @@ public static NavigableMap transformEntries( * @since 7.0 */ @FunctionalInterface - public interface EntryTransformer { + public interface EntryTransformer< + K, V1, V2> { /** * Determines an output value based on a key-value pair. This method is generally * expected, but not absolutely required, to have the following properties: @@ -1935,12 +2041,12 @@ public interface EntryTransformer { * @throws NullPointerException if the key or value is null and this transformer does not accept * null arguments */ - V2 transformEntry(@Nullable K key, @Nullable V1 value); + V2 transformEntry(K key, V1 value); } /** Views a function as an entry transformer that ignores the entry key. */ - static EntryTransformer asEntryTransformer( - final Function function) { + static + EntryTransformer asEntryTransformer(final Function function) { checkNotNull(function); return new EntryTransformer() { @Override @@ -1950,20 +2056,22 @@ public V2 transformEntry(K key, V1 value) { }; } - static Function asValueToValueFunction( - final EntryTransformer transformer, final K key) { + static + Function asValueToValueFunction( + final EntryTransformer transformer, final K key) { checkNotNull(transformer); return new Function() { @Override - public V2 apply(@Nullable V1 v1) { + public V2 apply(V1 v1) { return transformer.transformEntry(key, v1); } }; } /** Views an entry transformer as a function from {@code Entry} to values. */ - static Function, V2> asEntryToValueFunction( - final EntryTransformer transformer) { + static + Function, V2> asEntryToValueFunction( + final EntryTransformer transformer) { checkNotNull(transformer); return new Function, V2>() { @Override @@ -1974,8 +2082,9 @@ public V2 apply(Entry entry) { } /** Returns a view of an entry transformed by the specified transformer. */ - static Entry transformEntry( - final EntryTransformer transformer, final Entry entry) { + static + Entry transformEntry( + final EntryTransformer transformer, final Entry entry) { checkNotNull(transformer); checkNotNull(entry); return new AbstractMapEntry() { @@ -1992,8 +2101,9 @@ public V2 getValue() { } /** Views an entry transformer as a function from entries to entries. */ - static Function, Entry> asEntryToEntryFunction( - final EntryTransformer transformer) { + static + Function, Entry> asEntryToEntryFunction( + final EntryTransformer transformer) { checkNotNull(transformer); return new Function, Entry>() { @Override @@ -2003,7 +2113,9 @@ public Entry apply(final Entry entry) { }; } - static class TransformedEntriesMap extends IteratorBasedAbstractMap { + static class TransformedEntriesMap< + K, V1, V2> + extends IteratorBasedAbstractMap { final Map fromMap; final EntryTransformer transformer; @@ -2019,31 +2131,37 @@ public int size() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return fromMap.containsKey(key); } @Override public @Nullable V2 get(@Nullable Object key) { - return getOrDefault(key, null); + /* + * unsafeNull is safe because all getOrDefault does with a null defaultValue is return null, + * and all get() does with that is return it. + */ + return getOrDefault(key, unsafeNull()); } // safe as long as the user followed the Warning in the javadoc @SuppressWarnings("unchecked") @Override - public @Nullable V2 getOrDefault(@Nullable Object key, @Nullable V2 defaultValue) { + public V2 getOrDefault(@Nullable Object key, V2 defaultValue) { V1 value = fromMap.get(key); return (value != null || fromMap.containsKey(key)) - ? transformer.transformEntry((K) key, value) + // The cast is safe because of the containsKey check. + ? transformer.transformEntry((K) key, uncheckedCastNullableVToV(value)) : defaultValue; } // safe as long as the user followed the Warning in the javadoc @SuppressWarnings("unchecked") @Override - public V2 remove(Object key) { + public @Nullable V2 remove(@Nullable Object key) { return fromMap.containsKey(key) - ? transformer.transformEntry((K) key, fromMap.remove(key)) + // The cast is safe because of the containsKey check. + ? transformer.transformEntry((K) key, uncheckedCastNullableVToV(fromMap.remove(key))) : null; } @@ -2082,8 +2200,9 @@ public Collection values() { } } - static class TransformedEntriesSortedMap extends TransformedEntriesMap - implements SortedMap { + static class TransformedEntriesSortedMap< + K, V1, V2> + extends TransformedEntriesMap implements SortedMap { protected SortedMap fromMap() { return (SortedMap) fromMap; @@ -2095,7 +2214,7 @@ protected SortedMap fromMap() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return fromMap().comparator(); } @@ -2126,7 +2245,8 @@ public SortedMap tailMap(K fromKey) { } @GwtIncompatible // NavigableMap - private static class TransformedEntriesNavigableMap + private static class TransformedEntriesNavigableMap< + K, V1, V2> extends TransformedEntriesSortedMap implements NavigableMap { TransformedEntriesNavigableMap( @@ -2135,12 +2255,12 @@ private static class TransformedEntriesNavigableMap } @Override - public Entry ceilingEntry(K key) { + public @Nullable Entry ceilingEntry(K key) { return transformEntry(fromMap().ceilingEntry(key)); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return fromMap().ceilingKey(key); } @@ -2155,17 +2275,17 @@ public NavigableMap descendingMap() { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return transformEntry(fromMap().firstEntry()); } @Override - public Entry floorEntry(K key) { + public @Nullable Entry floorEntry(K key) { return transformEntry(fromMap().floorEntry(key)); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return fromMap().floorKey(key); } @@ -2180,27 +2300,27 @@ public NavigableMap headMap(K toKey, boolean inclusive) { } @Override - public Entry higherEntry(K key) { + public @Nullable Entry higherEntry(K key) { return transformEntry(fromMap().higherEntry(key)); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return fromMap().higherKey(key); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return transformEntry(fromMap().lastEntry()); } @Override - public Entry lowerEntry(K key) { + public @Nullable Entry lowerEntry(K key) { return transformEntry(fromMap().lowerEntry(key)); } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return fromMap().lowerKey(key); } @@ -2210,12 +2330,12 @@ public NavigableSet navigableKeySet() { } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { return transformEntry(fromMap().pollFirstEntry()); } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { return transformEntry(fromMap().pollLastEntry()); } @@ -2251,11 +2371,15 @@ protected NavigableMap fromMap() { } } - static Predicate> keyPredicateOnEntries(Predicate keyPredicate) { + static + Predicate> keyPredicateOnEntries( + Predicate keyPredicate) { return compose(keyPredicate, Maps.keyFunction()); } - static Predicate> valuePredicateOnEntries(Predicate valuePredicate) { + static + Predicate> valuePredicateOnEntries( + Predicate valuePredicate) { return compose(valuePredicate, Maps.valueFunction()); } @@ -2351,8 +2475,9 @@ public static SortedMap filterKeys( * @since 14.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap filterKeys( - NavigableMap unfiltered, final Predicate keyPredicate) { + public static + NavigableMap filterKeys( + NavigableMap unfiltered, final Predicate keyPredicate) { // TODO(lowasser): Return a subclass of Maps.FilteredKeyMap for slightly better // performance. return filterEntries(unfiltered, Maps.keyPredicateOnEntries(keyPredicate)); @@ -2442,8 +2567,9 @@ public static Map filterValues( * * @since 11.0 */ - public static SortedMap filterValues( - SortedMap unfiltered, final Predicate valuePredicate) { + public static + SortedMap filterValues( + SortedMap unfiltered, final Predicate valuePredicate) { return filterEntries(unfiltered, Maps.valuePredicateOnEntries(valuePredicate)); } @@ -2474,8 +2600,9 @@ public static SortedMap filterValues( * @since 14.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap filterValues( - NavigableMap unfiltered, final Predicate valuePredicate) { + public static + NavigableMap filterValues( + NavigableMap unfiltered, final Predicate valuePredicate) { return filterEntries(unfiltered, Maps.valuePredicateOnEntries(valuePredicate)); } @@ -2569,8 +2696,9 @@ public static Map filterEntries( * * @since 11.0 */ - public static SortedMap filterEntries( - SortedMap unfiltered, Predicate> entryPredicate) { + public static + SortedMap filterEntries( + SortedMap unfiltered, Predicate> entryPredicate) { checkNotNull(entryPredicate); return (unfiltered instanceof FilteredEntrySortedMap) ? filterFiltered((FilteredEntrySortedMap) unfiltered, entryPredicate) @@ -2604,8 +2732,9 @@ public static SortedMap filterEntries( * @since 14.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap filterEntries( - NavigableMap unfiltered, Predicate> entryPredicate) { + public static + NavigableMap filterEntries( + NavigableMap unfiltered, Predicate> entryPredicate) { checkNotNull(entryPredicate); return (unfiltered instanceof FilteredEntryNavigableMap) ? filterFiltered((FilteredEntryNavigableMap) unfiltered, entryPredicate) @@ -2662,8 +2791,9 @@ private static Map filterFiltered( * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when filtering a filtered * sorted map. */ - private static SortedMap filterFiltered( - FilteredEntrySortedMap map, Predicate> entryPredicate) { + private static + SortedMap filterFiltered( + FilteredEntrySortedMap map, Predicate> entryPredicate) { Predicate> predicate = Predicates.>and(map.predicate, entryPredicate); return new FilteredEntrySortedMap<>(map.sortedMap(), predicate); } @@ -2673,8 +2803,9 @@ private static SortedMap filterFiltered( * navigable map. */ @GwtIncompatible // NavigableMap - private static NavigableMap filterFiltered( - FilteredEntryNavigableMap map, Predicate> entryPredicate) { + private static + NavigableMap filterFiltered( + FilteredEntryNavigableMap map, Predicate> entryPredicate) { Predicate> predicate = Predicates.>and(map.entryPredicate, entryPredicate); return new FilteredEntryNavigableMap<>(map.unfiltered, predicate); @@ -2684,13 +2815,16 @@ private static NavigableMap filterFiltered( * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when filtering a filtered * map. */ - private static BiMap filterFiltered( - FilteredEntryBiMap map, Predicate> entryPredicate) { + private static + BiMap filterFiltered( + FilteredEntryBiMap map, Predicate> entryPredicate) { Predicate> predicate = Predicates.>and(map.predicate, entryPredicate); return new FilteredEntryBiMap<>(map.unfiltered(), predicate); } - private abstract static class AbstractFilteredMap extends ViewCachingAbstractMap { + private abstract static class AbstractFilteredMap< + K, V> + extends ViewCachingAbstractMap { final Map unfiltered; final Predicate> predicate; @@ -2699,16 +2833,16 @@ private abstract static class AbstractFilteredMap extends ViewCachingAbstr this.predicate = predicate; } - boolean apply(@Nullable Object key, @Nullable V value) { - // This method is called only when the key is in the map, implying that - // key is a K. - @SuppressWarnings("unchecked") + boolean apply(@Nullable Object key, V value) { + // This method is called only when the key is in the map (or about to be added to the map), + // implying that key is a K. + @SuppressWarnings({"unchecked", "nullness"}) K k = (K) key; return predicate.apply(Maps.immutableEntry(k, value)); } @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { checkArgument(apply(key, value)); return unfiltered.put(key, value); } @@ -2722,12 +2856,13 @@ public void putAll(Map map) { } @Override - public boolean containsKey(Object key) { - return unfiltered.containsKey(key) && apply(key, unfiltered.get(key)); + public boolean containsKey(@Nullable Object key) { + // The cast is safe because of the containsKey check. + return unfiltered.containsKey(key) && apply(key, uncheckedCastNullableVToV(unfiltered.get(key))); } @Override - public V get(Object key) { + public @Nullable V get(@Nullable Object key) { V value = unfiltered.get(key); return ((value != null) && apply(key, value)) ? value : null; } @@ -2738,7 +2873,7 @@ public boolean isEmpty() { } @Override - public V remove(Object key) { + public @Nullable V remove(@Nullable Object key) { return containsKey(key) ? unfiltered.remove(key) : null; } @@ -2748,7 +2883,9 @@ Collection createValues() { } } - private static final class FilteredMapValues extends Maps.Values { + private static final class FilteredMapValues< + K, V> + extends Maps.Values { final Map unfiltered; final Predicate> predicate; @@ -2760,7 +2897,7 @@ private static final class FilteredMapValues extends Maps.Values { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { Iterator> entryItr = unfiltered.entrySet().iterator(); while (entryItr.hasNext()) { Entry entry = entryItr.next(); @@ -2801,18 +2938,21 @@ public boolean retainAll(Collection collection) { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { // creating an ArrayList so filtering happens once return Lists.newArrayList(iterator()).toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return Lists.newArrayList(iterator()).toArray(array); } } - private static class FilteredKeyMap extends AbstractFilteredMap { + private static class FilteredKeyMap + extends AbstractFilteredMap { final Predicate keyPredicate; FilteredKeyMap( @@ -2837,12 +2977,13 @@ Set createKeySet() { // that key is a K. @Override @SuppressWarnings("unchecked") - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return unfiltered.containsKey(key) && keyPredicate.apply((K) key); } } - static class FilteredEntryMap extends AbstractFilteredMap { + static class FilteredEntryMap + extends AbstractFilteredMap { /** * Entries in this set satisfy the predicate, but they don't validate the input to {@code * Entry.setValue()}. @@ -2894,7 +3035,9 @@ Set createKeySet() { } static boolean removeAllKeys( - Map map, Predicate> entryPredicate, Collection keyCollection) { + Map map, + Predicate> entryPredicate, + Collection keyCollection) { Iterator> entryItr = map.entrySet().iterator(); boolean result = false; while (entryItr.hasNext()) { @@ -2908,7 +3051,9 @@ static boolean removeAllKeys( } static boolean retainAllKeys( - Map map, Predicate> entryPredicate, Collection keyCollection) { + Map map, + Predicate> entryPredicate, + Collection keyCollection) { Iterator> entryItr = map.entrySet().iterator(); boolean result = false; while (entryItr.hasNext()) { @@ -2928,7 +3073,7 @@ class KeySet extends Maps.KeySet { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (containsKey(o)) { unfiltered.remove(o); return true; @@ -2947,20 +3092,23 @@ public boolean retainAll(Collection collection) { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { // creating an ArrayList so filtering happens once return Lists.newArrayList(iterator()).toArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return Lists.newArrayList(iterator()).toArray(array); } } } - private static class FilteredEntrySortedMap extends FilteredEntryMap - implements SortedMap { + private static class FilteredEntrySortedMap< + K, V> + extends FilteredEntryMap implements SortedMap { FilteredEntrySortedMap( SortedMap unfiltered, Predicate> entryPredicate) { @@ -2984,7 +3132,7 @@ SortedSet createKeySet() { @WeakOuter class SortedKeySet extends KeySet implements SortedSet { @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return sortedMap().comparator(); } @@ -3015,7 +3163,7 @@ public K last() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return sortedMap().comparator(); } @@ -3031,7 +3179,8 @@ public K lastKey() { while (true) { // correctly throws NoSuchElementException when filtered map is empty. K key = headMap.lastKey(); - if (apply(key, unfiltered.get(key))) { + // The cast is safe because the key is taken from the map. + if (apply(key, uncheckedCastNullableVToV(unfiltered.get(key)))) { return key; } headMap = sortedMap().headMap(key); @@ -3055,7 +3204,9 @@ public SortedMap tailMap(K fromKey) { } @GwtIncompatible // NavigableMap - private static class FilteredEntryNavigableMap extends AbstractNavigableMap { + private static class FilteredEntryNavigableMap< + K, V> + extends AbstractNavigableMap { /* * It's less code to extend AbstractNavigableMap and forward the filtering logic to * FilteredEntryMap than to extend FilteredEntrySortedMap and reimplement all the NavigableMap @@ -3074,7 +3225,7 @@ private static class FilteredEntryNavigableMap extends AbstractNavigableMa } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return unfiltered.comparator(); } @@ -3129,12 +3280,12 @@ public boolean containsKey(@Nullable Object key) { } @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { return filteredDelegate.put(key, value); } @Override - public V remove(@Nullable Object key) { + public @Nullable V remove(@Nullable Object key) { return filteredDelegate.remove(key); } @@ -3154,12 +3305,12 @@ public Set> entrySet() { } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { return Iterables.removeFirstMatching(unfiltered.entrySet(), entryPredicate); } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { return Iterables.removeFirstMatching(unfiltered.descendingMap().entrySet(), entryPredicate); } @@ -3186,12 +3337,13 @@ public NavigableMap tailMap(K fromKey, boolean inclusive) { } } - static final class FilteredEntryBiMap extends FilteredEntryMap - implements BiMap { + static final class FilteredEntryBiMap + extends FilteredEntryMap implements BiMap { @RetainedWith private final BiMap inverse; - private static Predicate> inversePredicate( - final Predicate> forwardPredicate) { + private static + Predicate> inversePredicate( + final Predicate> forwardPredicate) { return new Predicate>() { @Override public boolean apply(Entry input) { @@ -3200,6 +3352,8 @@ public boolean apply(Entry input) { }; } + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) FilteredEntryBiMap(BiMap delegate, Predicate> predicate) { super(delegate, predicate); this.inverse = @@ -3217,7 +3371,7 @@ BiMap unfiltered() { } @Override - public V forcePut(@Nullable K key, @Nullable V value) { + public @Nullable V forcePut(K key, V value) { checkArgument(apply(key, value)); return unfiltered().forcePut(key, value); } @@ -3262,8 +3416,8 @@ public Set values() { * @since 12.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap unmodifiableNavigableMap( - NavigableMap map) { + public static + NavigableMap unmodifiableNavigableMap(NavigableMap map) { checkNotNull(map); if (map instanceof UnmodifiableNavigableMap) { @SuppressWarnings("unchecked") // covariant @@ -3274,14 +3428,14 @@ public static NavigableMap unmodifiableNavigableMap( } } - private static @Nullable Entry unmodifiableOrNull( - @Nullable Entry entry) { + private static @Nullable + Entry unmodifiableOrNull(@Nullable Entry entry) { return (entry == null) ? null : Maps.unmodifiableEntry(entry); } @GwtIncompatible // NavigableMap - static class UnmodifiableNavigableMap extends ForwardingSortedMap - implements NavigableMap, Serializable { + static class UnmodifiableNavigableMap + extends ForwardingSortedMap implements NavigableMap, Serializable { private final NavigableMap delegate; UnmodifiableNavigableMap(NavigableMap delegate) { @@ -3300,62 +3454,62 @@ protected SortedMap delegate() { } @Override - public Entry lowerEntry(K key) { + public @Nullable Entry lowerEntry(K key) { return unmodifiableOrNull(delegate.lowerEntry(key)); } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return delegate.lowerKey(key); } @Override - public Entry floorEntry(K key) { + public @Nullable Entry floorEntry(K key) { return unmodifiableOrNull(delegate.floorEntry(key)); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return delegate.floorKey(key); } @Override - public Entry ceilingEntry(K key) { + public @Nullable Entry ceilingEntry(K key) { return unmodifiableOrNull(delegate.ceilingEntry(key)); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return delegate.ceilingKey(key); } @Override - public Entry higherEntry(K key) { + public @Nullable Entry higherEntry(K key) { return unmodifiableOrNull(delegate.higherEntry(key)); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return delegate.higherKey(key); } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return unmodifiableOrNull(delegate.firstEntry()); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return unmodifiableOrNull(delegate.lastEntry()); } @Override - public final Entry pollFirstEntry() { + public final @Nullable Entry pollFirstEntry() { throw new UnsupportedOperationException(); } @Override - public final Entry pollLastEntry() { + public final @Nullable Entry pollLastEntry() { throw new UnsupportedOperationException(); } @@ -3467,8 +3621,8 @@ public NavigableMap tailMap(K fromKey, boolean inclusive) { * @since 13.0 */ @GwtIncompatible // NavigableMap - public static NavigableMap synchronizedNavigableMap( - NavigableMap navigableMap) { + public static + NavigableMap synchronizedNavigableMap(NavigableMap navigableMap) { return Synchronized.navigableMap(navigableMap); } @@ -3477,7 +3631,9 @@ public static NavigableMap synchronizedNavigableMap( * entrySet views. */ @GwtCompatible - abstract static class ViewCachingAbstractMap extends AbstractMap { + abstract static class ViewCachingAbstractMap< + K, V> + extends AbstractMap { /** * Creates the entry set to be returned by {@link #entrySet()}. This method is invoked at most * once on a given map, at the time when {@code entrySet} is first called. @@ -3517,7 +3673,9 @@ Collection createValues() { } } - abstract static class IteratorBasedAbstractMap extends AbstractMap { + abstract static class IteratorBasedAbstractMap< + K, V> + extends AbstractMap { @Override public abstract int size(); @@ -3567,7 +3725,8 @@ public void clear() { * Delegates to {@link Map#get}. Returns {@code null} on {@code ClassCastException} and {@code * NullPointerException}. */ - static V safeGet(Map map, @Nullable Object key) { + static @Nullable V safeGet( + Map map, @Nullable Object key) { checkNotNull(map); try { return map.get(key); @@ -3580,7 +3739,8 @@ static V safeGet(Map map, @Nullable Object key) { * Delegates to {@link Map#containsKey}. Returns {@code false} on {@code ClassCastException} and * {@code NullPointerException}. */ - static boolean safeContainsKey(Map map, Object key) { + static boolean safeContainsKey( + Map map, @Nullable Object key) { checkNotNull(map); try { return map.containsKey(key); @@ -3593,7 +3753,8 @@ static boolean safeContainsKey(Map map, Object key) { * Delegates to {@link Map#remove}. Returns {@code null} on {@code ClassCastException} and {@code * NullPointerException}. */ - static V safeRemove(Map map, Object key) { + static @Nullable V safeRemove( + Map map, @Nullable Object key) { checkNotNull(map); try { return map.remove(key); @@ -3603,12 +3764,14 @@ static V safeRemove(Map map, Object key) { } /** An admittedly inefficient implementation of {@link Map#containsKey}. */ - static boolean containsKeyImpl(Map map, @Nullable Object key) { + static boolean containsKeyImpl( + Map map, @Nullable Object key) { return Iterators.contains(keyIterator(map.entrySet().iterator()), key); } /** An implementation of {@link Map#containsValue}. */ - static boolean containsValueImpl(Map map, @Nullable Object value) { + static boolean containsValueImpl( + Map map, @Nullable Object value) { return Iterators.contains(valueIterator(map.entrySet().iterator()), value); } @@ -3624,11 +3787,13 @@ static boolean containsValueImpl(Map map, @Nullable Object value) { * @param o the object that might be contained in {@code c} * @return {@code true} if {@code c} contains {@code o} */ - static boolean containsEntryImpl(Collection> c, Object o) { + static boolean containsEntryImpl( + Collection> c, @Nullable Object o) { if (!(o instanceof Entry)) { return false; } - return c.contains(unmodifiableEntry((Entry) o)); + return c.contains( + unmodifiableEntry((Entry) o)); } /** @@ -3642,19 +3807,23 @@ static boolean containsEntryImpl(Collection> c, Object o) { * @param o the object to remove from {@code c} * @return {@code true} if {@code c} was changed */ - static boolean removeEntryImpl(Collection> c, Object o) { + static boolean removeEntryImpl( + Collection> c, @Nullable Object o) { if (!(o instanceof Entry)) { return false; } - return c.remove(unmodifiableEntry((Entry) o)); + return c.remove( + unmodifiableEntry((Entry) o)); } /** An implementation of {@link Map#equals}. */ - static boolean equalsImpl(Map map, Object object) { + static boolean equalsImpl( + Map map, @Nullable Object object) { if (map == object) { return true; } else if (object instanceof Map) { - Map o = (Map) object; + Map o = + (Map) object; return map.entrySet().equals(o.entrySet()); } return false; @@ -3675,13 +3844,15 @@ static String toStringImpl(Map map) { } /** An implementation of {@link Map#putAll}. */ - static void putAllImpl(Map self, Map map) { + static void putAllImpl( + Map self, Map map) { for (Entry entry : map.entrySet()) { self.put(entry.getKey(), entry.getValue()); } } - static class KeySet extends Sets.ImprovedAbstractSet { + static class KeySet + extends Sets.ImprovedAbstractSet { @Weak final Map map; KeySet(Map map) { @@ -3715,12 +3886,12 @@ public boolean isEmpty() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return map().containsKey(o); } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (contains(o)) { map().remove(o); return true; @@ -3734,15 +3905,18 @@ public void clear() { } } - static @Nullable K keyOrNull(@Nullable Entry entry) { + static @Nullable K keyOrNull( + @Nullable Entry entry) { return (entry == null) ? null : entry.getKey(); } - static @Nullable V valueOrNull(@Nullable Entry entry) { + static @Nullable V valueOrNull( + @Nullable Entry entry) { return (entry == null) ? null : entry.getValue(); } - static class SortedKeySet extends KeySet implements SortedSet { + static class SortedKeySet + extends KeySet implements SortedSet { SortedKeySet(SortedMap map) { super(map); } @@ -3753,7 +3927,7 @@ SortedMap map() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return map().comparator(); } @@ -3784,7 +3958,8 @@ public K last() { } @GwtIncompatible // NavigableMap - static class NavigableKeySet extends SortedKeySet implements NavigableSet { + static class NavigableKeySet + extends SortedKeySet implements NavigableSet { NavigableKeySet(NavigableMap map) { super(map); } @@ -3795,32 +3970,32 @@ NavigableMap map() { } @Override - public K lower(K e) { + public @Nullable K lower(K e) { return map().lowerKey(e); } @Override - public K floor(K e) { + public @Nullable K floor(K e) { return map().floorKey(e); } @Override - public K ceiling(K e) { + public @Nullable K ceiling(K e) { return map().ceilingKey(e); } @Override - public K higher(K e) { + public @Nullable K higher(K e) { return map().higherKey(e); } @Override - public K pollFirst() { + public @Nullable K pollFirst() { return keyOrNull(map().pollFirstEntry()); } @Override - public K pollLast() { + public @Nullable K pollLast() { return keyOrNull(map().pollLastEntry()); } @@ -3866,7 +4041,8 @@ public SortedSet tailSet(K fromElement) { } } - static class Values extends AbstractCollection { + static class Values + extends AbstractCollection { @Weak final Map map; Values(Map map) { @@ -3890,7 +4066,7 @@ public void forEach(Consumer action) { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { try { return super.remove(o); } catch (UnsupportedOperationException e) { @@ -3955,7 +4131,8 @@ public void clear() { } } - abstract static class EntrySet extends Sets.ImprovedAbstractSet> { + abstract static class EntrySet + extends Sets.ImprovedAbstractSet> { abstract Map map(); @Override @@ -3969,9 +4146,10 @@ public void clear() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { if (o instanceof Entry) { - Entry entry = (Entry) o; + Entry entry = + (Entry) o; Object key = entry.getKey(); V value = Maps.safeGet(map(), key); return Objects.equal(value, entry.getValue()) && (value != null || map().containsKey(key)); @@ -3985,9 +4163,11 @@ public boolean isEmpty() { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (contains(o)) { - Entry entry = (Entry) o; + // requireNonNull is safe because of the contains check. + Entry entry = + requireNonNull((Entry) o); return map().keySet().remove(entry.getKey()); } return false; @@ -4009,10 +4189,12 @@ public boolean retainAll(Collection c) { return super.retainAll(checkNotNull(c)); } catch (UnsupportedOperationException e) { // if the iterators don't support remove - Set keys = Sets.newHashSetWithExpectedSize(c.size()); + Set<@Nullable Object> keys = Sets.newHashSetWithExpectedSize(c.size()); for (Object o : c) { if (contains(o)) { - Entry entry = (Entry) o; + // requireNonNull is safe because of the contains check. + Entry entry = + requireNonNull((Entry) o); keys.add(entry.getKey()); } } @@ -4022,8 +4204,8 @@ public boolean retainAll(Collection c) { } @GwtIncompatible // NavigableMap - abstract static class DescendingMap extends ForwardingMap - implements NavigableMap { + abstract static class DescendingMap + extends ForwardingMap implements NavigableMap { abstract NavigableMap forward(); @@ -4064,62 +4246,62 @@ public K lastKey() { } @Override - public Entry lowerEntry(K key) { + public @Nullable Entry lowerEntry(K key) { return forward().higherEntry(key); } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { return forward().higherKey(key); } @Override - public Entry floorEntry(K key) { + public @Nullable Entry floorEntry(K key) { return forward().ceilingEntry(key); } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { return forward().ceilingKey(key); } @Override - public Entry ceilingEntry(K key) { + public @Nullable Entry ceilingEntry(K key) { return forward().floorEntry(key); } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { return forward().floorKey(key); } @Override - public Entry higherEntry(K key) { + public @Nullable Entry higherEntry(K key) { return forward().lowerEntry(key); } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { return forward().lowerKey(key); } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return forward().lastEntry(); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return forward().firstEntry(); } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { return forward().pollLastEntry(); } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { return forward().pollFirstEntry(); } @@ -4215,7 +4397,7 @@ public String toString() { } /** Returns a map from the ith element of list to i. */ - static ImmutableMap indexMap(Collection list) { + static ImmutableMap indexMap(Collection list) { ImmutableMap.Builder builder = new ImmutableMap.Builder<>(list.size()); int i = 0; for (E e : list) { @@ -4242,14 +4424,15 @@ static ImmutableMap indexMap(Collection list) { */ @Beta @GwtIncompatible // NavigableMap - public static , V> NavigableMap subMap( - NavigableMap map, Range range) { - if (map.comparator() != null - && map.comparator() != Ordering.natural() + public static , V> + NavigableMap subMap(NavigableMap map, Range range) { + Comparator comparator = map.comparator(); + if (comparator != null + && comparator != Ordering.natural() && range.hasLowerBound() && range.hasUpperBound()) { checkArgument( - map.comparator().compare(range.lowerEndpoint(), range.upperEndpoint()) <= 0, + comparator.compare(range.lowerEndpoint(), range.upperEndpoint()) <= 0, "map is using a custom comparator which is inconsistent with the natural ordering."); } if (range.hasLowerBound() && range.hasUpperBound()) { @@ -4265,4 +4448,20 @@ public static , V> NavigableMap subMap( } return checkNotNull(map); } + + @SuppressWarnings("nullness") + private static V unsafeNull() { + return null; + } + + @SuppressWarnings("nullness") + private static V uncheckedCastNullableVToV(@Nullable V value) { + /* + * We can't use requireNonNull because `value` might be null. Specifically, it can be null + * because the map might contain a null value to be returned to the user. This is in contrast to + * the other way for the result of map.get to be null, which is for the map not to have a value + * associated with the given key. + */ + return value; + } } diff --git a/guava/src/com/google/common/collect/MinMaxPriorityQueue.java b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java index 32cebefd4d99..079c3beb6cae 100644 --- a/guava/src/com/google/common/collect/MinMaxPriorityQueue.java +++ b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java @@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkPositionIndex; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.CollectPreconditions.checkRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -41,6 +42,7 @@ import java.util.NoSuchElementException; import java.util.PriorityQueue; import java.util.Queue; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -98,7 +100,7 @@ */ @Beta @GwtCompatible -public final class MinMaxPriorityQueue extends AbstractQueue { +public final class MinMaxPriorityQueue extends AbstractQueue { /** * Creates a new min-max priority queue with default settings: natural order, no maximum size, no @@ -121,7 +123,8 @@ public static > MinMaxPriorityQueue create( * Creates and returns a new builder, configured to build {@code MinMaxPriorityQueue} instances * that use {@code comparator} to determine the least and greatest elements. */ - public static Builder orderedBy(Comparator comparator) { + // TODO(cpovirk): Permit Comparator<@Nullable ...> with Comparator<@PolyNull B> ? + public static Builder orderedBy(Comparator comparator) { return new Builder(comparator); } @@ -154,7 +157,7 @@ public static Builder maximumSize(int maximumSize) { * @since 8.0 */ @Beta - public static final class Builder { + public static final class Builder { /* * TODO(kevinb): when the dust settles, see if we still need this or can * just default to DEFAULT_CAPACITY. @@ -224,7 +227,7 @@ private Ordering ordering() { private final Heap minHeap; private final Heap maxHeap; @VisibleForTesting final int maximumSize; - private Object[] queue; + private @Nullable Object[] queue; private int size; private int modCount; @@ -237,7 +240,7 @@ private MinMaxPriorityQueue(Builder builder, int queueSize) { this.maximumSize = builder.maximumSize; // TODO(kevinb): pad? - this.queue = new Object[queueSize]; + this.queue = new @Nullable Object[queueSize]; } @Override @@ -292,17 +295,21 @@ public boolean offer(E element) { @CanIgnoreReturnValue @Override - public E poll() { + public @Nullable E poll() { return isEmpty() ? null : removeAndGet(0); } @SuppressWarnings("unchecked") // we must carefully only allow Es to get in E elementData(int index) { - return (E) queue[index]; + /* + * requireNonNull is safe as long as we're careful to call this method only with populated + * indexes. + */ + return (E) requireNonNull(queue[index]); } @Override - public E peek() { + public @Nullable E peek() { return isEmpty() ? null : elementData(0); } @@ -325,7 +332,7 @@ private int getMaxElementIndex() { * empty. */ @CanIgnoreReturnValue - public E pollFirst() { + public @Nullable E pollFirst() { return poll(); } @@ -343,7 +350,7 @@ public E removeFirst() { * Retrieves, but does not remove, the least element of this queue, or returns {@code null} if the * queue is empty. */ - public E peekFirst() { + public @Nullable E peekFirst() { return peek(); } @@ -352,7 +359,7 @@ public E peekFirst() { * empty. */ @CanIgnoreReturnValue - public E pollLast() { + public @Nullable E pollLast() { return isEmpty() ? null : removeAndGet(getMaxElementIndex()); } @@ -373,7 +380,7 @@ public E removeLast() { * Retrieves, but does not remove, the greatest element of this queue, or returns {@code null} if * the queue is empty. */ - public E peekLast() { + public @Nullable E peekLast() { return isEmpty() ? null : elementData(getMaxElementIndex()); } @@ -392,6 +399,7 @@ public E peekLast() { */ @VisibleForTesting @CanIgnoreReturnValue + @Nullable MoveDesc removeAt(int index) { checkPositionIndex(index, size); modCount++; @@ -427,7 +435,7 @@ MoveDesc removeAt(int index) { return changes; } - private MoveDesc fillHole(int index, E toTrickle) { + private @Nullable MoveDesc fillHole(int index, E toTrickle) { Heap heap = heapForIndex(index); // We consider elementData(index) a "hole", and we want to fill it // with the last element of the heap, toTrickle. @@ -504,8 +512,10 @@ boolean isIntact() { @WeakOuter private class Heap { final Ordering ordering; - @Weak @Nullable Heap otherHeap; + @Weak Heap otherHeap; + // otherHeap is initialized immediately after construction. + @SuppressWarnings("nullness") Heap(Ordering ordering) { this.ordering = ordering; } @@ -518,6 +528,7 @@ int compareElements(int a, int b) { * Tries to move {@code toTrickle} from a min to a max level and bubble up there. If it moved * before {@code removeIndex} this method returns a pair as described in {@link #removeAt}. */ + @Nullable MoveDesc tryCrossOverAndBubbleUp(int removeIndex, int vacated, E toTrickle) { int crossOver = crossOver(vacated, toTrickle); if (crossOver == vacated) { @@ -795,6 +806,8 @@ public void remove() { forgetMeNot = new ArrayDeque(); skipMe = new ArrayList(3); } + // requireNonNull is safe because skipMe is initialized along with forgetMeNot. + requireNonNull(skipMe); if (!foundAndRemovedExactReference(skipMe, moved.toTrickle)) { forgetMeNot.add(moved.toTrickle); } @@ -805,7 +818,7 @@ public void remove() { cursor--; nextCursor--; } else { // we must have set lastFromForgetMeNot in next() - checkState(removeExact(lastFromForgetMeNot)); + checkState(removeExact(requireNonNull(lastFromForgetMeNot))); lastFromForgetMeNot = null; } } @@ -888,6 +901,7 @@ public void clear() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { Object[] copyTo = new Object[size]; System.arraycopy(queue, 0, copyTo, 0, size); diff --git a/guava/src/com/google/common/collect/MoreCollectors.java b/guava/src/com/google/common/collect/MoreCollectors.java index f447ebeb3b54..18daf8ed4010 100644 --- a/guava/src/com/google/common/collect/MoreCollectors.java +++ b/guava/src/com/google/common/collect/MoreCollectors.java @@ -17,6 +17,7 @@ package com.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import java.util.ArrayList; @@ -24,6 +25,7 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -55,14 +57,14 @@ public final class MoreCollectors { * which is null. */ @SuppressWarnings("unchecked") - public static Collector> toOptional() { + public static Collector> toOptional() { return (Collector) TO_OPTIONAL; } private static final Object NULL_PLACEHOLDER = new Object(); - private static final Collector ONLY_ELEMENT = - Collector.of( + private static final Collector<@Nullable Object, ?, @Nullable Object> ONLY_ELEMENT = + Collector.<@Nullable Object, ToOptionalState, @Nullable Object>of( ToOptionalState::new, (state, o) -> state.add((o == null) ? NULL_PLACEHOLDER : o), ToOptionalState::combine, @@ -100,7 +102,8 @@ private static final class ToOptionalState { IllegalArgumentException multiples(boolean overflow) { StringBuilder sb = new StringBuilder().append("expected one element but was: <").append(element); - for (Object o : extras) { + // requireNonNull is safe because we call this method only when extras exist. + for (Object o : requireNonNull(extras)) { sb.append(", ").append(o); } if (overflow) { diff --git a/guava/src/com/google/common/collect/Multimap.java b/guava/src/com/google/common/collect/Multimap.java index ec2b9ef2c544..ab681728d590 100644 --- a/guava/src/com/google/common/collect/Multimap.java +++ b/guava/src/com/google/common/collect/Multimap.java @@ -21,7 +21,6 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CompatibleWith; -import com.google.errorprone.annotations.DoNotMock; import java.util.Collection; import java.util.List; import java.util.Map; @@ -159,7 +158,6 @@ * @author Jared Levy * @since 2.0 */ -@DoNotMock("Use ImmutableMultimap, HashMultimap, or another implementation") @GwtCompatible public interface Multimap { // Query Operations @@ -211,7 +209,7 @@ boolean containsEntry( * multimap already contained the key-value pair and doesn't allow duplicates */ @CanIgnoreReturnValue - boolean put(@Nullable K key, @Nullable V value); + boolean put(K key, V value); /** * Removes a single key-value pair with the key {@code key} and the value {@code value} from this @@ -241,7 +239,7 @@ boolean remove( * @return {@code true} if the multimap changed */ @CanIgnoreReturnValue - boolean putAll(@Nullable K key, Iterable values); + boolean putAll(K key, Iterable values); /** * Stores all key-value pairs of {@code multimap} in this multimap, in the order returned by @@ -262,7 +260,7 @@ boolean remove( * no effect on the multimap. */ @CanIgnoreReturnValue - Collection replaceValues(@Nullable K key, Iterable values); + Collection replaceValues(K key, Iterable values); /** * Removes all values associated with the key {@code key}. @@ -288,7 +286,7 @@ boolean remove( * *

    Changes to the returned collection will update the underlying multimap, and vice versa. */ - Collection get(@Nullable K key); + Collection get(K key); /** * Returns a view collection of all distinct keys contained in this multimap. Note that the diff --git a/guava/src/com/google/common/collect/MultimapBuilder.java b/guava/src/com/google/common/collect/MultimapBuilder.java index 161c29d170ee..5dcee8e3472e 100644 --- a/guava/src/com/google/common/collect/MultimapBuilder.java +++ b/guava/src/com/google/common/collect/MultimapBuilder.java @@ -34,6 +34,7 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A builder for a multimap implementation that allows customization of the backing map and value @@ -72,7 +73,7 @@ private MultimapBuilder() {} private static final int DEFAULT_EXPECTED_KEYS = 8; /** Uses a hash table to map keys to value collections. */ - public static MultimapBuilderWithKeys hashKeys() { + public static MultimapBuilderWithKeys<@Nullable Object> hashKeys() { return hashKeys(DEFAULT_EXPECTED_KEYS); } @@ -82,9 +83,9 @@ public static MultimapBuilderWithKeys hashKeys() { * * @throws IllegalArgumentException if {@code expectedKeys < 0} */ - public static MultimapBuilderWithKeys hashKeys(final int expectedKeys) { + public static MultimapBuilderWithKeys<@Nullable Object> hashKeys(final int expectedKeys) { checkNonnegative(expectedKeys, "expectedKeys"); - return new MultimapBuilderWithKeys() { + return new MultimapBuilderWithKeys<@Nullable Object>() { @Override Map> createMap() { return Platform.newHashMapWithExpectedSize(expectedKeys); @@ -100,7 +101,7 @@ Map> createMap() { * multimap, save that if all values associated with a key are removed and then the key is added * back into the multimap, that key will come last in the key iteration order. */ - public static MultimapBuilderWithKeys linkedHashKeys() { + public static MultimapBuilderWithKeys<@Nullable Object> linkedHashKeys() { return linkedHashKeys(DEFAULT_EXPECTED_KEYS); } @@ -113,9 +114,9 @@ public static MultimapBuilderWithKeys linkedHashKeys() { * multimap, save that if all values associated with a key are removed and then the key is added * back into the multimap, that key will come last in the key iteration order. */ - public static MultimapBuilderWithKeys linkedHashKeys(final int expectedKeys) { + public static MultimapBuilderWithKeys<@Nullable Object> linkedHashKeys(final int expectedKeys) { checkNonnegative(expectedKeys, "expectedKeys"); - return new MultimapBuilderWithKeys() { + return new MultimapBuilderWithKeys<@Nullable Object>() { @Override Map> createMap() { return Platform.newLinkedHashMapWithExpectedSize(expectedKeys); @@ -151,7 +152,8 @@ public static MultimapBuilderWithKeys treeKeys() { *

    Multimaps generated by the resulting builder will not be serializable if {@code comparator} * is not serializable. */ - public static MultimapBuilderWithKeys treeKeys(final Comparator comparator) { + public static MultimapBuilderWithKeys treeKeys( + final Comparator comparator) { checkNotNull(comparator); return new MultimapBuilderWithKeys() { @Override @@ -180,7 +182,8 @@ Map> createMap() { }; } - private static final class ArrayListSupplier implements Supplier>, Serializable { + private static final class ArrayListSupplier + implements Supplier>, Serializable { private final int expectedValuesPerKey; ArrayListSupplier(int expectedValuesPerKey) { @@ -193,23 +196,24 @@ public List get() { } } - private enum LinkedListSupplier implements Supplier> { + private enum LinkedListSupplier implements Supplier> { INSTANCE; public static Supplier> instance() { // Each call generates a fresh LinkedList, which can serve as a List for any V. - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings({"rawtypes", "unchecked", "nullness"}) Supplier> result = (Supplier) INSTANCE; return result; } @Override - public List get() { + public List<@Nullable Object> get() { return new LinkedList<>(); } } - private static final class HashSetSupplier implements Supplier>, Serializable { + private static final class HashSetSupplier + implements Supplier>, Serializable { private final int expectedValuesPerKey; HashSetSupplier(int expectedValuesPerKey) { @@ -222,7 +226,8 @@ public Set get() { } } - private static final class LinkedHashSetSupplier implements Supplier>, Serializable { + private static final class LinkedHashSetSupplier + implements Supplier>, Serializable { private final int expectedValuesPerKey; LinkedHashSetSupplier(int expectedValuesPerKey) { @@ -235,7 +240,8 @@ public Set get() { } } - private static final class TreeSetSupplier implements Supplier>, Serializable { + private static final class TreeSetSupplier + implements Supplier>, Serializable { private final Comparator comparator; TreeSetSupplier(Comparator comparator) { @@ -278,7 +284,7 @@ public abstract static class MultimapBuilderWithKeys { abstract Map> createMap(); /** Uses an {@link ArrayList} to store value collections. */ - public ListMultimapBuilder arrayListValues() { + public ListMultimapBuilder arrayListValues() { return arrayListValues(DEFAULT_EXPECTED_VALUES_PER_KEY); } @@ -288,9 +294,10 @@ public ListMultimapBuilder arrayListValues() { * * @throws IllegalArgumentException if {@code expectedValuesPerKey < 0} */ - public ListMultimapBuilder arrayListValues(final int expectedValuesPerKey) { + public ListMultimapBuilder arrayListValues( + final int expectedValuesPerKey) { checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); - return new ListMultimapBuilder() { + return new ListMultimapBuilder() { @Override public ListMultimap build() { return Multimaps.newListMultimap( @@ -301,8 +308,8 @@ public ListMultimap build() { } /** Uses a {@link LinkedList} to store value collections. */ - public ListMultimapBuilder linkedListValues() { - return new ListMultimapBuilder() { + public ListMultimapBuilder linkedListValues() { + return new ListMultimapBuilder() { @Override public ListMultimap build() { return Multimaps.newListMultimap( @@ -312,7 +319,7 @@ public ListMultimap build() { } /** Uses a hash-based {@code Set} to store value collections. */ - public SetMultimapBuilder hashSetValues() { + public SetMultimapBuilder hashSetValues() { return hashSetValues(DEFAULT_EXPECTED_VALUES_PER_KEY); } @@ -322,9 +329,9 @@ public SetMultimapBuilder hashSetValues() { * * @throws IllegalArgumentException if {@code expectedValuesPerKey < 0} */ - public SetMultimapBuilder hashSetValues(final int expectedValuesPerKey) { + public SetMultimapBuilder hashSetValues(final int expectedValuesPerKey) { checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); - return new SetMultimapBuilder() { + return new SetMultimapBuilder() { @Override public SetMultimap build() { return Multimaps.newSetMultimap( @@ -335,7 +342,7 @@ public SetMultimap build() { } /** Uses an insertion-ordered hash-based {@code Set} to store value collections. */ - public SetMultimapBuilder linkedHashSetValues() { + public SetMultimapBuilder linkedHashSetValues() { return linkedHashSetValues(DEFAULT_EXPECTED_VALUES_PER_KEY); } @@ -345,9 +352,10 @@ public SetMultimapBuilder linkedHashSetValues() { * * @throws IllegalArgumentException if {@code expectedValuesPerKey < 0} */ - public SetMultimapBuilder linkedHashSetValues(final int expectedValuesPerKey) { + public SetMultimapBuilder linkedHashSetValues( + final int expectedValuesPerKey) { checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); - return new SetMultimapBuilder() { + return new SetMultimapBuilder() { @Override public SetMultimap build() { return Multimaps.newSetMultimap( @@ -369,7 +377,8 @@ public SortedSetMultimapBuilder treeSetValues() { *

    Multimaps generated by the resulting builder will not be serializable if {@code * comparator} is not serializable. */ - public SortedSetMultimapBuilder treeSetValues(final Comparator comparator) { + public SortedSetMultimapBuilder treeSetValues( + final Comparator comparator) { checkNotNull(comparator, "comparator"); return new SortedSetMultimapBuilder() { @Override @@ -416,7 +425,9 @@ public Multimap build( * * @since 16.0 */ - public abstract static class ListMultimapBuilder extends MultimapBuilder { + public abstract static class ListMultimapBuilder< + K0, V0> + extends MultimapBuilder { ListMultimapBuilder() {} @Override @@ -434,7 +445,9 @@ public ListMultimap build( * * @since 16.0 */ - public abstract static class SetMultimapBuilder extends MultimapBuilder { + public abstract static class SetMultimapBuilder< + K0, V0> + extends MultimapBuilder { SetMultimapBuilder() {} @Override diff --git a/guava/src/com/google/common/collect/Multimaps.java b/guava/src/com/google/common/collect/Multimaps.java index 1e29734df3fd..0615c673cbe0 100644 --- a/guava/src/com/google/common/collect/Multimaps.java +++ b/guava/src/com/google/common/collect/Multimaps.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; import static com.google.common.collect.CollectPreconditions.checkRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -52,6 +53,7 @@ import java.util.function.Consumer; import java.util.stream.Collector; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -104,10 +106,15 @@ private Multimaps() {} * @since 21.0 */ @Beta - public static > Collector toMultimap( - java.util.function.Function keyFunction, - java.util.function.Function valueFunction, - java.util.function.Supplier multimapSupplier) { + public static < + T, + K, + V, + M extends Multimap> + Collector toMultimap( + java.util.function.Function keyFunction, + java.util.function.Function valueFunction, + java.util.function.Supplier multimapSupplier) { checkNotNull(keyFunction); checkNotNull(valueFunction); checkNotNull(multimapSupplier); @@ -154,10 +161,15 @@ private Multimaps() {} * @since 21.0 */ @Beta - public static > Collector flatteningToMultimap( - java.util.function.Function keyFunction, - java.util.function.Function> valueFunction, - java.util.function.Supplier multimapSupplier) { + public static < + T, + K, + V, + M extends Multimap> + Collector flatteningToMultimap( + java.util.function.Function keyFunction, + java.util.function.Function> valueFunction, + java.util.function.Supplier multimapSupplier) { checkNotNull(keyFunction); checkNotNull(valueFunction); checkNotNull(multimapSupplier); @@ -215,7 +227,8 @@ public static Multimap newMultimap( return new CustomMultimap<>(map, factory); } - private static class CustomMultimap extends AbstractMapBasedMultimap { + private static class CustomMultimap + extends AbstractMapBasedMultimap { transient Supplier> factory; CustomMultimap(Map> map, Supplier> factory) { @@ -239,7 +252,8 @@ protected Collection createCollection() { } @Override - Collection unmodifiableCollectionSubclass(Collection collection) { + Collection unmodifiableCollectionSubclass( + Collection collection) { if (collection instanceof NavigableSet) { return Sets.unmodifiableNavigableSet((NavigableSet) collection); } else if (collection instanceof SortedSet) { @@ -322,12 +336,14 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo * @param factory supplier of new, empty lists that will each hold all values for a given key * @throws IllegalArgumentException if {@code map} is not empty */ - public static ListMultimap newListMultimap( - Map> map, final Supplier> factory) { + public static + ListMultimap newListMultimap( + Map> map, final Supplier> factory) { return new CustomListMultimap<>(map, factory); } - private static class CustomListMultimap extends AbstractListMultimap { + private static class CustomListMultimap + extends AbstractListMultimap { transient Supplier> factory; CustomListMultimap(Map> map, Supplier> factory) { @@ -400,12 +416,14 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo * @param factory supplier of new, empty sets that will each hold all values for a given key * @throws IllegalArgumentException if {@code map} is not empty */ - public static SetMultimap newSetMultimap( - Map> map, final Supplier> factory) { + public static + SetMultimap newSetMultimap( + Map> map, final Supplier> factory) { return new CustomSetMultimap<>(map, factory); } - private static class CustomSetMultimap extends AbstractSetMultimap { + private static class CustomSetMultimap + extends AbstractSetMultimap { transient Supplier> factory; CustomSetMultimap(Map> map, Supplier> factory) { @@ -429,7 +447,8 @@ protected Set createCollection() { } @Override - Collection unmodifiableCollectionSubclass(Collection collection) { + Collection unmodifiableCollectionSubclass( + Collection collection) { if (collection instanceof NavigableSet) { return Sets.unmodifiableNavigableSet((NavigableSet) collection); } else if (collection instanceof SortedSet) { @@ -440,6 +459,8 @@ Collection unmodifiableCollectionSubclass(Collection collection) { } @Override + // https://github.com/typetools/checker-framework/issues/3022 + @SuppressWarnings("argument.type.incompatible") Collection wrapCollection(K key, Collection collection) { if (collection instanceof NavigableSet) { return new WrappedNavigableSet(key, (NavigableSet) collection, null); @@ -500,14 +521,17 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo * key * @throws IllegalArgumentException if {@code map} is not empty */ - public static SortedSetMultimap newSortedSetMultimap( - Map> map, final Supplier> factory) { + public static + SortedSetMultimap newSortedSetMultimap( + Map> map, final Supplier> factory) { return new CustomSortedSetMultimap<>(map, factory); } - private static class CustomSortedSetMultimap extends AbstractSortedSetMultimap { + private static class CustomSortedSetMultimap< + K, V> + extends AbstractSortedSetMultimap { transient Supplier> factory; - transient Comparator valueComparator; + transient @Nullable Comparator valueComparator; CustomSortedSetMultimap(Map> map, Supplier> factory) { super(map); @@ -531,7 +555,7 @@ protected SortedSet createCollection() { } @Override - public Comparator valueComparator() { + public @Nullable Comparator valueComparator() { return valueComparator; } @@ -569,8 +593,8 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo * @return {@code dest} */ @CanIgnoreReturnValue - public static > M invertFrom( - Multimap source, M dest) { + public static > + M invertFrom(Multimap source, M dest) { checkNotNull(dest); for (Map.Entry entry : source.entries()) { dest.put(entry.getValue(), entry.getKey()); @@ -610,7 +634,8 @@ public static > M invertFrom( * @param multimap the multimap to be wrapped in a synchronized view * @return a synchronized view of the specified multimap */ - public static Multimap synchronizedMultimap(Multimap multimap) { + public static + Multimap synchronizedMultimap(Multimap multimap) { return Synchronized.multimap(multimap, null); } @@ -625,7 +650,8 @@ public static Multimap synchronizedMultimap(Multimap multimap * @param delegate the multimap for which an unmodifiable view is to be returned * @return an unmodifiable view of the specified multimap */ - public static Multimap unmodifiableMultimap(Multimap delegate) { + public static + Multimap unmodifiableMultimap(Multimap delegate) { if (delegate instanceof UnmodifiableMultimap || delegate instanceof ImmutableMultimap) { return delegate; } @@ -639,12 +665,13 @@ public static Multimap unmodifiableMultimap(Multimap delegate * @since 10.0 */ @Deprecated - public static Multimap unmodifiableMultimap(ImmutableMultimap delegate) { + public static + Multimap unmodifiableMultimap(ImmutableMultimap delegate) { return checkNotNull(delegate); } - private static class UnmodifiableMultimap extends ForwardingMultimap - implements Serializable { + private static class UnmodifiableMultimap + extends ForwardingMultimap implements Serializable { final Multimap delegate; transient @Nullable Collection> entries; transient @Nullable Multiset keys; @@ -733,12 +760,12 @@ public boolean putAll(Multimap multimap) { } @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { throw new UnsupportedOperationException(); } @Override - public Collection removeAll(Object key) { + public Collection removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -759,8 +786,9 @@ public Collection values() { private static final long serialVersionUID = 0; } - private static class UnmodifiableListMultimap extends UnmodifiableMultimap - implements ListMultimap { + private static class UnmodifiableListMultimap< + K, V> + extends UnmodifiableMultimap implements ListMultimap { UnmodifiableListMultimap(ListMultimap delegate) { super(delegate); } @@ -776,7 +804,7 @@ public List get(K key) { } @Override - public List removeAll(Object key) { + public List removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -788,8 +816,9 @@ public List replaceValues(K key, Iterable values) { private static final long serialVersionUID = 0; } - private static class UnmodifiableSetMultimap extends UnmodifiableMultimap - implements SetMultimap { + private static class UnmodifiableSetMultimap< + K, V> + extends UnmodifiableMultimap implements SetMultimap { UnmodifiableSetMultimap(SetMultimap delegate) { super(delegate); } @@ -814,7 +843,7 @@ public Set> entries() { } @Override - public Set removeAll(Object key) { + public Set removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -826,8 +855,9 @@ public Set replaceValues(K key, Iterable values) { private static final long serialVersionUID = 0; } - private static class UnmodifiableSortedSetMultimap extends UnmodifiableSetMultimap - implements SortedSetMultimap { + private static class UnmodifiableSortedSetMultimap< + K, V> + extends UnmodifiableSetMultimap implements SortedSetMultimap { UnmodifiableSortedSetMultimap(SortedSetMultimap delegate) { super(delegate); } @@ -843,7 +873,7 @@ public SortedSet get(K key) { } @Override - public SortedSet removeAll(Object key) { + public SortedSet removeAll(@Nullable Object key) { throw new UnsupportedOperationException(); } @@ -853,7 +883,7 @@ public SortedSet replaceValues(K key, Iterable values) { } @Override - public Comparator valueComparator() { + public @Nullable Comparator valueComparator() { return delegate().valueComparator(); } @@ -870,7 +900,8 @@ public Comparator valueComparator() { * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ - public static SetMultimap synchronizedSetMultimap(SetMultimap multimap) { + public static + SetMultimap synchronizedSetMultimap(SetMultimap multimap) { return Synchronized.setMultimap(multimap, null); } @@ -885,7 +916,8 @@ public static SetMultimap synchronizedSetMultimap(SetMultimap * @param delegate the multimap for which an unmodifiable view is to be returned * @return an unmodifiable view of the specified multimap */ - public static SetMultimap unmodifiableSetMultimap(SetMultimap delegate) { + public static + SetMultimap unmodifiableSetMultimap(SetMultimap delegate) { if (delegate instanceof UnmodifiableSetMultimap || delegate instanceof ImmutableSetMultimap) { return delegate; } @@ -899,8 +931,8 @@ public static SetMultimap unmodifiableSetMultimap(SetMultimap * @since 10.0 */ @Deprecated - public static SetMultimap unmodifiableSetMultimap( - ImmutableSetMultimap delegate) { + public static + SetMultimap unmodifiableSetMultimap(ImmutableSetMultimap delegate) { return checkNotNull(delegate); } @@ -915,8 +947,8 @@ public static SetMultimap unmodifiableSetMultimap( * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ - public static SortedSetMultimap synchronizedSortedSetMultimap( - SortedSetMultimap multimap) { + public static + SortedSetMultimap synchronizedSortedSetMultimap(SortedSetMultimap multimap) { return Synchronized.sortedSetMultimap(multimap, null); } @@ -931,8 +963,8 @@ public static SortedSetMultimap synchronizedSortedSetMultimap( * @param delegate the multimap for which an unmodifiable view is to be returned * @return an unmodifiable view of the specified multimap */ - public static SortedSetMultimap unmodifiableSortedSetMultimap( - SortedSetMultimap delegate) { + public static + SortedSetMultimap unmodifiableSortedSetMultimap(SortedSetMultimap delegate) { if (delegate instanceof UnmodifiableSortedSetMultimap) { return delegate; } @@ -947,7 +979,8 @@ public static SortedSetMultimap unmodifiableSortedSetMultimap( * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ - public static ListMultimap synchronizedListMultimap(ListMultimap multimap) { + public static + ListMultimap synchronizedListMultimap(ListMultimap multimap) { return Synchronized.listMultimap(multimap, null); } @@ -962,7 +995,8 @@ public static ListMultimap synchronizedListMultimap(ListMultimap ListMultimap unmodifiableListMultimap(ListMultimap delegate) { + public static + ListMultimap unmodifiableListMultimap(ListMultimap delegate) { if (delegate instanceof UnmodifiableListMultimap || delegate instanceof ImmutableListMultimap) { return delegate; } @@ -976,8 +1010,8 @@ public static ListMultimap unmodifiableListMultimap(ListMultimap ListMultimap unmodifiableListMultimap( - ImmutableListMultimap delegate) { + public static + ListMultimap unmodifiableListMultimap(ImmutableListMultimap delegate) { return checkNotNull(delegate); } @@ -989,7 +1023,8 @@ public static ListMultimap unmodifiableListMultimap( * @param collection the collection for which to return an unmodifiable view * @return an unmodifiable view of the collection */ - private static Collection unmodifiableValueCollection(Collection collection) { + private static Collection unmodifiableValueCollection( + Collection collection) { if (collection instanceof SortedSet) { return Collections.unmodifiableSortedSet((SortedSet) collection); } else if (collection instanceof Set) { @@ -1008,8 +1043,8 @@ private static Collection unmodifiableValueCollection(Collection colle * @param entries the entries for which to return an unmodifiable view * @return an unmodifiable view of the entries */ - private static Collection> unmodifiableEntries( - Collection> entries) { + private static + Collection> unmodifiableEntries(Collection> entries) { if (entries instanceof Set) { return Maps.unmodifiableEntrySet((Set>) entries); } @@ -1025,7 +1060,8 @@ private static Collection> unmodifiableEntries( @Beta @SuppressWarnings("unchecked") // safe by specification of ListMultimap.asMap() - public static Map> asMap(ListMultimap multimap) { + public static Map> asMap( + ListMultimap multimap) { return (Map>) (Map) multimap.asMap(); } @@ -1038,7 +1074,8 @@ public static Map> asMap(ListMultimap multimap) { @Beta @SuppressWarnings("unchecked") // safe by specification of SetMultimap.asMap() - public static Map> asMap(SetMultimap multimap) { + public static Map> asMap( + SetMultimap multimap) { return (Map>) (Map) multimap.asMap(); } @@ -1051,7 +1088,8 @@ public static Map> asMap(SetMultimap multimap) { @Beta @SuppressWarnings("unchecked") // safe by specification of SortedSetMultimap.asMap() - public static Map> asMap(SortedSetMultimap multimap) { + public static Map> asMap( + SortedSetMultimap multimap) { return (Map>) (Map) multimap.asMap(); } @@ -1062,7 +1100,8 @@ public static Map> asMap(SortedSetMultimap multimap * @since 15.0 */ @Beta - public static Map> asMap(Multimap multimap) { + public static + Map> asMap(Multimap multimap) { return multimap.asMap(); } @@ -1081,13 +1120,14 @@ public static Map> asMap(Multimap multimap) { * * @param map the backing map for the returned multimap view */ - public static SetMultimap forMap(Map map) { + public static SetMultimap forMap( + Map map) { return new MapMultimap<>(map); } /** @see Multimaps#forMap */ - private static class MapMultimap extends AbstractMultimap - implements SetMultimap, Serializable { + private static class MapMultimap + extends AbstractMultimap implements SetMultimap, Serializable { final Map map; MapMultimap(Map map) { @@ -1100,17 +1140,17 @@ public int size() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return map.containsKey(key); } @Override - public boolean containsValue(Object value) { + public boolean containsValue(@Nullable Object value) { return map.containsValue(value); } @Override - public boolean containsEntry(Object key, Object value) { + public boolean containsEntry(@Nullable Object key, @Nullable Object value) { return map.entrySet().contains(Maps.immutableEntry(key, value)); } @@ -1133,7 +1173,8 @@ public V next() { throw new NoSuchElementException(); } i++; - return map.get(key); + // The cast is safe because of the containsKey check in hasNext(). + return uncheckedCastNullableVToV(map.get(key)); } @Override @@ -1173,17 +1214,18 @@ public Set replaceValues(K key, Iterable values) { } @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { return map.entrySet().remove(Maps.immutableEntry(key, value)); } @Override - public Set removeAll(Object key) { + public Set removeAll(@Nullable Object key) { Set values = new HashSet(2); if (!map.containsKey(key)) { return values; } - values.add(map.remove(key)); + // The cast is safe because of the containsKey check. + values.add(uncheckedCastNullableVToV(map.remove(key))); return values; } @@ -1235,6 +1277,17 @@ public int hashCode() { private static final long serialVersionUID = 7845222491160860175L; } + @SuppressWarnings("nullness") + private static V uncheckedCastNullableVToV(@Nullable V oldValue) { + /* + * We can't use requireNonNull because `oldValue` might be null. Specifically, it can be null + * because the map might contain a null value to be returned to the user. This is in contrast to + * the other way for the result of map.get to be null, which is for the map not to have a value + * associated with the given key. + */ + return oldValue; + } + /** * Returns a view of a multimap where each value is transformed by a function. All other * properties of the multimap, such as iteration order, are left intact. For example, the code: @@ -1276,8 +1329,10 @@ public int hashCode() { * * @since 7.0 */ - public static Multimap transformValues( - Multimap fromMultimap, final Function function) { + public static < + K, V1, V2> + Multimap transformValues( + Multimap fromMultimap, final Function function) { checkNotNull(function); EntryTransformer transformer = Maps.asEntryTransformer(function); return transformEntries(fromMultimap, transformer); @@ -1323,8 +1378,10 @@ public static Multimap transformValues( * * @since 7.0 */ - public static ListMultimap transformValues( - ListMultimap fromMultimap, final Function function) { + public static < + K, V1, V2> + ListMultimap transformValues( + ListMultimap fromMultimap, final Function function) { checkNotNull(function); EntryTransformer transformer = Maps.asEntryTransformer(function); return transformEntries(fromMultimap, transformer); @@ -1381,8 +1438,10 @@ public static ListMultimap transformValues( * * @since 7.0 */ - public static Multimap transformEntries( - Multimap fromMap, EntryTransformer transformer) { + public static < + K, V1, V2> + Multimap transformEntries( + Multimap fromMap, EntryTransformer transformer) { return new TransformedEntriesMultimap<>(fromMap, transformer); } @@ -1434,12 +1493,16 @@ public static Multimap transformEntries( * * @since 7.0 */ - public static ListMultimap transformEntries( - ListMultimap fromMap, EntryTransformer transformer) { + public static < + K, V1, V2> + ListMultimap transformEntries( + ListMultimap fromMap, EntryTransformer transformer) { return new TransformedEntriesListMultimap<>(fromMap, transformer); } - private static class TransformedEntriesMultimap extends AbstractMultimap { + private static class TransformedEntriesMultimap< + K, V1, V2> + extends AbstractMultimap { final Multimap fromMultimap; final EntryTransformer transformer; @@ -1477,7 +1540,7 @@ public void clear() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return fromMultimap.containsKey(key); } @@ -1529,13 +1592,13 @@ public boolean putAll(Multimap multimap) { @SuppressWarnings("unchecked") @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { return get((K) key).remove(value); } @SuppressWarnings("unchecked") @Override - public Collection removeAll(Object key) { + public Collection removeAll(@Nullable Object key) { return transform((K) key, fromMultimap.removeAll(key)); } @@ -1556,7 +1619,8 @@ Collection createValues() { } } - private static final class TransformedEntriesListMultimap + private static final class TransformedEntriesListMultimap< + K, V1, V2> extends TransformedEntriesMultimap implements ListMultimap { TransformedEntriesListMultimap( @@ -1576,7 +1640,7 @@ public List get(K key) { @SuppressWarnings("unchecked") @Override - public List removeAll(Object key) { + public List removeAll(@Nullable Object key) { return transform((K) key, fromMultimap.removeAll(key)); } @@ -1621,8 +1685,8 @@ public List replaceValues(K key, Iterable values) { * @throws NullPointerException if any element of {@code values} is {@code null}, or if {@code * keyFunction} produces {@code null} for any key */ - public static ImmutableListMultimap index( - Iterable values, Function keyFunction) { + public static + ImmutableListMultimap index(Iterable values, Function keyFunction) { return index(values.iterator(), keyFunction); } @@ -1662,8 +1726,8 @@ public static ImmutableListMultimap index( * keyFunction} produces {@code null} for any key * @since 10.0 */ - public static ImmutableListMultimap index( - Iterator values, Function keyFunction) { + public static + ImmutableListMultimap index(Iterator values, Function keyFunction) { checkNotNull(keyFunction); ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); while (values.hasNext()) { @@ -1674,7 +1738,8 @@ public static ImmutableListMultimap index( return builder.build(); } - static class Keys extends AbstractMultiset { + static class Keys + extends AbstractMultiset { @Weak final Multimap multimap; Keys(Multimap multimap) { @@ -1782,7 +1847,8 @@ Iterator elementIterator() { } /** A skeleton implementation of {@link Multimap#entries()}. */ - abstract static class Entries extends AbstractCollection> { + abstract static class Entries + extends AbstractCollection> { abstract Multimap multimap(); @Override @@ -1793,7 +1859,8 @@ public int size() { @Override public boolean contains(@Nullable Object o) { if (o instanceof Map.Entry) { - Map.Entry entry = (Map.Entry) o; + Map.Entry entry = + (Map.Entry) o; return multimap().containsEntry(entry.getKey(), entry.getValue()); } return false; @@ -1802,7 +1869,8 @@ public boolean contains(@Nullable Object o) { @Override public boolean remove(@Nullable Object o) { if (o instanceof Map.Entry) { - Map.Entry entry = (Map.Entry) o; + Map.Entry entry = + (Map.Entry) o; return multimap().remove(entry.getKey(), entry.getValue()); } return false; @@ -1815,7 +1883,8 @@ public void clear() { } /** A skeleton implementation of {@link Multimap#asMap()}. */ - static final class AsMap extends Maps.ViewCachingAbstractMap> { + static final class AsMap + extends Maps.ViewCachingAbstractMap> { @Weak private final Multimap multimap; AsMap(Multimap multimap) { @@ -1832,7 +1901,7 @@ protected Set>> createEntrySet() { return new EntrySet(); } - void removeValuesForKey(Object key) { + void removeValuesForKey(@Nullable Object key) { multimap.keySet().remove(key); } @@ -1856,24 +1925,27 @@ public Collection apply(K key) { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { if (!contains(o)) { return false; } - Map.Entry entry = (Map.Entry) o; - removeValuesForKey(entry.getKey()); + // requireNonNull is safe because of the contains check. + Map.Entry entry = + requireNonNull((Map.Entry) o); + // Again, requireNonNull is safe because of the contains check :) + removeValuesForKey(requireNonNull(entry.getKey())); return true; } } @SuppressWarnings("unchecked") @Override - public Collection get(Object key) { + public @Nullable Collection get(@Nullable Object key) { return containsKey(key) ? multimap.get((K) key) : null; } @Override - public Collection remove(Object key) { + public @Nullable Collection remove(@Nullable Object key) { return containsKey(key) ? multimap.removeAll(key) : null; } @@ -1888,7 +1960,7 @@ public boolean isEmpty() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return multimap.containsKey(key); } @@ -1970,8 +2042,9 @@ public static Multimap filterKeys( * * @since 14.0 */ - public static SetMultimap filterKeys( - SetMultimap unfiltered, final Predicate keyPredicate) { + public static + SetMultimap filterKeys( + SetMultimap unfiltered, final Predicate keyPredicate) { if (unfiltered instanceof FilteredKeySetMultimap) { FilteredKeySetMultimap prev = (FilteredKeySetMultimap) unfiltered; return new FilteredKeySetMultimap<>( @@ -2011,8 +2084,9 @@ public static SetMultimap filterKeys( * * @since 14.0 */ - public static ListMultimap filterKeys( - ListMultimap unfiltered, final Predicate keyPredicate) { + public static + ListMultimap filterKeys( + ListMultimap unfiltered, final Predicate keyPredicate) { if (unfiltered instanceof FilteredKeyListMultimap) { FilteredKeyListMultimap prev = (FilteredKeyListMultimap) unfiltered; return new FilteredKeyListMultimap<>( @@ -2049,8 +2123,9 @@ public static ListMultimap filterKeys( * * @since 11.0 */ - public static Multimap filterValues( - Multimap unfiltered, final Predicate valuePredicate) { + public static + Multimap filterValues( + Multimap unfiltered, final Predicate valuePredicate) { return filterEntries(unfiltered, Maps.valuePredicateOnEntries(valuePredicate)); } @@ -2081,8 +2156,9 @@ public static Multimap filterValues( * * @since 14.0 */ - public static SetMultimap filterValues( - SetMultimap unfiltered, final Predicate valuePredicate) { + public static + SetMultimap filterValues( + SetMultimap unfiltered, final Predicate valuePredicate) { return filterEntries(unfiltered, Maps.valuePredicateOnEntries(valuePredicate)); } @@ -2111,8 +2187,9 @@ public static SetMultimap filterValues( * * @since 11.0 */ - public static Multimap filterEntries( - Multimap unfiltered, Predicate> entryPredicate) { + public static + Multimap filterEntries( + Multimap unfiltered, Predicate> entryPredicate) { checkNotNull(entryPredicate); if (unfiltered instanceof SetMultimap) { return filterEntries((SetMultimap) unfiltered, entryPredicate); @@ -2147,8 +2224,9 @@ public static Multimap filterEntries( * * @since 14.0 */ - public static SetMultimap filterEntries( - SetMultimap unfiltered, Predicate> entryPredicate) { + public static + SetMultimap filterEntries( + SetMultimap unfiltered, Predicate> entryPredicate) { checkNotNull(entryPredicate); return (unfiltered instanceof FilteredSetMultimap) ? filterFiltered((FilteredSetMultimap) unfiltered, entryPredicate) @@ -2161,8 +2239,9 @@ public static SetMultimap filterEntries( * lead to a multimap whose removal operations would fail. This method combines the predicates to * avoid that problem. */ - private static Multimap filterFiltered( - FilteredMultimap multimap, Predicate> entryPredicate) { + private static + Multimap filterFiltered( + FilteredMultimap multimap, Predicate> entryPredicate) { Predicate> predicate = Predicates.>and(multimap.entryPredicate(), entryPredicate); return new FilteredEntryMultimap<>(multimap.unfiltered(), predicate); @@ -2174,19 +2253,23 @@ private static Multimap filterFiltered( * lead to a multimap whose removal operations would fail. This method combines the predicates to * avoid that problem. */ - private static SetMultimap filterFiltered( - FilteredSetMultimap multimap, Predicate> entryPredicate) { + private static + SetMultimap filterFiltered( + FilteredSetMultimap multimap, Predicate> entryPredicate) { Predicate> predicate = Predicates.>and(multimap.entryPredicate(), entryPredicate); return new FilteredEntrySetMultimap<>(multimap.unfiltered(), predicate); } - static boolean equalsImpl(Multimap multimap, @Nullable Object object) { + static boolean equalsImpl( + Multimap multimap, + @Nullable Object object) { if (object == multimap) { return true; } if (object instanceof Multimap) { - Multimap that = (Multimap) object; + Multimap that = + (Multimap) object; return multimap.asMap().equals(that.asMap()); } return false; diff --git a/guava/src/com/google/common/collect/Multiset.java b/guava/src/com/google/common/collect/Multiset.java index 7fe885b45a02..be454a2d7923 100644 --- a/guava/src/com/google/common/collect/Multiset.java +++ b/guava/src/com/google/common/collect/Multiset.java @@ -130,7 +130,7 @@ public interface Multiset extends Collection { * return normally. */ @CanIgnoreReturnValue - int add(@Nullable E element, int occurrences); + int add(E element, int occurrences); /** * Adds a single occurrence of the specified element to this multiset. @@ -300,7 +300,7 @@ interface Entry { */ @Override // TODO(kevinb): check this wrt TreeMultiset? - boolean equals(Object o); + boolean equals(@Nullable Object o); /** * {@inheritDoc} diff --git a/guava/src/com/google/common/collect/Multisets.java b/guava/src/com/google/common/collect/Multisets.java index 36d146e5ff26..fb614b2753dc 100644 --- a/guava/src/com/google/common/collect/Multisets.java +++ b/guava/src/com/google/common/collect/Multisets.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.CollectPreconditions.checkNonnegative; import static com.google.common.collect.CollectPreconditions.checkRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -40,6 +41,7 @@ import java.util.Set; import java.util.Spliterator; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -72,10 +74,11 @@ private Multisets() {} * * @since 22.0 */ - public static > Collector toMultiset( - java.util.function.Function elementFunction, - java.util.function.ToIntFunction countFunction, - java.util.function.Supplier multisetSupplier) { + public static > + Collector toMultiset( + java.util.function.Function elementFunction, + java.util.function.ToIntFunction countFunction, + java.util.function.Supplier multisetSupplier) { checkNotNull(elementFunction); checkNotNull(countFunction); checkNotNull(multisetSupplier); @@ -98,7 +101,8 @@ private Multisets() {} * @param multiset the multiset for which an unmodifiable view is to be generated * @return an unmodifiable view of the multiset */ - public static Multiset unmodifiableMultiset(Multiset multiset) { + public static Multiset unmodifiableMultiset( + Multiset multiset) { if (multiset instanceof UnmodifiableMultiset || multiset instanceof ImmutableMultiset) { @SuppressWarnings("unchecked") // Since it's unmodifiable, the covariant cast is safe Multiset result = (Multiset) multiset; @@ -114,11 +118,13 @@ public static Multiset unmodifiableMultiset(Multiset multise * @since 10.0 */ @Deprecated - public static Multiset unmodifiableMultiset(ImmutableMultiset multiset) { + public static Multiset unmodifiableMultiset( + ImmutableMultiset multiset) { return checkNotNull(multiset); } - static class UnmodifiableMultiset extends ForwardingMultiset implements Serializable { + static class UnmodifiableMultiset extends ForwardingMultiset + implements Serializable { final Multiset delegate; UnmodifiableMultiset(Multiset delegate) { @@ -178,12 +184,12 @@ public boolean addAll(Collection elementsToAdd) { } @Override - public boolean remove(Object element) { + public boolean remove(@Nullable Object element) { throw new UnsupportedOperationException(); } @Override - public int remove(Object element, int occurrences) { + public int remove(@Nullable Object element, int occurrences) { throw new UnsupportedOperationException(); } @@ -227,7 +233,8 @@ public boolean setCount(E element, int oldCount, int newCount) { * @since 11.0 */ @Beta - public static SortedMultiset unmodifiableSortedMultiset(SortedMultiset sortedMultiset) { + public static SortedMultiset unmodifiableSortedMultiset( + SortedMultiset sortedMultiset) { // it's in its own file so it can be emulated for GWT return new UnmodifiableSortedMultiset(checkNotNull(sortedMultiset)); } @@ -240,22 +247,23 @@ public static SortedMultiset unmodifiableSortedMultiset(SortedMultiset * @param n the count to be associated with the returned entry * @throws IllegalArgumentException if {@code n} is negative */ - public static Multiset.Entry immutableEntry(@Nullable E e, int n) { + public static Multiset.Entry immutableEntry(E e, int n) { return new ImmutableEntry(e, n); } - static class ImmutableEntry extends AbstractEntry implements Serializable { - private final @Nullable E element; + static class ImmutableEntry extends AbstractEntry + implements Serializable { + private final E element; private final int count; - ImmutableEntry(@Nullable E element, int count) { + ImmutableEntry(E element, int count) { this.element = element; this.count = count; checkNonnegative(count, "count"); } @Override - public final @Nullable E getElement() { + public final E getElement() { return element; } @@ -264,7 +272,7 @@ public final int getCount() { return count; } - public ImmutableEntry nextInBucket() { + public @Nullable ImmutableEntry nextInBucket() { return null; } @@ -297,7 +305,8 @@ public ImmutableEntry nextInBucket() { * @since 14.0 */ @Beta - public static Multiset filter(Multiset unfiltered, Predicate predicate) { + public static Multiset filter( + Multiset unfiltered, Predicate predicate) { if (unfiltered instanceof FilteredMultiset) { // Support clear(), removeAll(), and retainAll() when filtering a filtered // collection. @@ -361,7 +370,7 @@ public int count(@Nullable Object element) { } @Override - public int add(@Nullable E element, int occurrences) { + public int add(E element, int occurrences) { checkArgument( predicate.apply(element), "Element %s does not match predicate %s", element, predicate); return unfiltered.add(element, occurrences); @@ -420,7 +429,7 @@ public boolean isEmpty() { } @Override - public int count(Object element) { + public int count(@Nullable Object element) { return Math.max(multiset1.count(element), multiset2.count(element)); } @@ -481,7 +490,7 @@ public static Multiset intersection( return new ViewMultiset() { @Override - public int count(Object element) { + public int count(@Nullable Object element) { int count1 = multiset1.count(element); return (count1 == 0) ? 0 : Math.min(count1, multiset2.count(element)); } @@ -554,7 +563,7 @@ public int size() { } @Override - public int count(Object element) { + public int count(@Nullable Object element) { return multiset1.count(element) + multiset2.count(element); } @@ -677,7 +686,9 @@ int distinctElements() { * @since 10.0 */ @CanIgnoreReturnValue - public static boolean containsOccurrences(Multiset superMultiset, Multiset subMultiset) { + public static boolean containsOccurrences( + Multiset superMultiset, + Multiset subMultiset) { checkNotNull(superMultiset); checkNotNull(subMultiset); for (Entry entry : subMultiset.entrySet()) { @@ -707,7 +718,8 @@ public static boolean containsOccurrences(Multiset superMultiset, Multiset */ @CanIgnoreReturnValue public static boolean retainOccurrences( - Multiset multisetToModify, Multiset multisetToRetain) { + Multiset multisetToModify, + Multiset multisetToRetain) { return retainOccurrencesImpl(multisetToModify, multisetToRetain); } @@ -758,9 +770,11 @@ private static boolean retainOccurrencesImpl( */ @CanIgnoreReturnValue public static boolean removeOccurrences( - Multiset multisetToModify, Iterable occurrencesToRemove) { + Multiset multisetToModify, + Iterable occurrencesToRemove) { if (occurrencesToRemove instanceof Multiset) { - return removeOccurrences(multisetToModify, (Multiset) occurrencesToRemove); + return removeOccurrences( + multisetToModify, (Multiset) occurrencesToRemove); } else { checkNotNull(multisetToModify); checkNotNull(occurrencesToRemove); @@ -796,12 +810,14 @@ public static boolean removeOccurrences( */ @CanIgnoreReturnValue public static boolean removeOccurrences( - Multiset multisetToModify, Multiset occurrencesToRemove) { + Multiset multisetToModify, + Multiset occurrencesToRemove) { checkNotNull(multisetToModify); checkNotNull(occurrencesToRemove); boolean changed = false; - Iterator> entryIterator = multisetToModify.entrySet().iterator(); + Iterator> entryIterator = + multisetToModify.entrySet().iterator(); while (entryIterator.hasNext()) { Entry entry = entryIterator.next(); int removeCount = occurrencesToRemove.count(entry.getElement()); @@ -828,7 +844,8 @@ abstract static class AbstractEntry implements Multiset.Entry { @Override public boolean equals(@Nullable Object object) { if (object instanceof Multiset.Entry) { - Multiset.Entry that = (Multiset.Entry) object; + Multiset.Entry that = + (Multiset.Entry) object; return this.getCount() == that.getCount() && Objects.equal(this.getElement(), that.getElement()); } @@ -860,7 +877,8 @@ public String toString() { } /** An implementation of {@link Multiset#equals}. */ - static boolean equalsImpl(Multiset multiset, @Nullable Object object) { + static boolean equalsImpl( + Multiset multiset, @Nullable Object object) { if (object == multiset) { return true; } @@ -886,7 +904,8 @@ static boolean equalsImpl(Multiset multiset, @Nullable Object object) { } /** An implementation of {@link Multiset#addAll}. */ - static boolean addAllImpl(Multiset self, Collection elements) { + static boolean addAllImpl( + Multiset self, Collection elements) { checkNotNull(self); checkNotNull(elements); if (elements instanceof Multiset) { @@ -899,7 +918,8 @@ static boolean addAllImpl(Multiset self, Collection elements } /** A specialization of {@code addAllImpl} for when {@code elements} is itself a Multiset. */ - private static boolean addAllImpl(Multiset self, Multiset elements) { + private static boolean addAllImpl( + Multiset self, Multiset elements) { if (elements.isEmpty()) { return false; } @@ -908,7 +928,9 @@ private static boolean addAllImpl(Multiset self, Multiset el } /** An implementation of {@link Multiset#removeAll}. */ - static boolean removeAllImpl(Multiset self, Collection elementsToRemove) { + static boolean removeAllImpl( + Multiset self, + Collection elementsToRemove) { Collection collection = (elementsToRemove instanceof Multiset) ? ((Multiset) elementsToRemove).elementSet() @@ -918,7 +940,9 @@ static boolean removeAllImpl(Multiset self, Collection elementsToRemove) { } /** An implementation of {@link Multiset#retainAll}. */ - static boolean retainAllImpl(Multiset self, Collection elementsToRetain) { + static boolean retainAllImpl( + Multiset self, + Collection elementsToRetain) { checkNotNull(elementsToRetain); Collection collection = (elementsToRetain instanceof Multiset) @@ -945,7 +969,8 @@ static int setCountImpl(Multiset self, E element, int count) { } /** An implementation of {@link Multiset#setCount(Object, int, int)}. */ - static boolean setCountImpl(Multiset self, E element, int oldCount, int newCount) { + static boolean setCountImpl( + Multiset self, E element, int oldCount, int newCount) { checkNonnegative(oldCount, "oldCount"); checkNonnegative(newCount, "newCount"); @@ -957,7 +982,8 @@ static boolean setCountImpl(Multiset self, E element, int oldCount, int n } } - static Iterator elementIterator(Iterator> entryIterator) { + static Iterator elementIterator( + Iterator> entryIterator) { return new TransformedIterator, E>(entryIterator) { @Override E transform(Entry entry) { @@ -975,7 +1001,7 @@ public void clear() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { return multiset().contains(o); } @@ -993,7 +1019,7 @@ public boolean isEmpty() { public abstract Iterator iterator(); @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { return multiset().remove(o, Integer.MAX_VALUE) > 0; } @@ -1003,7 +1029,8 @@ public int size() { } } - abstract static class EntrySet extends Sets.ImprovedAbstractSet> { + abstract static class EntrySet + extends Sets.ImprovedAbstractSet> { abstract Multiset multiset(); @Override @@ -1026,15 +1053,15 @@ public boolean contains(@Nullable Object o) { // GWT compiler warning; see contains(). @SuppressWarnings("cast") @Override - public boolean remove(Object object) { + public boolean remove(@Nullable Object object) { if (object instanceof Multiset.Entry) { Entry entry = (Entry) object; Object element = entry.getElement(); int entryCount = entry.getCount(); if (entryCount != 0) { // Safe as long as we never add a new entry, which we won't. - @SuppressWarnings("unchecked") - Multiset multiset = (Multiset) multiset(); + @SuppressWarnings({"unchecked", "nullness"}) + Multiset<@Nullable Object> multiset = (Multiset<@Nullable Object>) multiset(); return multiset.setCount(element, entryCount, 0); } } @@ -1086,7 +1113,8 @@ public E next() { } laterCount--; canRemove = true; - return currentEntry.getElement(); + // requireNonNull is safe because of the laterCount check. + return requireNonNull(currentEntry).getElement(); } @Override @@ -1095,7 +1123,8 @@ public void remove() { if (totalCount == 1) { entryIterator.remove(); } else { - multiset.remove(currentEntry.getElement()); + // requireNonNull is safe because of the canRemove check. + multiset.remove(requireNonNull(currentEntry).getElement()); } totalCount--; canRemove = false; @@ -1134,17 +1163,20 @@ static Multiset cast(Iterable iterable) { * @since 11.0 */ @Beta - public static ImmutableMultiset copyHighestCountFirst(Multiset multiset) { + public static ImmutableMultiset copyHighestCountFirst( + Multiset multiset) { Entry[] entries = (Entry[]) multiset.entrySet().toArray(new Entry[0]); Arrays.sort(entries, DecreasingCount.INSTANCE); return ImmutableMultiset.copyFromEntries(Arrays.asList(entries)); } - private static final class DecreasingCount implements Comparator> { + private static final class DecreasingCount + implements Comparator> { static final DecreasingCount INSTANCE = new DecreasingCount(); @Override - public int compare(Entry entry1, Entry entry2) { + public int compare( + Entry entry1, Entry entry2) { return entry2.getCount() - entry1.getCount(); // subtracting two nonnegative integers } } @@ -1153,7 +1185,8 @@ public int compare(Entry entry1, Entry entry2) { * An {@link AbstractMultiset} with additional default implementations, some of them linear-time * implementations in terms of {@code elementSet} and {@code entrySet}. */ - private abstract static class ViewMultiset extends AbstractMultiset { + private abstract static class ViewMultiset + extends AbstractMultiset { @Override public int size() { return linearTimeSizeImpl(this); diff --git a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java index c3ad9080d255..2138ce457245 100644 --- a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java +++ b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java @@ -28,6 +28,8 @@ import java.util.Map; import java.util.Set; import java.util.Spliterator; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A mutable class-to-instance map backed by an arbitrary user-provided map. See also {@link @@ -42,15 +44,16 @@ */ @GwtIncompatible @SuppressWarnings("serial") // using writeReplace instead of standard serialization -public final class MutableClassToInstanceMap extends ForwardingMap, B> +public final class MutableClassToInstanceMap + extends ForwardingMap, @Nullable B> implements ClassToInstanceMap, Serializable { /** * Returns a new {@code MutableClassToInstanceMap} instance backed by a {@link HashMap} using the * default initial capacity and load factor. */ - public static MutableClassToInstanceMap create() { - return new MutableClassToInstanceMap(new HashMap, B>()); + public static MutableClassToInstanceMap create() { + return new MutableClassToInstanceMap(new HashMap, @Nullable B>()); } /** @@ -58,87 +61,102 @@ public static MutableClassToInstanceMap create() { * backingMap}. The caller surrenders control of the backing map, and thus should not allow any * direct references to it to remain accessible. */ - public static MutableClassToInstanceMap create(Map, B> backingMap) { + public static MutableClassToInstanceMap create( + Map, @Nullable B> backingMap) { return new MutableClassToInstanceMap(backingMap); } - private final Map, B> delegate; + private final Map, @Nullable B> delegate; - private MutableClassToInstanceMap(Map, B> delegate) { + private MutableClassToInstanceMap(Map, @Nullable B> delegate) { this.delegate = checkNotNull(delegate); } @Override - protected Map, B> delegate() { + protected Map, @Nullable B> delegate() { return delegate; } /** * Wraps the {@code setValue} implementation of an {@code Entry} to enforce the class constraint. */ - private static Entry, B> checkedEntry( - final Entry, B> entry) { - return new ForwardingMapEntry, B>() { + private static Entry, @Nullable B> checkedEntry( + Entry, @Nullable B> entry) { + return new ForwardingMapEntry, @Nullable B>() { @Override - protected Entry, B> delegate() { + protected Entry, @Nullable B> delegate() { return entry; } @Override - public B setValue(B value) { + public @Nullable B setValue(@Nullable B value) { return super.setValue(cast(getKey(), value)); } }; } @Override - public Set, B>> entrySet() { - return new ForwardingSet, B>>() { + // The warning is probably related to https://github.com/typetools/checker-framework/issues/3027 + @SuppressWarnings("override.return.invalid") + public Set, @Nullable B>> entrySet() { + return new CheckedEntrySet(); + } - @Override - protected Set, B>> delegate() { - return MutableClassToInstanceMap.this.delegate().entrySet(); - } + // Not an anonymous class to avoid https://github.com/typetools/checker-framework/issues/3021 + private final class CheckedEntrySet + extends ForwardingSet, @Nullable B>> { + @Override + protected Set, @Nullable B>> delegate() { + return MutableClassToInstanceMap.this.delegate().entrySet(); + } - @Override - public Spliterator, B>> spliterator() { - return CollectSpliterators.map( - delegate().spliterator(), MutableClassToInstanceMap::checkedEntry); - } + @Override + public Spliterator, @Nullable B>> spliterator() { + return CollectSpliterators + ., @Nullable B>, Entry, @Nullable B>>map( + delegate().spliterator(), MutableClassToInstanceMap::checkedEntry); + } - @Override - public Iterator, B>> iterator() { - return new TransformedIterator, B>, Entry, B>>( - delegate().iterator()) { - @Override - Entry, B> transform(Entry, B> from) { - return checkedEntry(from); - } - }; - } + @Override + public Iterator, @Nullable B>> iterator() { + return new TransformedIterator< + Entry, @Nullable B>, Entry, @Nullable B>>( + delegate().iterator()) { + @Override + Entry, @Nullable B> transform( + Entry, @Nullable B> from) { + return MutableClassToInstanceMap.checkedEntry(from); + } + }; + } - @Override - public Object[] toArray() { - return standardToArray(); - } + @Override +@SuppressWarnings("nullness") + public Object[] toArray() { + return standardToArray(); + } - @Override - public T[] toArray(T[] array) { - return standardToArray(array); - } - }; + @Override +@SuppressWarnings("nullness") + public T[] toArray(T[] array) { + return standardToArray(array); + } } @Override @CanIgnoreReturnValue - public B put(Class key, B value) { + // The warning is probably related to https://github.com/typetools/checker-framework/issues/3027 + @SuppressWarnings("override.param.invalid") + public @Nullable B put(Class key, @Nullable B value) { return super.put(key, cast(key, value)); } @Override - public void putAll(Map, ? extends B> map) { - Map, B> copy = new LinkedHashMap<>(map); - for (Entry, B> entry : copy.entrySet()) { + // The warning is probably related to https://github.com/typetools/checker-framework/issues/3027 + @SuppressWarnings("override.param.invalid") + public void putAll(Map, ? extends @Nullable B> map) { + Map, @Nullable B> copy = new LinkedHashMap<>(map); + for (Entry, @Nullable B> entry : copy.entrySet()) { cast(entry.getKey(), entry.getValue()); } super.putAll(copy); @@ -146,17 +164,18 @@ public void putAll(Map, ? extends B> map) { @CanIgnoreReturnValue @Override - public T putInstance(Class type, T value) { + public @Nullable T putInstance(Class type, @Nullable T value) { return cast(type, put(type, value)); } @Override - public T getInstance(Class type) { + public @Nullable T getInstance(Class type) { return cast(type, get(type)); } @CanIgnoreReturnValue - private static T cast(Class type, B value) { + private static @Nullable T cast( + Class type, @Nullable Object value) { return Primitives.wrap(type).cast(value); } @@ -165,15 +184,15 @@ private Object writeReplace() { } /** Serialized form of the map, to avoid serializing the constraint. */ - private static final class SerializedForm implements Serializable { - private final Map, B> backingMap; + private static final class SerializedForm implements Serializable { + private final Map, @Nullable B> backingMap; - SerializedForm(Map, B> backingMap) { + SerializedForm(Map, @Nullable B> backingMap) { this.backingMap = backingMap; } Object readResolve() { - return create(backingMap); + return MutableClassToInstanceMap.create(backingMap); } private static final long serialVersionUID = 0; diff --git a/guava/src/com/google/common/collect/NaturalOrdering.java b/guava/src/com/google/common/collect/NaturalOrdering.java index c4b98e36a791..2f1af5d9b7a5 100644 --- a/guava/src/com/google/common/collect/NaturalOrdering.java +++ b/guava/src/com/google/common/collect/NaturalOrdering.java @@ -25,39 +25,40 @@ /** An ordering that uses the natural order of the values. */ @GwtCompatible(serializable = true) @SuppressWarnings({"unchecked", "rawtypes"}) // TODO(kevinb): the right way to explain this?? -final class NaturalOrdering extends Ordering implements Serializable { +final class NaturalOrdering extends Ordering> implements Serializable { static final NaturalOrdering INSTANCE = new NaturalOrdering(); - private transient @Nullable Ordering nullsFirst; - private transient @Nullable Ordering nullsLast; + private transient @Nullable Ordering<@Nullable Comparable> nullsFirst; + private transient @Nullable Ordering<@Nullable Comparable> nullsLast; @Override - public int compare(Comparable left, Comparable right) { + @SuppressWarnings("unchecked") // not safe because we want to support raw Comparable (#989) + public int compare(Comparable left, Comparable right) { checkNotNull(left); // for GWT checkNotNull(right); - return left.compareTo(right); + return ((Comparable) left).compareTo(right); } @Override - public Ordering nullsFirst() { - Ordering result = nullsFirst; + public > Ordering<@Nullable S> nullsFirst() { + Ordering<@Nullable Comparable> result = nullsFirst; if (result == null) { - result = nullsFirst = super.nullsFirst(); + result = nullsFirst = super.>nullsFirst(); } - return (Ordering) result; + return (Ordering<@Nullable S>) result; } @Override - public Ordering nullsLast() { - Ordering result = nullsLast; + public > Ordering<@Nullable S> nullsLast() { + Ordering<@Nullable Comparable> result = nullsLast; if (result == null) { - result = nullsLast = super.nullsLast(); + result = nullsLast = super.>nullsLast(); } - return (Ordering) result; + return (Ordering<@Nullable S>) result; } @Override - public Ordering reverse() { + public > Ordering reverse() { return (Ordering) ReverseNaturalOrdering.INSTANCE; } diff --git a/guava/src/com/google/common/collect/NullsFirstOrdering.java b/guava/src/com/google/common/collect/NullsFirstOrdering.java index 5e1dfe9d06f6..961b17b52a08 100644 --- a/guava/src/com/google/common/collect/NullsFirstOrdering.java +++ b/guava/src/com/google/common/collect/NullsFirstOrdering.java @@ -22,7 +22,8 @@ /** An ordering that treats {@code null} as less than all other values. */ @GwtCompatible(serializable = true) -final class NullsFirstOrdering extends Ordering implements Serializable { +final class NullsFirstOrdering extends Ordering<@Nullable T> + implements Serializable { final Ordering ordering; NullsFirstOrdering(Ordering ordering) { @@ -44,20 +45,21 @@ public int compare(@Nullable T left, @Nullable T right) { } @Override - public Ordering reverse() { + @SuppressWarnings("nullness") // should be safe, but not sure if we can avoid the warning + public Ordering reverse() { // ordering.reverse() might be optimized, so let it do its thing return ordering.reverse().nullsLast(); } @SuppressWarnings("unchecked") // still need the right way to explain this @Override - public Ordering nullsFirst() { - return (Ordering) this; + public Ordering<@Nullable S> nullsFirst() { + return (Ordering<@Nullable S>) this; } @Override - public Ordering nullsLast() { - return ordering.nullsLast(); + public Ordering<@Nullable S> nullsLast() { + return ordering.nullsLast(); } @Override @@ -66,7 +68,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof NullsFirstOrdering) { - NullsFirstOrdering that = (NullsFirstOrdering) object; + NullsFirstOrdering that = + (NullsFirstOrdering) object; return this.ordering.equals(that.ordering); } return false; diff --git a/guava/src/com/google/common/collect/NullsLastOrdering.java b/guava/src/com/google/common/collect/NullsLastOrdering.java index a62e2197939d..41e19fd908c1 100644 --- a/guava/src/com/google/common/collect/NullsLastOrdering.java +++ b/guava/src/com/google/common/collect/NullsLastOrdering.java @@ -22,7 +22,8 @@ /** An ordering that treats {@code null} as greater than all other values. */ @GwtCompatible(serializable = true) -final class NullsLastOrdering extends Ordering implements Serializable { +final class NullsLastOrdering extends Ordering<@Nullable T> + implements Serializable { final Ordering ordering; NullsLastOrdering(Ordering ordering) { @@ -44,20 +45,21 @@ public int compare(@Nullable T left, @Nullable T right) { } @Override - public Ordering reverse() { + @SuppressWarnings("nullness") // should be safe, but not sure if we can avoid the warning + public Ordering reverse() { // ordering.reverse() might be optimized, so let it do its thing return ordering.reverse().nullsFirst(); } @Override - public Ordering nullsFirst() { - return ordering.nullsFirst(); + public Ordering<@Nullable S> nullsFirst() { + return ordering.nullsFirst(); } @SuppressWarnings("unchecked") // still need the right way to explain this @Override - public Ordering nullsLast() { - return (Ordering) this; + public Ordering<@Nullable S> nullsLast() { + return (Ordering<@Nullable S>) this; } @Override @@ -66,7 +68,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof NullsLastOrdering) { - NullsLastOrdering that = (NullsLastOrdering) object; + NullsLastOrdering that = + (NullsLastOrdering) object; return this.ordering.equals(that.ordering); } return false; diff --git a/guava/src/com/google/common/collect/ObjectArrays.java b/guava/src/com/google/common/collect/ObjectArrays.java index cfc9a596c41d..72988c185a95 100644 --- a/guava/src/com/google/common/collect/ObjectArrays.java +++ b/guava/src/com/google/common/collect/ObjectArrays.java @@ -24,6 +24,7 @@ import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collection; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -45,7 +46,7 @@ private ObjectArrays() {} */ @GwtIncompatible // Array.newInstance(Class, int) @SuppressWarnings("unchecked") - public static T[] newArray(Class type, int length) { + public static T[] newArray(Class type, int length) { return (T[]) Array.newInstance(type, length); } @@ -67,7 +68,7 @@ public static T[] newArray(T[] reference, int length) { * @param type the component type of the returned array */ @GwtIncompatible // Array.newInstance(Class, int) - public static T[] concat(T[] first, T[] second, Class type) { + public static T[] concat(T[] first, T[] second, Class type) { T[] result = newArray(type, first.length + second.length); System.arraycopy(first, 0, result, 0, first.length); System.arraycopy(second, 0, result, first.length, second.length); @@ -82,7 +83,7 @@ public static T[] concat(T[] first, T[] second, Class type) { * @return an array whose size is one larger than {@code array}, with {@code element} occupying * the first position, and the elements of {@code array} occupying the remaining elements. */ - public static T[] concat(@Nullable T element, T[] array) { + public static T[] concat(T element, T[] array) { T[] result = newArray(array, array.length + 1); result[0] = element; System.arraycopy(array, 0, result, 1, array.length); @@ -97,7 +98,8 @@ public static T[] concat(@Nullable T element, T[] array) { * @return an array whose size is one larger than {@code array}, with the same contents as {@code * array}, plus {@code element} occupying the last position. */ - public static T[] concat(T[] array, @Nullable T element) { + @SuppressWarnings("assignment.type.incompatible") // arrays + public static T[] concat(T[] array, T element) { T[] result = Arrays.copyOf(array, array.length + 1); result[array.length] = element; return result; @@ -124,7 +126,9 @@ public static T[] concat(T[] array, @Nullable T element) { * @throws ArrayStoreException if the runtime type of the specified array is not a supertype of * the runtime type of every element in the specified collection */ - static T[] toArrayImpl(Collection c, T[] array) { + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) // arrays + static T[] toArrayImpl( + Collection c, T[] array) { int size = c.size(); if (array.length < size) { array = newArray(array, size); @@ -147,6 +151,7 @@ static T[] toArrayImpl(Collection c, T[] array) { * collection is set to {@code null}. This is useful in determining the length of the collection * only if the caller knows that the collection does not contain any null elements. */ + @SuppressWarnings("assignment.type.incompatible") // arrays static T[] toArrayImpl(Object[] src, int offset, int len, T[] dst) { checkPositionIndexes(offset, offset + len, src.length); if (dst.length < len) { @@ -189,6 +194,7 @@ static Object[] copyAsObjectArray(Object[] elements, int offset, int length) { } @CanIgnoreReturnValue + @SuppressWarnings("assignment.type.incompatible") // arrays private static Object[] fillArray(Iterable elements, Object[] array) { int i = 0; for (Object element : elements) { diff --git a/guava/src/com/google/common/collect/Ordering.java b/guava/src/com/google/common/collect/Ordering.java index 1bccd6df79a8..0fcb795d4f0e 100644 --- a/guava/src/com/google/common/collect/Ordering.java +++ b/guava/src/com/google/common/collect/Ordering.java @@ -38,6 +38,7 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -216,7 +217,7 @@ public static Ordering from(Ordering ordering) { */ // TODO(kevinb): provide replacement @GwtCompatible(serializable = true) - public static Ordering explicit(List valuesInOrder) { + public static Ordering explicit(List valuesInOrder) { return new ExplicitOrdering(valuesInOrder); } @@ -242,7 +243,8 @@ public static Ordering explicit(List valuesInOrder) { */ // TODO(kevinb): provide replacement @GwtCompatible(serializable = true) - public static Ordering explicit(T leastValue, T... remainingValuesInOrder) { + public static Ordering explicit( + T leastValue, T... remainingValuesInOrder) { return explicit(Lists.asList(leastValue, remainingValuesInOrder)); } @@ -278,7 +280,7 @@ public static Ordering explicit(T leastValue, T... remainingValuesInOrder */ @GwtCompatible(serializable = true) @SuppressWarnings("unchecked") - public static Ordering allEqual() { + public static Ordering<@Nullable Object> allEqual() { return AllEqualOrdering.INSTANCE; } @@ -311,16 +313,16 @@ public static Ordering usingToString() { * @since 2.0 */ // TODO(kevinb): copy to Comparators, etc. - public static Ordering arbitrary() { + public static Ordering<@Nullable Object> arbitrary() { return ArbitraryOrderingHolder.ARBITRARY_ORDERING; } private static class ArbitraryOrderingHolder { - static final Ordering ARBITRARY_ORDERING = new ArbitraryOrdering(); + static final Ordering<@Nullable Object> ARBITRARY_ORDERING = new ArbitraryOrdering(); } @VisibleForTesting - static class ArbitraryOrdering extends Ordering { + static class ArbitraryOrdering extends Ordering<@Nullable Object> { private final AtomicInteger counter = new AtomicInteger(0); private final ConcurrentMap uids = @@ -342,7 +344,7 @@ private Integer getUid(Object obj) { } @Override - public int compare(Object left, Object right) { + public int compare(@Nullable Object left, @Nullable Object right) { if (left == right) { return 0; } else if (left == null) { @@ -414,7 +416,7 @@ public Ordering reverse() { // type parameter lets us avoid the extra in statements like: // Ordering o = Ordering.natural().nullsFirst(); @GwtCompatible(serializable = true) - public Ordering nullsFirst() { + public Ordering<@Nullable S> nullsFirst() { return new NullsFirstOrdering(this); } @@ -427,7 +429,7 @@ public Ordering nullsFirst() { // type parameter lets us avoid the extra in statements like: // Ordering o = Ordering.natural().nullsLast(); @GwtCompatible(serializable = true) - public Ordering nullsLast() { + public Ordering<@Nullable S> nullsLast() { return new NullsLastOrdering(this); } @@ -491,7 +493,8 @@ public Ordering compound(Comparator secondaryCompara * @param comparators the comparators to try in order */ @GwtCompatible(serializable = true) - public static Ordering compound(Iterable> comparators) { + public static Ordering compound( + Iterable> comparators) { return new CompoundOrdering(comparators); } @@ -530,7 +533,7 @@ public Ordering> lexicographical() { // Override to add @Nullable @CanIgnoreReturnValue // TODO(kak): Consider removing this @Override - public abstract int compare(@Nullable T left, @Nullable T right); + public abstract int compare(T left, T right); /** * Returns the least of the specified values according to this ordering. If there are multiple @@ -590,7 +593,7 @@ public E min(Iterable iterable) { * @throws ClassCastException if the parameters are not mutually comparable under this * ordering. */ - public E min(@Nullable E a, @Nullable E b) { + public E min(E a, E b) { return (compare(a, b) <= 0) ? a : b; } @@ -608,7 +611,7 @@ public E min(@Nullable E a, @Nullable E b) { * @throws ClassCastException if the parameters are not mutually comparable under this * ordering. */ - public E min(@Nullable E a, @Nullable E b, @Nullable E c, E... rest) { + public E min(E a, E b, E c, E... rest) { E minSoFar = min(min(a, b), c); for (E r : rest) { @@ -676,7 +679,7 @@ public E max(Iterable iterable) { * @throws ClassCastException if the parameters are not mutually comparable under this * ordering. */ - public E max(@Nullable E a, @Nullable E b) { + public E max(E a, E b) { return (compare(a, b) >= 0) ? a : b; } @@ -694,7 +697,7 @@ public E max(@Nullable E a, @Nullable E b) { * @throws ClassCastException if the parameters are not mutually comparable under this * ordering. */ - public E max(@Nullable E a, @Nullable E b, @Nullable E c, E... rest) { + public E max(E a, E b, E c, E... rest) { E maxSoFar = max(max(a, b), c); for (E r : rest) { @@ -720,6 +723,7 @@ public E max(@Nullable E a, @Nullable E b, @Nullable E c, E... res * @throws IllegalArgumentException if {@code k} is negative * @since 8.0 */ + @SuppressWarnings("assignment.type.incompatible") // arrays public List leastOf(Iterable iterable, int k) { if (iterable instanceof Collection) { Collection collection = (Collection) iterable; @@ -829,11 +833,10 @@ public List greatestOf(Iterator iterator, int k) { * duplicates according to the comparator. The sort performed is stable, meaning that such * elements will appear in the returned list in the same order they appeared in {@code elements}. * - *

    Performance note: According to our - * benchmarking - * on Open JDK 7, {@link #immutableSortedCopy} generally performs better (in both time and space) - * than this method, and this method in turn generally performs better than copying the list and - * calling {@link Collections#sort(List)}. + *

    Performance note: According to our benchmarking on Open JDK 7, {@link + * #immutableSortedCopy} generally performs better (in both time and space) than this method, and + * this method in turn generally performs better than copying the list and calling {@link + * Collections#sort(List)}. */ // TODO(kevinb): rerun benchmarks including new options public List sortedCopy(Iterable elements) { @@ -851,14 +854,14 @@ public List sortedCopy(Iterable elements) { * duplicates according to the comparator. The sort performed is stable, meaning that such * elements will appear in the returned list in the same order they appeared in {@code elements}. * - *

    Performance note: According to our - * benchmarking - * on Open JDK 7, this method is the most efficient way to make a sorted copy of a collection. + *

    Performance note: According to our benchmarking on Open JDK 7, this method is the + * most efficient way to make a sorted copy of a collection. * * @throws NullPointerException if any element of {@code elements} is {@code null} * @since 3.0 */ // TODO(kevinb): rerun benchmarks including new options + @SuppressWarnings("nullness") // unsafe, but there's not much we can do about it now public ImmutableList immutableSortedCopy(Iterable elements) { return ImmutableList.sortedCopyOf(this, elements); } @@ -920,7 +923,7 @@ public boolean isStrictlyOrdered(Iterable iterable) { * @deprecated Use {@link Collections#binarySearch(List, Object, Comparator)} directly. */ @Deprecated - public int binarySearch(List sortedList, @Nullable T key) { + public int binarySearch(List sortedList, T key) { return Collections.binarySearch(sortedList, key, this); } diff --git a/guava/src/com/google/common/collect/PeekingIterator.java b/guava/src/com/google/common/collect/PeekingIterator.java index 5a6c60b2bec4..12e910167a98 100644 --- a/guava/src/com/google/common/collect/PeekingIterator.java +++ b/guava/src/com/google/common/collect/PeekingIterator.java @@ -18,9 +18,9 @@ import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.util.Iterator; import java.util.NoSuchElementException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An iterator that supports a one-element lookahead while iterating. @@ -32,7 +32,6 @@ * @author Mick Killianey * @since 2.0 */ -@DoNotMock("Use Iterators.peekingIterator") @GwtCompatible public interface PeekingIterator extends Iterator { /** diff --git a/guava/src/com/google/common/collect/Platform.java b/guava/src/com/google/common/collect/Platform.java index d4afd3299ca6..4dc0143f4a74 100644 --- a/guava/src/com/google/common/collect/Platform.java +++ b/guava/src/com/google/common/collect/Platform.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Methods factored out so that they can be emulated differently in GWT. @@ -33,7 +34,8 @@ final class Platform { java.util.logging.Logger.getLogger(Platform.class.getName()); /** Returns the platform preferred implementation of a map based on a hash table. */ - static Map newHashMapWithExpectedSize(int expectedSize) { + static + Map newHashMapWithExpectedSize(int expectedSize) { return Maps.newHashMapWithExpectedSize(expectedSize); } @@ -41,7 +43,8 @@ static Map newHashMapWithExpectedSize(int expectedSize) { * Returns the platform preferred implementation of an insertion ordered map based on a hash * table. */ - static Map newLinkedHashMapWithExpectedSize(int expectedSize) { + static + Map newLinkedHashMapWithExpectedSize(int expectedSize) { return Maps.newLinkedHashMapWithExpectedSize(expectedSize); } @@ -62,7 +65,8 @@ static Set newLinkedHashSetWithExpectedSize(int expectedSize) { * Returns the platform preferred map implementation that preserves insertion order when used only * for insertions. */ - static Map preservesInsertionOrderOnPutsMap() { + static + Map preservesInsertionOrderOnPutsMap() { return Maps.newLinkedHashMap(); } @@ -80,6 +84,7 @@ static Set preservesInsertionOrderOnAddsSet() { * @param reference any array of the desired type * @param length the length of the new array */ + @SuppressWarnings("argument.type.incompatible") // arrays static T[] newArray(T[] reference, int length) { Class type = reference.getClass().getComponentType(); @@ -91,6 +96,7 @@ static T[] newArray(T[] reference, int length) { } /** Equivalent to Arrays.copyOfRange(source, from, to, arrayOfType.getClass()). */ + @SuppressWarnings("return.type.incompatible") // arrays static T[] copy(Object[] source, int from, int to, T[] arrayOfType) { return Arrays.copyOfRange(source, from, to, (Class) arrayOfType.getClass()); } @@ -131,7 +137,6 @@ static void checkGwtRpcEnabled() { + " warning because you are sending a Guava type over GWT-RPC, which will break. You" + " can identify which type by looking at the class name in the attached stack trace.", new Throwable()); - } private Platform() {} diff --git a/guava/src/com/google/common/collect/Queues.java b/guava/src/com/google/common/collect/Queues.java index 79fcb9d911d0..f7ece4fe09e3 100644 --- a/guava/src/com/google/common/collect/Queues.java +++ b/guava/src/com/google/common/collect/Queues.java @@ -32,6 +32,8 @@ import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Static utility methods pertaining to {@link Queue} and {@link Deque} instances. Also see this @@ -51,7 +53,8 @@ private Queues() {} * policy. */ @GwtIncompatible // ArrayBlockingQueue - public static ArrayBlockingQueue newArrayBlockingQueue(int capacity) { + public static ArrayBlockingQueue newArrayBlockingQueue( + int capacity) { return new ArrayBlockingQueue(capacity); } @@ -62,7 +65,7 @@ public static ArrayBlockingQueue newArrayBlockingQueue(int capacity) { * * @since 12.0 */ - public static ArrayDeque newArrayDeque() { + public static ArrayDeque newArrayDeque() { return new ArrayDeque(); } @@ -72,7 +75,8 @@ public static ArrayDeque newArrayDeque() { * * @since 12.0 */ - public static ArrayDeque newArrayDeque(Iterable elements) { + public static ArrayDeque newArrayDeque( + Iterable elements) { if (elements instanceof Collection) { return new ArrayDeque(Collections2.cast(elements)); } @@ -85,7 +89,7 @@ public static ArrayDeque newArrayDeque(Iterable elements) { /** Creates an empty {@code ConcurrentLinkedQueue}. */ @GwtIncompatible // ConcurrentLinkedQueue - public static ConcurrentLinkedQueue newConcurrentLinkedQueue() { + public static ConcurrentLinkedQueue newConcurrentLinkedQueue() { return new ConcurrentLinkedQueue(); } @@ -94,7 +98,7 @@ public static ConcurrentLinkedQueue newConcurrentLinkedQueue() { * the order they are returned by the iterable's iterator. */ @GwtIncompatible // ConcurrentLinkedQueue - public static ConcurrentLinkedQueue newConcurrentLinkedQueue( + public static ConcurrentLinkedQueue newConcurrentLinkedQueue( Iterable elements) { if (elements instanceof Collection) { return new ConcurrentLinkedQueue(Collections2.cast(elements)); @@ -112,7 +116,7 @@ public static ConcurrentLinkedQueue newConcurrentLinkedQueue( * @since 12.0 */ @GwtIncompatible // LinkedBlockingDeque - public static LinkedBlockingDeque newLinkedBlockingDeque() { + public static LinkedBlockingDeque newLinkedBlockingDeque() { return new LinkedBlockingDeque(); } @@ -123,7 +127,8 @@ public static LinkedBlockingDeque newLinkedBlockingDeque() { * @since 12.0 */ @GwtIncompatible // LinkedBlockingDeque - public static LinkedBlockingDeque newLinkedBlockingDeque(int capacity) { + public static LinkedBlockingDeque newLinkedBlockingDeque( + int capacity) { return new LinkedBlockingDeque(capacity); } @@ -135,7 +140,8 @@ public static LinkedBlockingDeque newLinkedBlockingDeque(int capacity) { * @since 12.0 */ @GwtIncompatible // LinkedBlockingDeque - public static LinkedBlockingDeque newLinkedBlockingDeque(Iterable elements) { + public static LinkedBlockingDeque newLinkedBlockingDeque( + Iterable elements) { if (elements instanceof Collection) { return new LinkedBlockingDeque(Collections2.cast(elements)); } @@ -148,7 +154,7 @@ public static LinkedBlockingDeque newLinkedBlockingDeque(Iterable LinkedBlockingQueue newLinkedBlockingQueue() { + public static LinkedBlockingQueue newLinkedBlockingQueue() { return new LinkedBlockingQueue(); } @@ -158,7 +164,8 @@ public static LinkedBlockingQueue newLinkedBlockingQueue() { * @throws IllegalArgumentException if {@code capacity} is less than 1 */ @GwtIncompatible // LinkedBlockingQueue - public static LinkedBlockingQueue newLinkedBlockingQueue(int capacity) { + public static LinkedBlockingQueue newLinkedBlockingQueue( + int capacity) { return new LinkedBlockingQueue(capacity); } @@ -171,7 +178,8 @@ public static LinkedBlockingQueue newLinkedBlockingQueue(int capacity) { * @return a new {@code LinkedBlockingQueue} containing those elements */ @GwtIncompatible // LinkedBlockingQueue - public static LinkedBlockingQueue newLinkedBlockingQueue(Iterable elements) { + public static LinkedBlockingQueue newLinkedBlockingQueue( + Iterable elements) { if (elements instanceof Collection) { return new LinkedBlockingQueue(Collections2.cast(elements)); } @@ -248,7 +256,7 @@ public static PriorityQueue newPriorityQueue( /** Creates an empty {@code SynchronousQueue} with nonfair access policy. */ @GwtIncompatible // SynchronousQueue - public static SynchronousQueue newSynchronousQueue() { + public static SynchronousQueue newSynchronousQueue() { return new SynchronousQueue(); } @@ -267,7 +275,7 @@ public static SynchronousQueue newSynchronousQueue() { @Beta @CanIgnoreReturnValue @GwtIncompatible // BlockingQueue - public static int drain( + public static int drain( BlockingQueue q, Collection buffer, int numElements, java.time.Duration timeout) throws InterruptedException { // TODO(b/126049426): Consider using saturateToNanos(timeout) instead. @@ -290,7 +298,7 @@ public static int drain( @CanIgnoreReturnValue @GwtIncompatible // BlockingQueue @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static int drain( + public static int drain( BlockingQueue q, Collection buffer, int numElements, @@ -337,7 +345,7 @@ public static int drain( @Beta @CanIgnoreReturnValue @GwtIncompatible // BlockingQueue - public static int drainUninterruptibly( + public static int drainUninterruptibly( BlockingQueue q, Collection buffer, int numElements, @@ -362,8 +370,11 @@ public static int drainUninterruptibly( @Beta @CanIgnoreReturnValue @GwtIncompatible // BlockingQueue - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static int drainUninterruptibly( + @SuppressWarnings({ + "GoodTime", // should accept a java.time.Duration + "argument.type.incompatible", // https://github.com/typetools/checker-framework/issues/1727 + }) + public static int drainUninterruptibly( BlockingQueue q, Collection buffer, int numElements, diff --git a/guava/src/com/google/common/collect/Range.java b/guava/src/com/google/common/collect/Range.java index a6bae2034880..84f2a7190754 100644 --- a/guava/src/com/google/common/collect/Range.java +++ b/guava/src/com/google/common/collect/Range.java @@ -137,12 +137,12 @@ public Cut apply(Range range) { } } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "nullness"}) static > Function, Cut> lowerBoundFn() { return (Function) LowerBoundFn.INSTANCE; } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "nullness"}) static > Function, Cut> upperBoundFn() { return (Function) UpperBoundFn.INSTANCE; } @@ -691,8 +691,8 @@ Object readResolve() { } @SuppressWarnings("unchecked") // this method may throw CCE - static int compareOrThrow(Comparable left, Comparable right) { - return left.compareTo(right); + static int compareOrThrow(Comparable left, Comparable right) { + return ((Comparable) left).compareTo(right); } /** Needed to serialize sorted collections of Ranges. */ diff --git a/guava/src/com/google/common/collect/RangeMap.java b/guava/src/com/google/common/collect/RangeMap.java index 0b319bdb61b9..3b1c6eba93bf 100644 --- a/guava/src/com/google/common/collect/RangeMap.java +++ b/guava/src/com/google/common/collect/RangeMap.java @@ -18,12 +18,12 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; -import com.google.errorprone.annotations.DoNotMock; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.function.BiFunction; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -37,9 +37,8 @@ * @since 14.0 */ @Beta -@DoNotMock("Use ImmutableRangeMap or TreeRangeMap") @GwtIncompatible -public interface RangeMap { +public interface RangeMap { /** * Returns the value associated with the specified key, or {@code null} if there is no such value. * @@ -129,7 +128,7 @@ public interface RangeMap { void merge( Range range, @Nullable V value, - BiFunction remappingFunction); + BiFunction remappingFunction); /** * Returns a view of this range map as an unmodifiable {@code Map, V>}. Modifications to diff --git a/guava/src/com/google/common/collect/RangeSet.java b/guava/src/com/google/common/collect/RangeSet.java index 4805108c1b6a..345b27b2a1cd 100644 --- a/guava/src/com/google/common/collect/RangeSet.java +++ b/guava/src/com/google/common/collect/RangeSet.java @@ -15,7 +15,6 @@ package com.google.common.collect; import com.google.common.annotations.Beta; -import com.google.errorprone.annotations.DoNotMock; import com.google.common.annotations.GwtIncompatible; import java.util.NoSuchElementException; import java.util.Set; @@ -50,7 +49,6 @@ * @since 14.0 */ @Beta -@DoNotMock("Use ImmutableRangeSet or TreeRangeSet") @GwtIncompatible public interface RangeSet { // TODO(lowasser): consider adding default implementations of some of these methods @@ -64,6 +62,7 @@ public interface RangeSet { * Returns the unique range from this range set that {@linkplain Range#contains contains} {@code * value}, or {@code null} if this range set does not contain {@code value}. */ + @Nullable Range rangeContaining(C value); /** diff --git a/guava/src/com/google/common/collect/RegularContiguousSet.java b/guava/src/com/google/common/collect/RegularContiguousSet.java index 849758579201..a982ba41de68 100644 --- a/guava/src/com/google/common/collect/RegularContiguousSet.java +++ b/guava/src/com/google/common/collect/RegularContiguousSet.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkElementIndex; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.BoundType.CLOSED; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -71,8 +72,9 @@ ContiguousSet tailSetImpl(C fromElement, boolean inclusive) { @GwtIncompatible // not used by GWT emulation @Override - int indexOf(Object target) { - return contains(target) ? (int) domain.distance(first(), (C) target) : -1; + int indexOf(@Nullable Object target) { + // requireNonNull is safe because of the contains check. + return contains(target) ? (int) domain.distance(first(), (C) requireNonNull(target)) : -1; } @Override @@ -81,7 +83,7 @@ public UnmodifiableIterator iterator() { final C last = last(); @Override - protected C computeNext(C previous) { + protected @Nullable C computeNext(C previous) { return equalsOrThrow(previous, last) ? null : domain.next(previous); } }; @@ -94,7 +96,7 @@ public UnmodifiableIterator descendingIterator() { final C first = first(); @Override - protected C computeNext(C previous) { + protected @Nullable C computeNext(C previous) { return equalsOrThrow(previous, first) ? null : domain.previous(previous); } }; @@ -111,12 +113,14 @@ boolean isPartialView() { @Override public C first() { - return range.lowerBound.leastValueAbove(domain); + // requireNonNull is safe because we checked this in ContiguousSet.create. + return requireNonNull(range.lowerBound.leastValueAbove(domain)); } @Override public C last() { - return range.upperBound.greatestValueBelow(domain); + // requireNonNull is safe because we checked this in ContiguousSet.create. + return requireNonNull(range.upperBound.greatestValueBelow(domain)); } @Override diff --git a/guava/src/com/google/common/collect/RegularImmutableAsList.java b/guava/src/com/google/common/collect/RegularImmutableAsList.java index df17b6e341b4..546d73253e44 100644 --- a/guava/src/com/google/common/collect/RegularImmutableAsList.java +++ b/guava/src/com/google/common/collect/RegularImmutableAsList.java @@ -19,6 +19,8 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An {@link ImmutableAsList} implementation specialized for when the delegate collection is already @@ -28,7 +30,7 @@ */ @GwtCompatible(emulated = true) @SuppressWarnings("serial") // uses writeReplace, not default serialization -class RegularImmutableAsList extends ImmutableAsList { +class RegularImmutableAsList extends ImmutableAsList { private final ImmutableCollection delegate; private final ImmutableList delegateList; @@ -69,7 +71,7 @@ int copyIntoArray(Object[] dst, int offset) { } @Override - Object[] internalArray() { + Object @Nullable [] internalArray() { return delegateList.internalArray(); } diff --git a/guava/src/com/google/common/collect/RegularImmutableBiMap.java b/guava/src/com/google/common/collect/RegularImmutableBiMap.java index f5b898841513..8307e6f2cb10 100644 --- a/guava/src/com/google/common/collect/RegularImmutableBiMap.java +++ b/guava/src/com/google/common/collect/RegularImmutableBiMap.java @@ -31,6 +31,7 @@ import java.io.Serializable; import java.util.function.BiConsumer; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -40,29 +41,33 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -class RegularImmutableBiMap extends ImmutableBiMap { +class RegularImmutableBiMap + extends ImmutableBiMap { + @SuppressWarnings({"unchecked", "nullness"}) static final RegularImmutableBiMap EMPTY = new RegularImmutableBiMap<>( null, null, (Entry[]) ImmutableMap.EMPTY_ENTRY_ARRAY, 0, 0); static final double MAX_LOAD_FACTOR = 1.2; - private final transient ImmutableMapEntry[] keyTable; - private final transient ImmutableMapEntry[] valueTable; + private final transient @Nullable ImmutableMapEntry @Nullable [] keyTable; + private final transient @Nullable ImmutableMapEntry @Nullable [] valueTable; @VisibleForTesting final transient Entry[] entries; private final transient int mask; private final transient int hashCode; - static ImmutableBiMap fromEntries(Entry... entries) { + static ImmutableBiMap fromEntries( + Entry... entries) { return fromEntryArray(entries.length, entries); } - static ImmutableBiMap fromEntryArray(int n, Entry[] entryArray) { + static ImmutableBiMap fromEntryArray( + int n, Entry[] entryArray) { checkPositionIndex(n, entryArray.length); int tableSize = Hashing.closedTableSize(n, MAX_LOAD_FACTOR); int mask = tableSize - 1; - ImmutableMapEntry[] keyTable = createEntryArray(tableSize); - ImmutableMapEntry[] valueTable = createEntryArray(tableSize); + @Nullable ImmutableMapEntry[] keyTable = createEntryArray(tableSize); + @Nullable ImmutableMapEntry[] valueTable = createEntryArray(tableSize); Entry[] entries; if (n == entryArray.length) { entries = entryArray; @@ -104,8 +109,8 @@ static ImmutableBiMap fromEntryArray(int n, Entry[] entryArra } private RegularImmutableBiMap( - ImmutableMapEntry[] keyTable, - ImmutableMapEntry[] valueTable, + @Nullable ImmutableMapEntry @Nullable [] keyTable, + @Nullable ImmutableMapEntry @Nullable [] valueTable, Entry[] entries, int mask, int hashCode) { @@ -135,7 +140,7 @@ private static int checkNoConflictInValueBucket( @Override public @Nullable V get(@Nullable Object key) { - return (keyTable == null) ? null : RegularImmutableMap.get(key, keyTable, mask); + return RegularImmutableMap.get(key, keyTable, mask); } @Override @@ -178,7 +183,7 @@ public int size() { return entries.length; } - @LazyInit @RetainedWith private transient ImmutableBiMap inverse; + @LazyInit @RetainedWith private transient @Nullable ImmutableBiMap inverse; @Override public ImmutableBiMap inverse() { @@ -208,7 +213,7 @@ public void forEach(BiConsumer action) { } @Override - public K get(@Nullable Object value) { + public @Nullable K get(@Nullable Object value) { if (value == null || valueTable == null) { return null; } @@ -287,7 +292,8 @@ Object writeReplace() { } } - private static class InverseSerializedForm implements Serializable { + private static class InverseSerializedForm + implements Serializable { private final ImmutableBiMap forward; InverseSerializedForm(ImmutableBiMap forward) { diff --git a/guava/src/com/google/common/collect/RegularImmutableList.java b/guava/src/com/google/common/collect/RegularImmutableList.java index 47f42d5db22c..da2ba6822a44 100644 --- a/guava/src/com/google/common/collect/RegularImmutableList.java +++ b/guava/src/com/google/common/collect/RegularImmutableList.java @@ -20,6 +20,7 @@ import com.google.common.annotations.VisibleForTesting; import java.util.Spliterator; import java.util.Spliterators; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Implementation of {@link ImmutableList} backed by a simple array. @@ -28,7 +29,7 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -class RegularImmutableList extends ImmutableList { +class RegularImmutableList extends ImmutableList { static final ImmutableList EMPTY = new RegularImmutableList<>(new Object[0]); @VisibleForTesting final transient Object[] array; diff --git a/guava/src/com/google/common/collect/RegularImmutableMap.java b/guava/src/com/google/common/collect/RegularImmutableMap.java index 3c74dc2d967c..ac99f5a4a64c 100644 --- a/guava/src/com/google/common/collect/RegularImmutableMap.java +++ b/guava/src/com/google/common/collect/RegularImmutableMap.java @@ -28,6 +28,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.Serializable; import java.util.function.BiConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -38,8 +39,9 @@ * @author Gregory Kick */ @GwtCompatible(serializable = true, emulated = true) -final class RegularImmutableMap extends ImmutableMap { - @SuppressWarnings("unchecked") +final class RegularImmutableMap + extends ImmutableMap { + @SuppressWarnings({"unchecked", "nullness"}) static final ImmutableMap EMPTY = new RegularImmutableMap<>((Entry[]) ImmutableMap.EMPTY_ENTRY_ARRAY, null, 0); @@ -65,11 +67,12 @@ final class RegularImmutableMap extends ImmutableMap { // entries in insertion order @VisibleForTesting final transient Entry[] entries; // array of linked lists of entries - private final transient ImmutableMapEntry[] table; + private final transient ImmutableMapEntry @Nullable [] table; // 'and' with an int to get a table index private final transient int mask; - static ImmutableMap fromEntries(Entry... entries) { + static ImmutableMap fromEntries( + Entry... entries) { return fromEntryArray(entries.length, entries); } @@ -78,7 +81,8 @@ static ImmutableMap fromEntries(Entry... entries) { * the entries in entryArray with its own entry objects (though they will have the same key/value * contents), and may take ownership of entryArray. */ - static ImmutableMap fromEntryArray(int n, Entry[] entryArray) { + static ImmutableMap fromEntryArray( + int n, Entry[] entryArray) { checkPositionIndex(n, entryArray.length); if (n == 0) { return (RegularImmutableMap) EMPTY; @@ -117,18 +121,21 @@ static ImmutableMap fromEntryArray(int n, Entry[] entryArray) } /** Makes an entry usable internally by a new ImmutableMap without rereading its contents. */ - static ImmutableMapEntry makeImmutable(Entry entry, K key, V value) { + static + ImmutableMapEntry makeImmutable(Entry entry, K key, V value) { boolean reusable = entry instanceof ImmutableMapEntry && ((ImmutableMapEntry) entry).isReusable(); return reusable ? (ImmutableMapEntry) entry : new ImmutableMapEntry(key, value); } /** Makes an entry usable internally by a new ImmutableMap. */ - static ImmutableMapEntry makeImmutable(Entry entry) { + static + ImmutableMapEntry makeImmutable(Entry entry) { return makeImmutable(entry, entry.getKey(), entry.getValue()); } - private RegularImmutableMap(Entry[] entries, ImmutableMapEntry[] table, int mask) { + private RegularImmutableMap( + Entry[] entries, ImmutableMapEntry @Nullable [] table, int mask) { this.entries = entries; this.table = table; this.mask = mask; @@ -150,12 +157,12 @@ static int checkNoConflictInKeyBucket( } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { return get(key, table, mask); } - static @Nullable V get( - @Nullable Object key, ImmutableMapEntry @Nullable [] keyTable, int mask) { + static @Nullable V get( + @Nullable Object key, @Nullable ImmutableMapEntry @Nullable [] keyTable, int mask) { if (key == null || keyTable == null) { return null; } @@ -207,7 +214,8 @@ ImmutableSet createKeySet() { } @GwtCompatible(emulated = true) - private static final class KeySet extends IndexedImmutableSet { + private static final class KeySet + extends IndexedImmutableSet { private final RegularImmutableMap map; KeySet(RegularImmutableMap map) { @@ -220,7 +228,7 @@ K get(int index) { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { return map.containsKey(object); } @@ -241,7 +249,7 @@ Object writeReplace() { } @GwtIncompatible // serialization - private static class SerializedForm implements Serializable { + private static class SerializedForm implements Serializable { final ImmutableMap map; SerializedForm(ImmutableMap map) { @@ -262,7 +270,8 @@ ImmutableCollection createValues() { } @GwtCompatible(emulated = true) - private static final class Values extends ImmutableList { + private static final class Values + extends ImmutableList { final RegularImmutableMap map; Values(RegularImmutableMap map) { @@ -291,7 +300,7 @@ Object writeReplace() { } @GwtIncompatible // serialization - private static class SerializedForm implements Serializable { + private static class SerializedForm implements Serializable { final ImmutableMap map; SerializedForm(ImmutableMap map) { diff --git a/guava/src/com/google/common/collect/RegularImmutableMultiset.java b/guava/src/com/google/common/collect/RegularImmutableMultiset.java index 93843da61e06..53116fca8653 100644 --- a/guava/src/com/google/common/collect/RegularImmutableMultiset.java +++ b/guava/src/com/google/common/collect/RegularImmutableMultiset.java @@ -19,11 +19,13 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; +import com.google.common.base.Preconditions; import com.google.common.collect.Multisets.ImmutableEntry; import com.google.common.primitives.Ints; import com.google.errorprone.annotations.concurrent.LazyInit; import java.util.Arrays; import java.util.Collection; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -34,10 +36,11 @@ */ @GwtCompatible(emulated = true, serializable = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -class RegularImmutableMultiset extends ImmutableMultiset { +class RegularImmutableMultiset extends ImmutableMultiset { static final ImmutableMultiset EMPTY = create(ImmutableList.>of()); - static ImmutableMultiset create(Collection> entries) { + static ImmutableMultiset create( + Collection> entries) { int distinct = entries.size(); @SuppressWarnings("unchecked") Multisets.ImmutableEntry[] entryArray = new Multisets.ImmutableEntry[distinct]; @@ -53,7 +56,8 @@ static ImmutableMultiset create(Collection> int hashCode = 0; long size = 0; for (Entry entry : entries) { - E element = checkNotNull(entry.getElement()); + // TODO(cpovirk): Why does our prototype checker (but not stock CF) need ? + E element = Preconditions.checkNotNull(entry.getElement()); int count = entry.getCount(); int hash = element.hashCode(); int bucket = Hashing.smear(hash) & mask; @@ -120,14 +124,14 @@ private static boolean hashFloodingDetected(Multisets.ImmutableEntry[] hashTa private final transient int size; private final transient int hashCode; - @LazyInit private transient ImmutableSet elementSet; + @LazyInit private transient @Nullable ImmutableSet elementSet; private RegularImmutableMultiset( ImmutableEntry[] entries, - ImmutableEntry[] hashTable, + ImmutableEntry @Nullable [] hashTable, int size, int hashCode, - ImmutableSet elementSet) { + @Nullable ImmutableSet elementSet) { this.entries = entries; this.hashTable = hashTable; this.size = size; @@ -135,7 +139,8 @@ private RegularImmutableMultiset( this.elementSet = elementSet; } - private static final class NonTerminalEntry extends Multisets.ImmutableEntry { + private static final class NonTerminalEntry + extends Multisets.ImmutableEntry { private final Multisets.ImmutableEntry nextInBucket; NonTerminalEntry(E element, int count, ImmutableEntry nextInBucket) { diff --git a/guava/src/com/google/common/collect/RegularImmutableSet.java b/guava/src/com/google/common/collect/RegularImmutableSet.java index d4d2f200090e..c814f772fab5 100644 --- a/guava/src/com/google/common/collect/RegularImmutableSet.java +++ b/guava/src/com/google/common/collect/RegularImmutableSet.java @@ -20,6 +20,7 @@ import com.google.common.annotations.VisibleForTesting; import java.util.Spliterator; import java.util.Spliterators; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -29,18 +30,19 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -final class RegularImmutableSet extends ImmutableSet { +final class RegularImmutableSet extends ImmutableSet { static final RegularImmutableSet EMPTY = new RegularImmutableSet<>(new Object[0], 0, null, 0); private final transient Object[] elements; // the same elements in hashed positions (plus nulls) - @VisibleForTesting final transient Object[] table; + @VisibleForTesting final transient @Nullable Object @Nullable [] table; // 'and' with an int to get a valid table index. private final transient int mask; private final transient int hashCode; - RegularImmutableSet(Object[] elements, int hashCode, Object[] table, int mask) { + RegularImmutableSet( + Object[] elements, int hashCode, @Nullable Object @Nullable [] table, int mask) { this.elements = elements; this.table = table; this.mask = mask; @@ -49,7 +51,7 @@ final class RegularImmutableSet extends ImmutableSet { @Override public boolean contains(@Nullable Object target) { - Object[] table = this.table; + @Nullable Object[] table = this.table; if (target == null || table == null) { return false; } diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java b/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java index 3056d56f4f18..e8c087bf938c 100644 --- a/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java +++ b/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java @@ -23,6 +23,7 @@ import com.google.common.primitives.Ints; import java.util.Comparator; import java.util.function.ObjIntConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -32,7 +33,8 @@ */ @SuppressWarnings("serial") // uses writeReplace, not default serialization @GwtIncompatible -final class RegularImmutableSortedMultiset extends ImmutableSortedMultiset { +final class RegularImmutableSortedMultiset + extends ImmutableSortedMultiset { private static final long[] ZERO_CUMULATIVE_COUNTS = {0}; static final ImmutableSortedMultiset NATURAL_EMPTY_MULTISET = @@ -76,12 +78,12 @@ public void forEachEntry(ObjIntConsumer action) { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return isEmpty() ? null : getEntry(0); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return isEmpty() ? null : getEntry(length - 1); } diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedSet.java b/guava/src/com/google/common/collect/RegularImmutableSortedSet.java index c659adad7410..f0bc8563e032 100644 --- a/guava/src/com/google/common/collect/RegularImmutableSortedSet.java +++ b/guava/src/com/google/common/collect/RegularImmutableSortedSet.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.Spliterator; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,7 +40,7 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings({"serial", "rawtypes"}) -final class RegularImmutableSortedSet extends ImmutableSortedSet { +final class RegularImmutableSortedSet extends ImmutableSortedSet { static final RegularImmutableSortedSet NATURAL_EMPTY_SET = new RegularImmutableSortedSet<>(ImmutableList.of(), Ordering.natural()); @@ -51,7 +52,7 @@ final class RegularImmutableSortedSet extends ImmutableSortedSet { } @Override - Object[] internalArray() { + Object @Nullable [] internalArray() { return elements.internalArray(); } @@ -220,25 +221,25 @@ public E last() { } @Override - public E lower(E element) { + public @Nullable E lower(E element) { int index = headIndex(element, false) - 1; return (index == -1) ? null : elements.get(index); } @Override - public E floor(E element) { + public @Nullable E floor(E element) { int index = headIndex(element, true) - 1; return (index == -1) ? null : elements.get(index); } @Override - public E ceiling(E element) { + public @Nullable E ceiling(E element) { int index = tailIndex(element, true); return (index == size()) ? null : elements.get(index); } @Override - public E higher(E element) { + public @Nullable E higher(E element) { int index = tailIndex(element, false); return (index == size()) ? null : elements.get(index); } diff --git a/guava/src/com/google/common/collect/RegularImmutableTable.java b/guava/src/com/google/common/collect/RegularImmutableTable.java index 1511fa2b467e..25a5cdacd17a 100644 --- a/guava/src/com/google/common/collect/RegularImmutableTable.java +++ b/guava/src/com/google/common/collect/RegularImmutableTable.java @@ -24,6 +24,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -32,7 +33,9 @@ * @author Gregory Kick */ @GwtCompatible -abstract class RegularImmutableTable extends ImmutableTable { +abstract class RegularImmutableTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends ImmutableTable { RegularImmutableTable() {} abstract Cell getCell(int iterationIndex); @@ -57,7 +60,13 @@ Cell get(int index) { @Override public boolean contains(@Nullable Object object) { if (object instanceof Cell) { - Cell cell = (Cell) object; + Cell + cell = + (Cell< + ?, + ?, + ?>) + object; Object value = RegularImmutableTable.this.get(cell.getRowKey(), cell.getColumnKey()); return value != null && value.equals(cell.getValue()); } @@ -95,10 +104,11 @@ boolean isPartialView() { } } - static RegularImmutableTable forCells( - List> cells, - final @Nullable Comparator rowComparator, - final @Nullable Comparator columnComparator) { + static + RegularImmutableTable forCells( + List> cells, + final @Nullable Comparator rowComparator, + final @Nullable Comparator columnComparator) { checkNotNull(cells); if (rowComparator != null || columnComparator != null) { /* @@ -129,14 +139,16 @@ public int compare(Cell cell1, Cell cell2) { return forCellsInternal(cells, rowComparator, columnComparator); } - static RegularImmutableTable forCells(Iterable> cells) { + static + RegularImmutableTable forCells(Iterable> cells) { return forCellsInternal(cells, null, null); } - private static RegularImmutableTable forCellsInternal( - Iterable> cells, - @Nullable Comparator rowComparator, - @Nullable Comparator columnComparator) { + private static + RegularImmutableTable forCellsInternal( + Iterable> cells, + @Nullable Comparator rowComparator, + @Nullable Comparator columnComparator) { Set rowSpaceBuilder = new LinkedHashSet<>(); Set columnSpaceBuilder = new LinkedHashSet<>(); ImmutableList> cellList = ImmutableList.copyOf(cells); @@ -158,10 +170,11 @@ private static RegularImmutableTable forCellsInternal( } /** A factory that chooses the most space-efficient representation of the table. */ - static RegularImmutableTable forOrderedComponents( - ImmutableList> cellList, - ImmutableSet rowSpace, - ImmutableSet columnSpace) { + static + RegularImmutableTable forOrderedComponents( + ImmutableList> cellList, + ImmutableSet rowSpace, + ImmutableSet columnSpace) { // use a dense table if more than half of the cells have values // TODO(gak): tune this condition based on empirical evidence return (cellList.size() > (((long) rowSpace.size() * columnSpace.size()) / 2)) @@ -174,7 +187,7 @@ static RegularImmutableTable forOrderedComponents( * We could have declared this method 'static' but the additional compile-time checks achieved by * referencing the type variables seem worthwhile. */ - final void checkNoDuplicate(R rowKey, C columnKey, V existingValue, V newValue) { + final void checkNoDuplicate(R rowKey, C columnKey, @Nullable V existingValue, V newValue) { checkArgument( existingValue == null, "Duplicate key: (row=%s, column=%s), values: [%s, %s].", diff --git a/guava/src/com/google/common/collect/ReverseNaturalOrdering.java b/guava/src/com/google/common/collect/ReverseNaturalOrdering.java index 612d846a7727..0ec5f84ada1b 100644 --- a/guava/src/com/google/common/collect/ReverseNaturalOrdering.java +++ b/guava/src/com/google/common/collect/ReverseNaturalOrdering.java @@ -25,63 +25,64 @@ /** An ordering that uses the reverse of the natural order of the values. */ @GwtCompatible(serializable = true) @SuppressWarnings({"unchecked", "rawtypes"}) // TODO(kevinb): the right way to explain this?? -final class ReverseNaturalOrdering extends Ordering implements Serializable { +final class ReverseNaturalOrdering extends Ordering> implements Serializable { static final ReverseNaturalOrdering INSTANCE = new ReverseNaturalOrdering(); @Override - public int compare(Comparable left, Comparable right) { + @SuppressWarnings("unchecked") // not safe because we want to support raw Comparable (#989) + public int compare(Comparable left, Comparable right) { checkNotNull(left); // right null is caught later if (left == right) { return 0; } - return right.compareTo(left); + return ((Comparable) right).compareTo(left); } @Override - public Ordering reverse() { + public > Ordering reverse() { return Ordering.natural(); } // Override the min/max methods to "hoist" delegation outside loops @Override - public E min(E a, E b) { + public > E min(E a, E b) { return NaturalOrdering.INSTANCE.max(a, b); } @Override - public E min(E a, E b, E c, E... rest) { + public > E min(E a, E b, E c, E... rest) { return NaturalOrdering.INSTANCE.max(a, b, c, rest); } @Override - public E min(Iterator iterator) { + public > E min(Iterator iterator) { return NaturalOrdering.INSTANCE.max(iterator); } @Override - public E min(Iterable iterable) { + public > E min(Iterable iterable) { return NaturalOrdering.INSTANCE.max(iterable); } @Override - public E max(E a, E b) { + public > E max(E a, E b) { return NaturalOrdering.INSTANCE.min(a, b); } @Override - public E max(E a, E b, E c, E... rest) { + public > E max(E a, E b, E c, E... rest) { return NaturalOrdering.INSTANCE.min(a, b, c, rest); } @Override - public E max(Iterator iterator) { + public > E max(Iterator iterator) { return NaturalOrdering.INSTANCE.min(iterator); } @Override - public E max(Iterable iterable) { + public > E max(Iterable iterable) { return NaturalOrdering.INSTANCE.min(iterable); } diff --git a/guava/src/com/google/common/collect/ReverseOrdering.java b/guava/src/com/google/common/collect/ReverseOrdering.java index ab9c3ac77864..b9068e6e7f99 100644 --- a/guava/src/com/google/common/collect/ReverseOrdering.java +++ b/guava/src/com/google/common/collect/ReverseOrdering.java @@ -25,7 +25,8 @@ /** An ordering that uses the reverse of a given order. */ @GwtCompatible(serializable = true) -final class ReverseOrdering extends Ordering implements Serializable { +final class ReverseOrdering extends Ordering + implements Serializable { final Ordering forwardOrder; ReverseOrdering(Ordering forwardOrder) { @@ -96,7 +97,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof ReverseOrdering) { - ReverseOrdering that = (ReverseOrdering) object; + ReverseOrdering that = + (ReverseOrdering) object; return this.forwardOrder.equals(that.forwardOrder); } return false; diff --git a/guava/src/com/google/common/collect/RowSortedTable.java b/guava/src/com/google/common/collect/RowSortedTable.java index 9cdae791946d..f2d226113e8c 100644 --- a/guava/src/com/google/common/collect/RowSortedTable.java +++ b/guava/src/com/google/common/collect/RowSortedTable.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Interface that extends {@code Table} and whose rows are sorted. @@ -33,7 +34,9 @@ * @since 8.0 */ @GwtCompatible -public interface RowSortedTable extends Table { +public interface RowSortedTable< + R, C, V> + extends Table { /** * {@inheritDoc} * diff --git a/guava/src/com/google/common/collect/Serialization.java b/guava/src/com/google/common/collect/Serialization.java index 929a48f01c15..e473dffac5ae 100644 --- a/guava/src/com/google/common/collect/Serialization.java +++ b/guava/src/com/google/common/collect/Serialization.java @@ -23,6 +23,8 @@ import java.lang.reflect.Field; import java.util.Collection; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Provides static methods for serializing collection classes. @@ -54,7 +56,8 @@ static int readCount(ObjectInputStream stream) throws IOException { *

    The serialized output consists of the number of entries, first key, first value, second key, * second value, and so on. */ - static void writeMap(Map map, ObjectOutputStream stream) throws IOException { + static void writeMap( + Map map, ObjectOutputStream stream) throws IOException { stream.writeInt(map.size()); for (Map.Entry entry : map.entrySet()) { stream.writeObject(entry.getKey()); @@ -66,8 +69,8 @@ static void writeMap(Map map, ObjectOutputStream stream) throws IOE * Populates a map by reading an input stream, as part of deserialization. See {@link #writeMap} * for the data format. */ - static void populateMap(Map map, ObjectInputStream stream) - throws IOException, ClassNotFoundException { + static void populateMap( + Map map, ObjectInputStream stream) throws IOException, ClassNotFoundException { int size = stream.readInt(); populateMap(map, stream, size); } @@ -76,7 +79,8 @@ static void populateMap(Map map, ObjectInputStream stream) * Populates a map by reading an input stream, as part of deserialization. See {@link #writeMap} * for the data format. The size is determined by a prior call to {@link #readCount}. */ - static void populateMap(Map map, ObjectInputStream stream, int size) + static void populateMap( + Map map, ObjectInputStream stream, int size) throws IOException, ClassNotFoundException { for (int i = 0; i < size; i++) { @SuppressWarnings("unchecked") // reading data stored by writeMap @@ -94,8 +98,8 @@ static void populateMap(Map map, ObjectInputStream stream, int size *

    The serialized output consists of the number of distinct elements, the first element, its * count, the second element, its count, and so on. */ - static void writeMultiset(Multiset multiset, ObjectOutputStream stream) - throws IOException { + static void writeMultiset( + Multiset multiset, ObjectOutputStream stream) throws IOException { int entryCount = multiset.entrySet().size(); stream.writeInt(entryCount); for (Multiset.Entry entry : multiset.entrySet()) { @@ -108,8 +112,8 @@ static void writeMultiset(Multiset multiset, ObjectOutputStream stream) * Populates a multiset by reading an input stream, as part of deserialization. See {@link * #writeMultiset} for the data format. */ - static void populateMultiset(Multiset multiset, ObjectInputStream stream) - throws IOException, ClassNotFoundException { + static void populateMultiset( + Multiset multiset, ObjectInputStream stream) throws IOException, ClassNotFoundException { int distinctElements = stream.readInt(); populateMultiset(multiset, stream, distinctElements); } @@ -138,8 +142,8 @@ static void populateMultiset( *

    The serialized output consists of the number of distinct keys, and then for each distinct * key: the key, the number of values for that key, and the key's values. */ - static void writeMultimap(Multimap multimap, ObjectOutputStream stream) - throws IOException { + static void writeMultimap( + Multimap multimap, ObjectOutputStream stream) throws IOException { stream.writeInt(multimap.asMap().size()); for (Map.Entry> entry : multimap.asMap().entrySet()) { stream.writeObject(entry.getKey()); @@ -154,7 +158,8 @@ static void writeMultimap(Multimap multimap, ObjectOutputStream str * Populates a multimap by reading an input stream, as part of deserialization. See {@link * #writeMultimap} for the data format. */ - static void populateMultimap(Multimap multimap, ObjectInputStream stream) + static void populateMultimap( + Multimap multimap, ObjectInputStream stream) throws IOException, ClassNotFoundException { int distinctKeys = stream.readInt(); populateMultimap(multimap, stream, distinctKeys); @@ -182,7 +187,8 @@ static void populateMultimap( } // Secret sauce for setting final fields; don't make it public. - static FieldSetter getFieldSetter(final Class clazz, String fieldName) { + static FieldSetter getFieldSetter( + final Class clazz, String fieldName) { try { Field field = clazz.getDeclaredField(fieldName); return new FieldSetter(field); @@ -192,7 +198,7 @@ static FieldSetter getFieldSetter(final Class clazz, String fieldName) } // Secret sauce for setting final fields; don't make it public. - static final class FieldSetter { + static final class FieldSetter { private final Field field; private FieldSetter(Field field) { diff --git a/guava/src/com/google/common/collect/SetMultimap.java b/guava/src/com/google/common/collect/SetMultimap.java index 90e6e1b03144..bdf5384b0928 100644 --- a/guava/src/com/google/common/collect/SetMultimap.java +++ b/guava/src/com/google/common/collect/SetMultimap.java @@ -49,7 +49,8 @@ * @since 2.0 */ @GwtCompatible -public interface SetMultimap extends Multimap { +public interface SetMultimap + extends Multimap { /** * {@inheritDoc} * @@ -58,7 +59,7 @@ public interface SetMultimap extends Multimap { * interface. */ @Override - Set get(@Nullable K key); + Set get(K key); /** * {@inheritDoc} diff --git a/guava/src/com/google/common/collect/Sets.java b/guava/src/com/google/common/collect/Sets.java index b2e394bb0e44..0fa1736858b3 100644 --- a/guava/src/com/google/common/collect/Sets.java +++ b/guava/src/com/google/common/collect/Sets.java @@ -51,6 +51,7 @@ import java.util.function.Consumer; import java.util.stream.Collector; import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -287,7 +288,8 @@ public static HashSet newHashSet(Iterator elements) { * without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ - public static HashSet newHashSetWithExpectedSize(int expectedSize) { + public static HashSet newHashSetWithExpectedSize( + int expectedSize) { return new HashSet(Maps.capacity(expectedSize)); } @@ -301,7 +303,7 @@ public static HashSet newHashSetWithExpectedSize(int expectedSize) { * @return a new, empty thread-safe {@code Set} * @since 15.0 */ - public static Set newConcurrentHashSet() { + public static Set newConcurrentHashSet() { return Collections.newSetFromMap(new ConcurrentHashMap()); } @@ -318,7 +320,8 @@ public static Set newConcurrentHashSet() { * @throws NullPointerException if {@code elements} or any of its contents is null * @since 15.0 */ - public static Set newConcurrentHashSet(Iterable elements) { + public static Set newConcurrentHashSet( + Iterable elements) { Set set = newConcurrentHashSet(); Iterables.addAll(set, elements); return set; @@ -356,7 +359,8 @@ public static LinkedHashSet newLinkedHashSet() { * @param elements the elements that the set should contain, in order * @return a new {@code LinkedHashSet} containing those elements (minus duplicates) */ - public static LinkedHashSet newLinkedHashSet(Iterable elements) { + public static LinkedHashSet newLinkedHashSet( + Iterable elements) { if (elements instanceof Collection) { return new LinkedHashSet(Collections2.cast(elements)); } @@ -377,7 +381,8 @@ public static LinkedHashSet newLinkedHashSet(Iterable elemen * @throws IllegalArgumentException if {@code expectedSize} is negative * @since 11.0 */ - public static LinkedHashSet newLinkedHashSetWithExpectedSize(int expectedSize) { + public static LinkedHashSet newLinkedHashSetWithExpectedSize( + int expectedSize) { return new LinkedHashSet(Maps.capacity(expectedSize)); } @@ -442,7 +447,8 @@ public static TreeSet newTreeSet(Iterable * @return a new, empty {@code TreeSet} * @throws NullPointerException if {@code comparator} is null */ - public static TreeSet newTreeSet(Comparator comparator) { + public static TreeSet newTreeSet( + Comparator comparator) { return new TreeSet(checkNotNull(comparator)); } @@ -481,7 +487,8 @@ public static CopyOnWriteArraySet newCopyOnWriteArraySet() { * @since 12.0 */ @GwtIncompatible // CopyOnWriteArraySet - public static CopyOnWriteArraySet newCopyOnWriteArraySet(Iterable elements) { + public static CopyOnWriteArraySet newCopyOnWriteArraySet( + Iterable elements) { // We copy elements to an ArrayList first, rather than incurring the // quadratic cost of adding them to the COWAS directly. Collection elementsCollection = @@ -593,6 +600,7 @@ private SetView() {} // no subclasses but our own * nonstandard notion of equivalence, for example if it is a {@link TreeSet} using a comparator * that is inconsistent with {@link Object#equals(Object)}. */ + @SuppressWarnings("nullness") // Unsafe, but we can't fix it now. public ImmutableSet immutableCopy() { return ImmutableSet.copyOf(this); } @@ -634,7 +642,7 @@ public final boolean add(E e) { @CanIgnoreReturnValue @Deprecated @Override - public final boolean remove(Object object) { + public final boolean remove(@Nullable Object object) { throw new UnsupportedOperationException(); } @@ -721,7 +729,8 @@ public final void clear() { * equivalence relations (as {@link HashSet}, {@link TreeSet}, and the {@link Map#keySet} of an * {@code IdentityHashMap} all are). */ - public static SetView union(final Set set1, final Set set2) { + public static SetView union( + final Set set1, final Set set2) { checkNotNull(set1, "set1"); checkNotNull(set2, "set2"); @@ -775,7 +784,7 @@ public Stream parallelStream() { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { return set1.contains(object) || set2.contains(object); } @@ -787,6 +796,7 @@ public > S copyInto(S set) { } @Override + @SuppressWarnings("nullness") // see supertype public ImmutableSet immutableCopy() { return new ImmutableSet.Builder().addAll(set1).addAll(set2).build(); } @@ -820,7 +830,8 @@ public ImmutableSet immutableCopy() { * *

    This is unfortunate, but should come up only very rarely. */ - public static SetView intersection(final Set set1, final Set set2) { + public static SetView intersection( + final Set set1, final Set set2) { checkNotNull(set1, "set1"); checkNotNull(set2, "set2"); @@ -870,7 +881,7 @@ public boolean isEmpty() { } @Override - public boolean contains(Object object) { + public boolean contains(@Nullable Object object) { return set1.contains(object) && set2.contains(object); } @@ -891,7 +902,8 @@ public boolean containsAll(Collection collection) { * equivalence relations (as {@code HashSet}, {@code TreeSet}, and the keySet of an {@code * IdentityHashMap} all are). */ - public static SetView difference(final Set set1, final Set set2) { + public static SetView difference( + final Set set1, final Set set2) { checkNotNull(set1, "set1"); checkNotNull(set2, "set2"); @@ -941,7 +953,7 @@ public boolean isEmpty() { } @Override - public boolean contains(Object element) { + public boolean contains(@Nullable Object element) { return set1.contains(element) && !set2.contains(element); } }; @@ -1010,7 +1022,7 @@ public boolean isEmpty() { } @Override - public boolean contains(Object element) { + public boolean contains(@Nullable Object element) { return set1.contains(element) ^ set2.contains(element); } }; @@ -1043,7 +1055,8 @@ public boolean contains(Object element) { * you to migrate to streams. */ // TODO(kevinb): how to omit that last sentence when building GWT javadoc? - public static Set filter(Set unfiltered, Predicate predicate) { + public static Set filter( + Set unfiltered, Predicate predicate) { if (unfiltered instanceof SortedSet) { return filter((SortedSet) unfiltered, predicate); } @@ -1082,7 +1095,8 @@ public static Set filter(Set unfiltered, Predicate predicat * * @since 11.0 */ - public static SortedSet filter(SortedSet unfiltered, Predicate predicate) { + public static SortedSet filter( + SortedSet unfiltered, Predicate predicate) { if (unfiltered instanceof FilteredSet) { // Support clear(), removeAll(), and retainAll() when filtering a filtered // collection. @@ -1133,7 +1147,8 @@ public static NavigableSet filter( return new FilteredNavigableSet(checkNotNull(unfiltered), checkNotNull(predicate)); } - private static class FilteredSet extends FilteredCollection implements Set { + private static class FilteredSet extends FilteredCollection + implements Set { FilteredSet(Set unfiltered, Predicate predicate) { super(unfiltered, predicate); } @@ -1149,14 +1164,15 @@ public int hashCode() { } } - private static class FilteredSortedSet extends FilteredSet implements SortedSet { + private static class FilteredSortedSet extends FilteredSet + implements SortedSet { FilteredSortedSet(SortedSet unfiltered, Predicate predicate) { super(unfiltered, predicate); } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return ((SortedSet) unfiltered).comparator(); } @@ -1216,22 +1232,22 @@ NavigableSet unfiltered() { } @Override - public E ceiling(E e) { + public @Nullable E ceiling(E e) { return Iterables.find(unfiltered().tailSet(e, true), predicate, null); } @Override - public E higher(E e) { + public @Nullable E higher(E e) { return Iterables.find(unfiltered().tailSet(e, false), predicate, null); } @Override - public E pollFirst() { + public @Nullable E pollFirst() { return Iterables.removeFirstMatching(unfiltered(), predicate); } @Override - public E pollLast() { + public @Nullable E pollLast() { return Iterables.removeFirstMatching(unfiltered().descendingSet(), predicate); } @@ -1321,7 +1337,8 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { * @throws IllegalArgumentException if the cartesian product size exceeds the {@code int} range * @since 2.0 */ - public static Set> cartesianProduct(List> sets) { + public static Set> cartesianProduct( + List> sets) { return CartesianSet.create(sets); } @@ -1379,16 +1396,17 @@ public static Set> cartesianProduct(List> * @since 2.0 */ @SafeVarargs - public static Set> cartesianProduct(Set... sets) { + public static Set> cartesianProduct( + Set... sets) { return cartesianProduct(Arrays.asList(sets)); } - private static final class CartesianSet extends ForwardingCollection> - implements Set> { + private static final class CartesianSet + extends ForwardingCollection> implements Set> { private final transient ImmutableList> axes; private final transient CartesianList delegate; - static Set> create(List> sets) { + static Set> create(List> sets) { ImmutableList.Builder> axesBuilder = new ImmutableList.Builder<>(sets.size()); for (Set set : sets) { ImmutableSet copy = ImmutableSet.copyOf(set); @@ -1506,11 +1524,11 @@ public int hashCode() { * @since 4.0 */ @GwtCompatible(serializable = false) - public static Set> powerSet(Set set) { + public static Set> powerSet(Set set) { return new PowerSet(set); } - private static final class SubSet extends AbstractSet { + private static final class SubSet extends AbstractSet { private final ImmutableMap inputSet; private final int mask; @@ -1554,7 +1572,7 @@ public boolean contains(@Nullable Object o) { } } - private static final class PowerSet extends AbstractSet> { + private static final class PowerSet extends AbstractSet> { final ImmutableMap inputSet; PowerSet(Set input) { @@ -1642,7 +1660,7 @@ public String toString() { * @since 23.0 */ @Beta - public static Set> combinations(Set set, final int size) { + public static Set> combinations(Set set, final int size) { final ImmutableMap index = Maps.indexMap(set); checkNonnegative(size, "size"); checkArgument(size <= index.size(), "size (%s) must be <= set.size() (%s)", size, index.size()); @@ -1782,15 +1800,16 @@ static boolean equalsImpl(Set s, @Nullable Object object) { * @return an unmodifiable view of the specified navigable set * @since 12.0 */ - public static NavigableSet unmodifiableNavigableSet(NavigableSet set) { + public static NavigableSet unmodifiableNavigableSet( + NavigableSet set) { if (set instanceof ImmutableCollection || set instanceof UnmodifiableNavigableSet) { return set; } return new UnmodifiableNavigableSet(set); } - static final class UnmodifiableNavigableSet extends ForwardingSortedSet - implements NavigableSet, Serializable { + static final class UnmodifiableNavigableSet + extends ForwardingSortedSet implements NavigableSet, Serializable { private final NavigableSet delegate; private final SortedSet unmodifiableDelegate; @@ -1827,32 +1846,32 @@ public void forEach(Consumer action) { } @Override - public E lower(E e) { + public @Nullable E lower(E e) { return delegate.lower(e); } @Override - public E floor(E e) { + public @Nullable E floor(E e) { return delegate.floor(e); } @Override - public E ceiling(E e) { + public @Nullable E ceiling(E e) { return delegate.ceiling(e); } @Override - public E higher(E e) { + public @Nullable E higher(E e) { return delegate.higher(e); } @Override - public E pollFirst() { + public @Nullable E pollFirst() { throw new UnsupportedOperationException(); } @Override - public E pollLast() { + public @Nullable E pollLast() { throw new UnsupportedOperationException(); } @@ -1939,12 +1958,14 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { * @since 13.0 */ @GwtIncompatible // NavigableSet - public static NavigableSet synchronizedNavigableSet(NavigableSet navigableSet) { + public static NavigableSet synchronizedNavigableSet( + NavigableSet navigableSet) { return Synchronized.navigableSet(navigableSet); } /** Remove each element in an iterable from a set. */ - static boolean removeAllImpl(Set set, Iterator iterator) { + static boolean removeAllImpl( + Set set, Iterator iterator) { boolean changed = false; while (iterator.hasNext()) { changed |= set.remove(iterator.next()); @@ -1952,7 +1973,8 @@ static boolean removeAllImpl(Set set, Iterator iterator) { return changed; } - static boolean removeAllImpl(Set set, Collection collection) { + static boolean removeAllImpl( + Set set, Collection collection) { checkNotNull(collection); // for GWT if (collection instanceof Multiset) { collection = ((Multiset) collection).elementSet(); @@ -1985,32 +2007,32 @@ protected NavigableSet delegate() { } @Override - public E lower(E e) { + public @Nullable E lower(E e) { return forward.higher(e); } @Override - public E floor(E e) { + public @Nullable E floor(E e) { return forward.ceiling(e); } @Override - public E ceiling(E e) { + public @Nullable E ceiling(E e) { return forward.floor(e); } @Override - public E higher(E e) { + public @Nullable E higher(E e) { return forward.lower(e); } @Override - public E pollFirst() { + public @Nullable E pollFirst() { return forward.pollLast(); } @Override - public E pollLast() { + public @Nullable E pollLast() { return forward.pollFirst(); } @@ -2087,11 +2109,13 @@ public Iterator iterator() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { return standardToArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return standardToArray(array); } diff --git a/guava/src/com/google/common/collect/SingletonImmutableBiMap.java b/guava/src/com/google/common/collect/SingletonImmutableBiMap.java index 32376e07803b..1c95112b3ba9 100644 --- a/guava/src/com/google/common/collect/SingletonImmutableBiMap.java +++ b/guava/src/com/google/common/collect/SingletonImmutableBiMap.java @@ -23,6 +23,7 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import com.google.j2objc.annotations.RetainedWith; import java.util.function.BiConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -33,7 +34,8 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -final class SingletonImmutableBiMap extends ImmutableBiMap { +final class SingletonImmutableBiMap + extends ImmutableBiMap { final transient K singleKey; final transient V singleValue; @@ -51,7 +53,7 @@ private SingletonImmutableBiMap(K singleKey, V singleValue, ImmutableBiMap } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { return singleKey.equals(key) ? singleValue : null; } @@ -90,7 +92,7 @@ ImmutableSet createKeySet() { return ImmutableSet.of(singleKey); } - @LazyInit @RetainedWith transient ImmutableBiMap inverse; + @LazyInit @RetainedWith transient @Nullable ImmutableBiMap inverse; @Override public ImmutableBiMap inverse() { diff --git a/guava/src/com/google/common/collect/SingletonImmutableList.java b/guava/src/com/google/common/collect/SingletonImmutableList.java index eec0daa18263..11f64aed8fc3 100644 --- a/guava/src/com/google/common/collect/SingletonImmutableList.java +++ b/guava/src/com/google/common/collect/SingletonImmutableList.java @@ -22,6 +22,7 @@ import com.google.common.base.Preconditions; import java.util.Collections; import java.util.Spliterator; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Implementation of {@link ImmutableList} with exactly one element. @@ -30,7 +31,7 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -final class SingletonImmutableList extends ImmutableList { +final class SingletonImmutableList extends ImmutableList { final transient E element; diff --git a/guava/src/com/google/common/collect/SingletonImmutableSet.java b/guava/src/com/google/common/collect/SingletonImmutableSet.java index 0f882b3eaad9..b92c1aa0d000 100644 --- a/guava/src/com/google/common/collect/SingletonImmutableSet.java +++ b/guava/src/com/google/common/collect/SingletonImmutableSet.java @@ -19,6 +19,8 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.base.Preconditions; import com.google.errorprone.annotations.concurrent.LazyInit; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Implementation of {@link ImmutableSet} with exactly one element. @@ -28,7 +30,7 @@ */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // uses writeReplace(), not default serialization -final class SingletonImmutableSet extends ImmutableSet { +final class SingletonImmutableSet extends ImmutableSet { final transient E element; // This is transient because it will be recalculated on the first @@ -56,7 +58,7 @@ public int size() { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { return element.equals(target); } diff --git a/guava/src/com/google/common/collect/SingletonImmutableTable.java b/guava/src/com/google/common/collect/SingletonImmutableTable.java index 58a182cccd3e..bbbe39e21a01 100644 --- a/guava/src/com/google/common/collect/SingletonImmutableTable.java +++ b/guava/src/com/google/common/collect/SingletonImmutableTable.java @@ -20,6 +20,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; /** * An implementation of {@link ImmutableTable} that holds a single cell. @@ -27,7 +28,9 @@ * @author Gregory Kick */ @GwtCompatible -class SingletonImmutableTable extends ImmutableTable { +class SingletonImmutableTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends ImmutableTable { final R singleRowKey; final C singleColumnKey; final V singleValue; diff --git a/guava/src/com/google/common/collect/SortedIterable.java b/guava/src/com/google/common/collect/SortedIterable.java index d46e8afcd9c5..434a541afaf2 100644 --- a/guava/src/com/google/common/collect/SortedIterable.java +++ b/guava/src/com/google/common/collect/SortedIterable.java @@ -17,6 +17,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Comparator; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An {@code Iterable} whose elements are sorted relative to a {@code Comparator}, typically diff --git a/guava/src/com/google/common/collect/SortedIterables.java b/guava/src/com/google/common/collect/SortedIterables.java index 2c0aa7ccac89..bf33cc439a7e 100644 --- a/guava/src/com/google/common/collect/SortedIterables.java +++ b/guava/src/com/google/common/collect/SortedIterables.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Comparator; import java.util.SortedSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Utilities for dealing with sorted collections of all types. @@ -33,7 +34,9 @@ private SortedIterables() {} * Returns {@code true} if {@code elements} is a sorted collection using an ordering equivalent to * {@code comparator}. */ - public static boolean hasSameComparator(Comparator comparator, Iterable elements) { + public static boolean hasSameComparator( + Comparator comparator, + Iterable elements) { checkNotNull(comparator); checkNotNull(elements); Comparator comparator2; @@ -49,7 +52,8 @@ public static boolean hasSameComparator(Comparator comparator, Iterable el @SuppressWarnings("unchecked") // if sortedSet.comparator() is null, the set must be naturally ordered - public static Comparator comparator(SortedSet sortedSet) { + public static Comparator comparator( + SortedSet sortedSet) { Comparator result = sortedSet.comparator(); if (result == null) { result = (Comparator) Ordering.natural(); diff --git a/guava/src/com/google/common/collect/SortedLists.java b/guava/src/com/google/common/collect/SortedLists.java index 339e7fce77a5..96e048ab1fca 100644 --- a/guava/src/com/google/common/collect/SortedLists.java +++ b/guava/src/com/google/common/collect/SortedLists.java @@ -35,13 +35,15 @@ * @author Louis Wasserman */ @GwtCompatible -@Beta final class SortedLists { +@Beta +final class SortedLists { private SortedLists() {} /** * A specification for which index to return if the list contains at least one element that * compares as equal to the key. - */ enum KeyPresentBehavior { + */ + enum KeyPresentBehavior { /** * Return the index of any list element that compares as equal to the key. No guarantees are * made as to which index is returned, if more than one element compares as equal to the key. @@ -128,7 +130,8 @@ abstract int resultIndex( /** * A specification for which index to return if the list contains no elements that compare as * equal to the key. - */ enum KeyAbsentBehavior { + */ + enum KeyAbsentBehavior { /** * Return the index of the next lower element in the list, or {@code -1} if there is no such * element. @@ -196,7 +199,7 @@ public static int binarySearch( public static int binarySearch( List list, Function keyFunction, - @Nullable K key, + K key, KeyPresentBehavior presentBehavior, KeyAbsentBehavior absentBehavior) { return binarySearch( @@ -213,7 +216,7 @@ public static int binarySearch( public static int binarySearch( List list, Function keyFunction, - @Nullable K key, + K key, Comparator keyComparator, KeyPresentBehavior presentBehavior, KeyAbsentBehavior absentBehavior) { @@ -246,7 +249,7 @@ public static int binarySearch( */ public static int binarySearch( List list, - @Nullable E key, + E key, Comparator comparator, KeyPresentBehavior presentBehavior, KeyAbsentBehavior absentBehavior) { diff --git a/guava/src/com/google/common/collect/SortedMapDifference.java b/guava/src/com/google/common/collect/SortedMapDifference.java index 4715e93e5c9c..87f2aebaebc7 100644 --- a/guava/src/com/google/common/collect/SortedMapDifference.java +++ b/guava/src/com/google/common/collect/SortedMapDifference.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.SortedMap; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An object representing the differences between two sorted maps. @@ -26,7 +27,8 @@ * @since 8.0 */ @GwtCompatible -public interface SortedMapDifference extends MapDifference { +public interface SortedMapDifference + extends MapDifference { @Override SortedMap entriesOnlyOnLeft(); diff --git a/guava/src/com/google/common/collect/SortedMultiset.java b/guava/src/com/google/common/collect/SortedMultiset.java index 2635b37ede33..99ddfa490e46 100644 --- a/guava/src/com/google/common/collect/SortedMultiset.java +++ b/guava/src/com/google/common/collect/SortedMultiset.java @@ -22,6 +22,7 @@ import java.util.Iterator; import java.util.NavigableSet; import java.util.Set; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link Multiset} which maintains the ordering of its elements, according to either their @@ -42,7 +43,8 @@ * @since 11.0 */ @GwtCompatible(emulated = true) -public interface SortedMultiset extends SortedMultisetBridge, SortedIterable { +public interface SortedMultiset + extends SortedMultisetBridge, SortedIterable { /** * Returns the comparator that orders this multiset, or {@link Ordering#natural()} if the natural * ordering of the elements is used. @@ -54,24 +56,28 @@ public interface SortedMultiset extends SortedMultisetBridge, SortedIterab * Returns the entry of the first element in this multiset, or {@code null} if this multiset is * empty. */ + @Nullable Entry firstEntry(); /** * Returns the entry of the last element in this multiset, or {@code null} if this multiset is * empty. */ + @Nullable Entry lastEntry(); /** * Returns and removes the entry associated with the lowest element in this multiset, or returns * {@code null} if this multiset is empty. */ + @Nullable Entry pollFirstEntry(); /** * Returns and removes the entry associated with the greatest element in this multiset, or returns * {@code null} if this multiset is empty. */ + @Nullable Entry pollLastEntry(); /** diff --git a/guava/src/com/google/common/collect/SortedMultisetBridge.java b/guava/src/com/google/common/collect/SortedMultisetBridge.java index 064cb7588f5d..cdc0a0b349c6 100644 --- a/guava/src/com/google/common/collect/SortedMultisetBridge.java +++ b/guava/src/com/google/common/collect/SortedMultisetBridge.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtIncompatible; import java.util.SortedSet; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Superinterface of {@link SortedMultiset} to introduce a bridge method for {@code elementSet()}, diff --git a/guava/src/com/google/common/collect/SortedMultisets.java b/guava/src/com/google/common/collect/SortedMultisets.java index a928959e9c30..f41448cdbe23 100644 --- a/guava/src/com/google/common/collect/SortedMultisets.java +++ b/guava/src/com/google/common/collect/SortedMultisets.java @@ -40,7 +40,8 @@ final class SortedMultisets { private SortedMultisets() {} /** A skeleton implementation for {@link SortedMultiset#elementSet}. */ - static class ElementSet extends Multisets.ElementSet implements SortedSet { + static class ElementSet extends Multisets.ElementSet + implements SortedSet { @Weak private final SortedMultiset multiset; ElementSet(SortedMultiset multiset) { @@ -90,28 +91,29 @@ public E last() { /** A skeleton navigable implementation for {@link SortedMultiset#elementSet}. */ @GwtIncompatible // Navigable - static class NavigableElementSet extends ElementSet implements NavigableSet { + static class NavigableElementSet extends ElementSet + implements NavigableSet { NavigableElementSet(SortedMultiset multiset) { super(multiset); } @Override - public E lower(E e) { + public @Nullable E lower(E e) { return getElementOrNull(multiset().headMultiset(e, OPEN).lastEntry()); } @Override - public E floor(E e) { + public @Nullable E floor(E e) { return getElementOrNull(multiset().headMultiset(e, CLOSED).lastEntry()); } @Override - public E ceiling(E e) { + public @Nullable E ceiling(E e) { return getElementOrNull(multiset().tailMultiset(e, CLOSED).firstEntry()); } @Override - public E higher(E e) { + public @Nullable E higher(E e) { return getElementOrNull(multiset().tailMultiset(e, OPEN).firstEntry()); } @@ -126,12 +128,12 @@ public Iterator descendingIterator() { } @Override - public E pollFirst() { + public @Nullable E pollFirst() { return getElementOrNull(multiset().pollFirstEntry()); } @Override - public E pollLast() { + public @Nullable E pollLast() { return getElementOrNull(multiset().pollLastEntry()); } @@ -158,14 +160,15 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { } } - private static E getElementOrThrow(Entry entry) { + private static E getElementOrThrow(@Nullable Entry entry) { if (entry == null) { throw new NoSuchElementException(); } return entry.getElement(); } - private static E getElementOrNull(@Nullable Entry entry) { + private static @Nullable E getElementOrNull( + @Nullable Entry entry) { return (entry == null) ? null : entry.getElement(); } } diff --git a/guava/src/com/google/common/collect/SortedSetMultimap.java b/guava/src/com/google/common/collect/SortedSetMultimap.java index 9f073bfc8816..798291d8375d 100644 --- a/guava/src/com/google/common/collect/SortedSetMultimap.java +++ b/guava/src/com/google/common/collect/SortedSetMultimap.java @@ -45,7 +45,8 @@ * @since 2.0 */ @GwtCompatible -public interface SortedSetMultimap extends SetMultimap { +public interface SortedSetMultimap + extends SetMultimap { // Following Javadoc copied from Multimap. /** @@ -59,7 +60,7 @@ public interface SortedSetMultimap extends SetMultimap { * {@link Multimap} interface. */ @Override - SortedSet get(@Nullable K key); + SortedSet get(K key); /** * Removes all values associated with a given key. @@ -109,5 +110,6 @@ public interface SortedSetMultimap extends SetMultimap { * Returns the comparator that orders the multimap values, with {@code null} indicating that * natural ordering is used. */ + @Nullable Comparator valueComparator(); } diff --git a/guava/src/com/google/common/collect/SparseImmutableTable.java b/guava/src/com/google/common/collect/SparseImmutableTable.java index a7fe85debd1c..06e5cc37f7a7 100644 --- a/guava/src/com/google/common/collect/SparseImmutableTable.java +++ b/guava/src/com/google/common/collect/SparseImmutableTable.java @@ -14,16 +14,21 @@ package com.google.common.collect; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.GwtCompatible; import com.google.errorprone.annotations.Immutable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; +import org.checkerframework.checker.nullness.qual.NonNull; /** A {@code RegularImmutableTable} optimized for sparse data. */ @GwtCompatible @Immutable(containerOf = {"R", "C", "V"}) -final class SparseImmutableTable extends RegularImmutableTable { +final class SparseImmutableTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends RegularImmutableTable { static final ImmutableTable EMPTY = new SparseImmutableTable<>( ImmutableList.>of(), ImmutableSet.of(), ImmutableSet.of()); @@ -61,12 +66,16 @@ final class SparseImmutableTable extends RegularImmutableTable C columnKey = cell.getColumnKey(); V value = cell.getValue(); - cellRowIndices[i] = rowIndex.get(rowKey); - Map thisRow = rows.get(rowKey); + /* + * These requireNonNull calls are safe because we construct the maps to hold all the provided + * cells. + */ + cellRowIndices[i] = requireNonNull(rowIndex.get(rowKey)); + Map thisRow = requireNonNull(rows.get(rowKey)); cellColumnInRowIndices[i] = thisRow.size(); V oldValue = thisRow.put(columnKey, value); checkNoDuplicate(rowKey, columnKey, oldValue, value); - columns.get(columnKey).put(rowKey, value); + requireNonNull(columns.get(columnKey)).put(rowKey, value); } this.cellRowIndices = cellRowIndices; this.cellColumnInRowIndices = cellColumnInRowIndices; @@ -128,7 +137,8 @@ SerializedForm createSerializedForm() { int[] cellColumnIndices = new int[cellSet().size()]; int i = 0; for (Cell cell : cellSet()) { - cellColumnIndices[i++] = columnKeyToIndex.get(cell.getColumnKey()); + // requireNonNull is safe because the cell exists in the table. + cellColumnIndices[i++] = requireNonNull(columnKeyToIndex.get(cell.getColumnKey())); } return SerializedForm.create(this, cellRowIndices, cellColumnIndices); } diff --git a/guava/src/com/google/common/collect/StandardRowSortedTable.java b/guava/src/com/google/common/collect/StandardRowSortedTable.java index 19a14c38533f..1fd36e2e20c8 100644 --- a/guava/src/com/google/common/collect/StandardRowSortedTable.java +++ b/guava/src/com/google/common/collect/StandardRowSortedTable.java @@ -26,6 +26,8 @@ import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Implementation of {@code Table} whose iteration ordering across row keys is sorted by their @@ -45,8 +47,9 @@ * @author Jared Levy */ @GwtCompatible -class StandardRowSortedTable extends StandardTable - implements RowSortedTable { +class StandardRowSortedTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends StandardTable implements RowSortedTable { /* * TODO(jlevy): Consider adding headTable, tailTable, and subTable methods, * which return a Table view with rows keys in a given range. Create a @@ -102,7 +105,7 @@ SortedSet createKeySet() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { return sortedBackingMap().comparator(); } diff --git a/guava/src/com/google/common/collect/StandardTable.java b/guava/src/com/google/common/collect/StandardTable.java index 6adc4dca0db8..b2a89788736d 100644 --- a/guava/src/com/google/common/collect/StandardTable.java +++ b/guava/src/com/google/common/collect/StandardTable.java @@ -23,6 +23,7 @@ import static com.google.common.base.Predicates.not; import static com.google.common.collect.Maps.safeContainsKey; import static com.google.common.collect.Maps.safeGet; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Function; @@ -42,6 +43,7 @@ import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -64,7 +66,8 @@ * @author Jared Levy */ @GwtCompatible -class StandardTable extends AbstractTable implements Serializable { +class StandardTable + extends AbstractTable implements Serializable { @GwtTransient final Map> backingMap; @GwtTransient final Supplier> factory; @@ -104,7 +107,7 @@ public boolean containsValue(@Nullable Object value) { } @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { return (rowKey == null || columnKey == null) ? null : super.get(rowKey, columnKey); } @@ -140,7 +143,7 @@ private Map getOrCreate(R rowKey) { @CanIgnoreReturnValue @Override - public V put(R rowKey, C columnKey, V value) { + public @Nullable V put(R rowKey, C columnKey, V value) { checkNotNull(rowKey); checkNotNull(columnKey); checkNotNull(value); @@ -149,7 +152,7 @@ public V put(R rowKey, C columnKey, V value) { @CanIgnoreReturnValue @Override - public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { if ((rowKey == null) || (columnKey == null)) { return null; } @@ -165,7 +168,7 @@ public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { } @CanIgnoreReturnValue - private Map removeColumn(Object column) { + private Map removeColumn(@Nullable Object column) { Map output = new LinkedHashMap<>(); Iterator>> iterator = backingMap.entrySet().iterator(); while (iterator.hasNext()) { @@ -181,12 +184,14 @@ private Map removeColumn(Object column) { return output; } - private boolean containsMapping(Object rowKey, Object columnKey, Object value) { + private boolean containsMapping( + @Nullable Object rowKey, @Nullable Object columnKey, @Nullable Object value) { return value != null && value.equals(get(rowKey, columnKey)); } /** Remove a row key / column key / value mapping, if present. */ - private boolean removeMapping(Object rowKey, Object columnKey, Object value) { + private boolean removeMapping( + @Nullable Object rowKey, @Nullable Object columnKey, @Nullable Object value) { if (containsMapping(rowKey, columnKey, value)) { remove(rowKey, columnKey); return true; @@ -248,6 +253,8 @@ public Cell next() { rowEntry = rowIterator.next(); columnIterator = rowEntry.getValue().entrySet().iterator(); } + // requireNonNull is safe because of the hasNext check. + requireNonNull(rowEntry); Entry columnEntry = columnIterator.next(); return Tables.immutableCell(rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue()); } @@ -255,7 +262,15 @@ public Cell next() { @Override public void remove() { columnIterator.remove(); - if (rowEntry.getValue().isEmpty()) { + /* + * requireNonNull is safe because: + * + * - columnIterator.remove() succeeded, so it must have returned a value, so it must have been + * initialized by next() -- which initializes rowEntry, too. + * + * - rowEntry isn't cleared until columnIterator is exhausted. + */ + if (requireNonNull(rowEntry).getValue().isEmpty()) { rowIterator.remove(); rowEntry = null; } @@ -290,38 +305,40 @@ class Row extends IteratorBasedAbstractMap { @Nullable Map backingRowMap; + @Nullable Map backingRowMap() { return (backingRowMap == null || (backingRowMap.isEmpty() && backingMap.containsKey(rowKey))) ? backingRowMap = computeBackingRowMap() : backingRowMap; } + @Nullable Map computeBackingRowMap() { return backingMap.get(rowKey); } // Call this every time we perform a removal. void maintainEmptyInvariant() { - if (backingRowMap() != null && backingRowMap.isEmpty()) { + if (nonNullButEmpty(backingRowMap())) { backingMap.remove(rowKey); backingRowMap = null; } } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { Map backingRowMap = backingRowMap(); return (key != null && backingRowMap != null) && Maps.safeContainsKey(backingRowMap, key); } @Override - public V get(Object key) { + public @Nullable V get(@Nullable Object key) { Map backingRowMap = backingRowMap(); return (key != null && backingRowMap != null) ? Maps.safeGet(backingRowMap, key) : null; } @Override - public V put(C key, V value) { + public @Nullable V put(C key, V value) { checkNotNull(key); checkNotNull(value); if (backingRowMap != null && !backingRowMap.isEmpty()) { @@ -331,7 +348,7 @@ public V put(C key, V value) { } @Override - public V remove(Object key) { + public @Nullable V remove(@Nullable Object key) { Map backingRowMap = backingRowMap(); if (backingRowMap == null) { return null; @@ -404,7 +421,7 @@ public V setValue(V value) { } @Override - public boolean equals(Object object) { + public boolean equals(@Nullable Object object) { // TODO(lowasser): identify why this affects GWT tests return standardEquals(object); } @@ -430,22 +447,22 @@ private class Column extends ViewCachingAbstractMap { } @Override - public V put(R key, V value) { + public @Nullable V put(R key, V value) { return StandardTable.this.put(key, columnKey, value); } @Override - public V get(Object key) { + public @Nullable V get(@Nullable Object key) { return StandardTable.this.get(key, columnKey); } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return StandardTable.this.contains(key, columnKey); } @Override - public V remove(Object key) { + public @Nullable V remove(@Nullable Object key) { return StandardTable.this.remove(key, columnKey); } @@ -503,18 +520,20 @@ public void clear() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { if (o instanceof Entry) { - Entry entry = (Entry) o; + Entry entry = + (Entry) o; return containsMapping(entry.getKey(), columnKey, entry.getValue()); } return false; } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { if (obj instanceof Entry) { - Entry entry = (Entry) obj; + Entry entry = + (Entry) obj; return removeMapping(entry.getKey(), columnKey, entry.getValue()); } return false; @@ -543,12 +562,19 @@ public R getKey() { @Override public V getValue() { - return entry.getValue().get(columnKey); + /* + * The cast is safe because of the containsKey check above. (Well, it's possible for + * the map to change between that call and this one. But if that happens, the + * behavior is undefined because of the concurrent mutation.) + */ + return uncheckedCastNullableVToV(entry.getValue().get(columnKey)); } @Override public V setValue(V value) { - return entry.getValue().put(columnKey, checkNotNull(value)); + // TODO(cpovirk): Maybe Map.Entry.getValue+setValue should return @Nullable V? + return uncheckedCastNullableVToV( + entry.getValue().put(columnKey, checkNotNull(value))); } } return new EntryImpl(); @@ -570,12 +596,12 @@ private class KeySet extends Maps.KeySet { } @Override - public boolean contains(Object obj) { + public boolean contains(@Nullable Object obj) { return StandardTable.this.contains(obj, columnKey); } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { return StandardTable.this.remove(obj, columnKey) != null; } @@ -597,7 +623,7 @@ private class Values extends Maps.Values { } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { return obj != null && removeFromColumnIf(Maps.valuePredicateOnEntries(equalTo(obj))); } @@ -647,7 +673,7 @@ public int size() { } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { if (obj == null) { return false; } @@ -702,7 +728,7 @@ public boolean retainAll(Collection c) { } @Override - public boolean contains(Object obj) { + public boolean contains(@Nullable Object obj) { return containsColumn(obj); } } @@ -763,19 +789,20 @@ Map> createRowMap() { @WeakOuter class RowMap extends ViewCachingAbstractMap> { @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return containsRow(key); } // performing cast only when key is in backing map and has the correct type @SuppressWarnings("unchecked") @Override - public Map get(Object key) { - return containsRow(key) ? row((R) key) : null; + public @Nullable Map get(@Nullable Object key) { + // requireNonNull is safe because of the containsRow check. + return containsRow(key) ? row((R) requireNonNull(key)) : null; } @Override - public Map remove(Object key) { + public @Nullable Map remove(@Nullable Object key) { return (key == null) ? null : backingMap.remove(key); } @@ -804,9 +831,10 @@ public int size() { } @Override - public boolean contains(Object obj) { + public boolean contains(@Nullable Object obj) { if (obj instanceof Entry) { - Entry entry = (Entry) obj; + Entry entry = + (Entry) obj; return entry.getKey() != null && entry.getValue() instanceof Map && Collections2.safeContains(backingMap.entrySet(), entry); @@ -815,9 +843,10 @@ public boolean contains(Object obj) { } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { if (obj instanceof Entry) { - Entry entry = (Entry) obj; + Entry entry = + (Entry) obj; return entry.getKey() != null && entry.getValue() instanceof Map && backingMap.entrySet().remove(entry); @@ -841,17 +870,18 @@ private class ColumnMap extends ViewCachingAbstractMap> { // has the correct type. @SuppressWarnings("unchecked") @Override - public Map get(Object key) { - return containsColumn(key) ? column((C) key) : null; + public @Nullable Map get(@Nullable Object key) { + // requireNonNull is safe because of the containsColumn check. + return containsColumn(key) ? column((C) requireNonNull(key)) : null; } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return containsColumn(key); } @Override - public Map remove(Object key) { + public @Nullable Map remove(@Nullable Object key) { return containsColumn(key) ? removeColumn(key) : null; } @@ -890,25 +920,25 @@ public int size() { } @Override - public boolean contains(Object obj) { + public boolean contains(@Nullable Object obj) { if (obj instanceof Entry) { - Entry entry = (Entry) obj; + Entry entry = + (Entry) obj; if (containsColumn(entry.getKey())) { - // The cast to C occurs only when the key is in the map, implying - // that it has the correct type. - @SuppressWarnings("unchecked") - C columnKey = (C) entry.getKey(); - return get(columnKey).equals(entry.getValue()); + // requireNonNull is safe because of the containsColumn check. + return requireNonNull(get(entry.getKey())).equals(entry.getValue()); } } return false; } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { if (contains(obj)) { - Entry entry = (Entry) obj; - removeColumn(entry.getKey()); + Entry entry = + (Entry) obj; + // requireNonNull is safe because of the contains check. + removeColumn(requireNonNull(entry).getKey()); return true; } return false; @@ -947,7 +977,7 @@ private class ColumnMapValues extends Maps.Values> { } @Override - public boolean remove(Object obj) { + public boolean remove(@Nullable Object obj) { for (Entry> entry : ColumnMap.this.entrySet()) { if (entry.getValue().equals(obj)) { removeColumn(entry.getKey()); @@ -985,5 +1015,20 @@ public boolean retainAll(Collection c) { } } + static boolean nonNullButEmpty(@Nullable Map map) { + return map != null && map.isEmpty(); + } + + @SuppressWarnings("nullness") + private static V uncheckedCastNullableVToV(@Nullable V value) { + /* + * We can't use requireNonNull because `value` might be null. Specifically, it can be null + * because the table might contain a null value to be returned to the user. This is in contrast + * to the other way for the result of table.get to be null, which is for the map not to have a + * value associated with the given keys. + */ + return value; + } + private static final long serialVersionUID = 0; } diff --git a/guava/src/com/google/common/collect/Streams.java b/guava/src/com/google/common/collect/Streams.java index 333fc2a58487..64445b80ba28 100644 --- a/guava/src/com/google/common/collect/Streams.java +++ b/guava/src/com/google/common/collect/Streams.java @@ -45,6 +45,7 @@ import java.util.stream.LongStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -89,7 +90,8 @@ public static Stream stream(Iterator iterator) { * otherwise returns an empty stream. */ @Beta - public static Stream stream(com.google.common.base.Optional optional) { + public static Stream stream( + com.google.common.base.Optional optional) { return optional.isPresent() ? Stream.of(optional.get()) : Stream.empty(); } @@ -100,7 +102,7 @@ public static Stream stream(com.google.common.base.Optional optional) *

    Java 9 users: use {@code optional.stream()} instead. */ @Beta - public static Stream stream(java.util.Optional optional) { + public static Stream stream(java.util.Optional optional) { return optional.isPresent() ? Stream.of(optional.get()) : Stream.empty(); } @@ -300,8 +302,9 @@ public static DoubleStream concat(DoubleStream... streams) { * This may harm parallel performance. */ @Beta - public static Stream zip( - Stream streamA, Stream streamB, BiFunction function) { + public static + Stream zip( + Stream streamA, Stream streamB, BiFunction function) { checkNotNull(streamA); checkNotNull(streamB); checkNotNull(function); @@ -446,7 +449,7 @@ class Splitr extends MapWithIndexSpliterator, R, Splitr> implemen } @Override - public void accept(@Nullable T t) { + public void accept(T t) { this.holder = t; } @@ -454,7 +457,8 @@ public void accept(@Nullable T t) { public boolean tryAdvance(Consumer action) { if (fromSpliterator.tryAdvance(this)) { try { - action.accept(function.apply(holder, index++)); + // The cast is safe because tryAdvance puts a T into `holder`. + action.accept(function.apply(uncheckedCastNullableTToT(holder), index++)); return true; } finally { holder = null; @@ -471,6 +475,17 @@ Splitr createSplit(Spliterator from, long i) { return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close); } + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T element) { + /* + * We can't use requireNonNull because `element` might be null. Specifically, it can be null + * because the spliterator might contain a null element to be returned to the user. This is in + * contrast to the other way for `element` to be null, which is for the spliterator not to have + * a next value computed yet. + */ + return element; + } + /** * Returns a stream consisting of the results of applying the given function to the elements of * {@code stream} and their indexes in the stream. For example, @@ -494,7 +509,8 @@ Splitr createSplit(Spliterator from, long i) { * was defined. */ @Beta - public static Stream mapWithIndex(IntStream stream, IntFunctionWithIndex function) { + public static Stream mapWithIndex( + IntStream stream, IntFunctionWithIndex function) { checkNotNull(stream); checkNotNull(function); boolean isParallel = stream.isParallel(); @@ -573,7 +589,8 @@ Splitr createSplit(Spliterator.OfInt from, long i) { * was defined. */ @Beta - public static Stream mapWithIndex(LongStream stream, LongFunctionWithIndex function) { + public static Stream mapWithIndex( + LongStream stream, LongFunctionWithIndex function) { checkNotNull(stream); checkNotNull(function); boolean isParallel = stream.isParallel(); @@ -724,7 +741,9 @@ public interface FunctionWithIndex { } private abstract static class MapWithIndexSpliterator< - F extends Spliterator, R, S extends MapWithIndexSpliterator> + F extends Spliterator, + R, + S extends MapWithIndexSpliterator> implements Spliterator { final F fromSpliterator; long index; @@ -737,9 +756,9 @@ private abstract static class MapWithIndexSpliterator< abstract S createSplit(F from, long i); @Override - public S trySplit() { + public @Nullable S trySplit() { @SuppressWarnings("unchecked") - F split = (F) fromSpliterator.trySplit(); + F split = (@Nullable F) fromSpliterator.trySplit(); if (split == null) { return null; } @@ -818,10 +837,10 @@ public interface DoubleFunctionWithIndex { * @throws NullPointerException if the last element of the stream is null */ @Beta - public static java.util.Optional findLast(Stream stream) { + public static java.util.Optional findLast(Stream stream) { class OptionalState { boolean set = false; - T value = null; + @Nullable T value = null; void set(@Nullable T value) { this.set = true; @@ -830,7 +849,8 @@ void set(@Nullable T value) { T get() { checkState(set); - return value; + // The cast is safe because of the checkState call. + return uncheckedCastNullableTToT(value); } } OptionalState state = new OptionalState(); diff --git a/guava/src/com/google/common/collect/Synchronized.java b/guava/src/com/google/common/collect/Synchronized.java index 0f175cc2360c..5f7560fdcbf7 100644 --- a/guava/src/com/google/common/collect/Synchronized.java +++ b/guava/src/com/google/common/collect/Synchronized.java @@ -70,6 +70,8 @@ static class SynchronizedObject implements Serializable { final Object delegate; final Object mutex; + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) SynchronizedObject(Object delegate, @Nullable Object mutex) { this.delegate = checkNotNull(delegate); this.mutex = (mutex == null) ? this : mutex; @@ -104,12 +106,14 @@ private void writeObject(ObjectOutputStream stream) throws IOException { private static final long serialVersionUID = 0; } - private static Collection collection(Collection collection, @Nullable Object mutex) { + private static Collection collection( + Collection collection, @Nullable Object mutex) { return new SynchronizedCollection(collection, mutex); } @VisibleForTesting - static class SynchronizedCollection extends SynchronizedObject implements Collection { + static class SynchronizedCollection extends SynchronizedObject + implements Collection { private SynchronizedCollection(Collection delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -142,7 +146,7 @@ public void clear() { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { synchronized (mutex) { return delegate().contains(o); } @@ -196,7 +200,7 @@ public void forEach(Consumer action) { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { synchronized (mutex) { return delegate().remove(o); } @@ -231,6 +235,7 @@ public int size() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { synchronized (mutex) { return delegate().toArray(); @@ -238,6 +243,7 @@ public Object[] toArray() { } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] a) { synchronized (mutex) { return delegate().toArray(a); @@ -252,7 +258,8 @@ static Set set(Set set, @Nullable Object mutex) { return new SynchronizedSet(set, mutex); } - static class SynchronizedSet extends SynchronizedCollection implements Set { + static class SynchronizedSet extends SynchronizedCollection + implements Set { SynchronizedSet(Set delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -264,7 +271,7 @@ Set delegate() { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == this) { return true; } @@ -283,11 +290,13 @@ public int hashCode() { private static final long serialVersionUID = 0; } - private static SortedSet sortedSet(SortedSet set, @Nullable Object mutex) { + private static SortedSet sortedSet( + SortedSet set, @Nullable Object mutex) { return new SynchronizedSortedSet(set, mutex); } - static class SynchronizedSortedSet extends SynchronizedSet implements SortedSet { + static class SynchronizedSortedSet extends SynchronizedSet + implements SortedSet { SynchronizedSortedSet(SortedSet delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -298,7 +307,7 @@ SortedSet delegate() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { synchronized (mutex) { return delegate().comparator(); } @@ -348,7 +357,8 @@ private static List list(List list, @Nullable Object mutex) { : new SynchronizedList(list, mutex); } - private static class SynchronizedList extends SynchronizedCollection implements List { + private static class SynchronizedList + extends SynchronizedCollection implements List { SynchronizedList(List delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -380,14 +390,14 @@ public E get(int index) { } @Override - public int indexOf(Object o) { + public int indexOf(@Nullable Object o) { synchronized (mutex) { return delegate().indexOf(o); } } @Override - public int lastIndexOf(Object o) { + public int lastIndexOf(@Nullable Object o) { synchronized (mutex) { return delegate().lastIndexOf(o); } @@ -439,7 +449,7 @@ public List subList(int fromIndex, int toIndex) { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == this) { return true; } @@ -458,8 +468,8 @@ public int hashCode() { private static final long serialVersionUID = 0; } - private static class SynchronizedRandomAccessList extends SynchronizedList - implements RandomAccess { + private static class SynchronizedRandomAccessList + extends SynchronizedList implements RandomAccess { SynchronizedRandomAccessList(List list, @Nullable Object mutex) { super(list, mutex); } @@ -467,15 +477,16 @@ private static class SynchronizedRandomAccessList extends SynchronizedList private static final long serialVersionUID = 0; } - static Multiset multiset(Multiset multiset, @Nullable Object mutex) { + static Multiset multiset( + Multiset multiset, @Nullable Object mutex) { if (multiset instanceof SynchronizedMultiset || multiset instanceof ImmutableMultiset) { return multiset; } return new SynchronizedMultiset(multiset, mutex); } - private static class SynchronizedMultiset extends SynchronizedCollection - implements Multiset { + private static class SynchronizedMultiset + extends SynchronizedCollection implements Multiset { transient @Nullable Set elementSet; transient @Nullable Set> entrySet; @@ -489,7 +500,7 @@ Multiset delegate() { } @Override - public int count(Object o) { + public int count(@Nullable Object o) { synchronized (mutex) { return delegate().count(o); } @@ -503,7 +514,7 @@ public int add(E e, int n) { } @Override - public int remove(Object o, int n) { + public int remove(@Nullable Object o, int n) { synchronized (mutex) { return delegate().remove(o, n); } @@ -544,7 +555,7 @@ public Set> entrySet() { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == this) { return true; } @@ -563,15 +574,16 @@ public int hashCode() { private static final long serialVersionUID = 0; } - static Multimap multimap(Multimap multimap, @Nullable Object mutex) { + static Multimap multimap( + Multimap multimap, @Nullable Object mutex) { if (multimap instanceof SynchronizedMultimap || multimap instanceof BaseImmutableMultimap) { return multimap; } return new SynchronizedMultimap<>(multimap, mutex); } - private static class SynchronizedMultimap extends SynchronizedObject - implements Multimap { + private static class SynchronizedMultimap + extends SynchronizedObject implements Multimap { transient @Nullable Set keySet; transient @Nullable Collection valuesCollection; transient @Nullable Collection> entries; @@ -603,21 +615,21 @@ public boolean isEmpty() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { synchronized (mutex) { return delegate().containsKey(key); } } @Override - public boolean containsValue(Object value) { + public boolean containsValue(@Nullable Object value) { synchronized (mutex) { return delegate().containsValue(value); } } @Override - public boolean containsEntry(Object key, Object value) { + public boolean containsEntry(@Nullable Object key, @Nullable Object value) { synchronized (mutex) { return delegate().containsEntry(key, value); } @@ -659,14 +671,14 @@ public Collection replaceValues(K key, Iterable values) { } @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { synchronized (mutex) { return delegate().remove(key, value); } } @Override - public Collection removeAll(Object key) { + public Collection removeAll(@Nullable Object key) { synchronized (mutex) { return delegate().removeAll(key); // copy not synchronized } @@ -737,7 +749,7 @@ public Multiset keys() { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == this) { return true; } @@ -764,8 +776,9 @@ static ListMultimap listMultimap( return new SynchronizedListMultimap<>(multimap, mutex); } - private static class SynchronizedListMultimap extends SynchronizedMultimap - implements ListMultimap { + private static class SynchronizedListMultimap< + K, V> + extends SynchronizedMultimap implements ListMultimap { SynchronizedListMultimap(ListMultimap delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -783,7 +796,7 @@ public List get(K key) { } @Override - public List removeAll(Object key) { + public List removeAll(@Nullable Object key) { synchronized (mutex) { return delegate().removeAll(key); // copy not synchronized } @@ -799,15 +812,17 @@ public List replaceValues(K key, Iterable values) { private static final long serialVersionUID = 0; } - static SetMultimap setMultimap(SetMultimap multimap, @Nullable Object mutex) { + static SetMultimap setMultimap( + SetMultimap multimap, @Nullable Object mutex) { if (multimap instanceof SynchronizedSetMultimap || multimap instanceof BaseImmutableMultimap) { return multimap; } return new SynchronizedSetMultimap<>(multimap, mutex); } - private static class SynchronizedSetMultimap extends SynchronizedMultimap - implements SetMultimap { + private static class SynchronizedSetMultimap< + K, V> + extends SynchronizedMultimap implements SetMultimap { transient @Nullable Set> entrySet; SynchronizedSetMultimap(SetMultimap delegate, @Nullable Object mutex) { @@ -827,7 +842,7 @@ public Set get(K key) { } @Override - public Set removeAll(Object key) { + public Set removeAll(@Nullable Object key) { synchronized (mutex) { return delegate().removeAll(key); // copy not synchronized } @@ -853,16 +868,18 @@ public Set> entries() { private static final long serialVersionUID = 0; } - static SortedSetMultimap sortedSetMultimap( - SortedSetMultimap multimap, @Nullable Object mutex) { + static + SortedSetMultimap sortedSetMultimap( + SortedSetMultimap multimap, @Nullable Object mutex) { if (multimap instanceof SynchronizedSortedSetMultimap) { return multimap; } return new SynchronizedSortedSetMultimap<>(multimap, mutex); } - private static class SynchronizedSortedSetMultimap extends SynchronizedSetMultimap - implements SortedSetMultimap { + private static class SynchronizedSortedSetMultimap< + K, V> + extends SynchronizedSetMultimap implements SortedSetMultimap { SynchronizedSortedSetMultimap(SortedSetMultimap delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -880,7 +897,7 @@ public SortedSet get(K key) { } @Override - public SortedSet removeAll(Object key) { + public SortedSet removeAll(@Nullable Object key) { synchronized (mutex) { return delegate().removeAll(key); // copy not synchronized } @@ -894,7 +911,7 @@ public SortedSet replaceValues(K key, Iterable values) { } @Override - public Comparator valueComparator() { + public @Nullable Comparator valueComparator() { synchronized (mutex) { return delegate().valueComparator(); } @@ -917,7 +934,8 @@ private static Collection typePreservingCollection( return collection(collection, mutex); } - private static Set typePreservingSet(Set set, @Nullable Object mutex) { + private static Set typePreservingSet( + Set set, @Nullable Object mutex) { if (set instanceof SortedSet) { return sortedSet((SortedSet) set, mutex); } else { @@ -925,7 +943,8 @@ private static Set typePreservingSet(Set set, @Nullable Object mutex) } } - private static class SynchronizedAsMapEntries + private static class SynchronizedAsMapEntries< + K, V> extends SynchronizedSet>> { SynchronizedAsMapEntries(Set>> delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -956,6 +975,7 @@ public Collection getValue() { // See Collections.CheckedMap.CheckedEntrySet for details on attacks. @Override +@SuppressWarnings("nullness") public Object[] toArray() { synchronized (mutex) { return ObjectArrays.toArrayImpl(delegate()); @@ -963,6 +983,7 @@ public Object[] toArray() { } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { synchronized (mutex) { return ObjectArrays.toArrayImpl(delegate(), array); @@ -970,7 +991,7 @@ public T[] toArray(T[] array) { } @Override - public boolean contains(Object o) { + public boolean contains(@Nullable Object o) { synchronized (mutex) { return Maps.containsEntryImpl(delegate(), o); } @@ -984,7 +1005,7 @@ public boolean containsAll(Collection c) { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == this) { return true; } @@ -994,7 +1015,7 @@ public boolean equals(Object o) { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { synchronized (mutex) { return Maps.removeEntryImpl(delegate(), o); } @@ -1018,11 +1039,13 @@ public boolean retainAll(Collection c) { } @VisibleForTesting - static Map map(Map map, @Nullable Object mutex) { + static Map map( + Map map, @Nullable Object mutex) { return new SynchronizedMap<>(map, mutex); } - private static class SynchronizedMap extends SynchronizedObject implements Map { + private static class SynchronizedMap + extends SynchronizedObject implements Map { transient @Nullable Set keySet; transient @Nullable Collection values; transient @Nullable Set> entrySet; @@ -1045,14 +1068,14 @@ public void clear() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { synchronized (mutex) { return delegate().containsKey(key); } } @Override - public boolean containsValue(Object value) { + public boolean containsValue(@Nullable Object value) { synchronized (mutex) { return delegate().containsValue(value); } @@ -1076,14 +1099,14 @@ public void forEach(BiConsumer action) { } @Override - public V get(Object key) { + public @Nullable V get(@Nullable Object key) { synchronized (mutex) { return delegate().get(key); } } @Override - public V getOrDefault(Object key, V defaultValue) { + public V getOrDefault(@Nullable Object key, V defaultValue) { synchronized (mutex) { return delegate().getOrDefault(key, defaultValue); } @@ -1107,14 +1130,14 @@ public Set keySet() { } @Override - public V put(K key, V value) { + public @Nullable V put(K key, V value) { synchronized (mutex) { return delegate().put(key, value); } } @Override - public V putIfAbsent(K key, V value) { + public @Nullable V putIfAbsent(K key, V value) { synchronized (mutex) { return delegate().putIfAbsent(key, value); } @@ -1128,14 +1151,14 @@ public boolean replace(K key, V oldValue, V newValue) { } @Override - public V replace(K key, V value) { + public @Nullable V replace(K key, V value) { synchronized (mutex) { return delegate().replace(key, value); } } @Override - public V computeIfAbsent(K key, Function mappingFunction) { + public V computeIfAbsent(K key, Function mappingFunction) { synchronized (mutex) { return delegate().computeIfAbsent(key, mappingFunction); } @@ -1143,14 +1166,15 @@ public V computeIfAbsent(K key, Function mappingFunction @Override public V computeIfPresent( - K key, BiFunction remappingFunction) { + K key, BiFunction remappingFunction) { synchronized (mutex) { return delegate().computeIfPresent(key, remappingFunction); } } @Override - public V compute(K key, BiFunction remappingFunction) { + public V compute( + K key, BiFunction remappingFunction) { synchronized (mutex) { return delegate().compute(key, remappingFunction); } @@ -1158,7 +1182,7 @@ public V compute(K key, BiFunction remappingF @Override public V merge( - K key, V value, BiFunction remappingFunction) { + K key, V value, BiFunction remappingFunction) { synchronized (mutex) { return delegate().merge(key, value, remappingFunction); } @@ -1179,14 +1203,14 @@ public void replaceAll(BiFunction function) { } @Override - public V remove(Object key) { + public @Nullable V remove(@Nullable Object key) { synchronized (mutex) { return delegate().remove(key); } } @Override - public boolean remove(Object key, Object value) { + public boolean remove(@Nullable Object key, @Nullable Object value) { synchronized (mutex) { return delegate().remove(key, value); } @@ -1210,7 +1234,7 @@ public Collection values() { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == this) { return true; } @@ -1229,12 +1253,13 @@ public int hashCode() { private static final long serialVersionUID = 0; } - static SortedMap sortedMap(SortedMap sortedMap, @Nullable Object mutex) { + static SortedMap sortedMap( + SortedMap sortedMap, @Nullable Object mutex) { return new SynchronizedSortedMap<>(sortedMap, mutex); } - static class SynchronizedSortedMap extends SynchronizedMap - implements SortedMap { + static class SynchronizedSortedMap + extends SynchronizedMap implements SortedMap { SynchronizedSortedMap(SortedMap delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -1246,7 +1271,7 @@ SortedMap delegate() { } @Override - public Comparator comparator() { + public @Nullable Comparator comparator() { synchronized (mutex) { return delegate().comparator(); } @@ -1290,7 +1315,8 @@ public SortedMap tailMap(K fromKey) { private static final long serialVersionUID = 0; } - static BiMap biMap(BiMap bimap, @Nullable Object mutex) { + static BiMap biMap( + BiMap bimap, @Nullable Object mutex) { if (bimap instanceof SynchronizedBiMap || bimap instanceof ImmutableBiMap) { return bimap; } @@ -1298,8 +1324,8 @@ static BiMap biMap(BiMap bimap, @Nullable Object mutex) { } @VisibleForTesting - static class SynchronizedBiMap extends SynchronizedMap - implements BiMap, Serializable { + static class SynchronizedBiMap + extends SynchronizedMap implements BiMap, Serializable { private transient @Nullable Set valueSet; @RetainedWith private transient @Nullable BiMap inverse; @@ -1325,7 +1351,7 @@ public Set values() { } @Override - public V forcePut(K key, V value) { + public @Nullable V forcePut(K key, V value) { synchronized (mutex) { return delegate().forcePut(key, value); } @@ -1344,7 +1370,8 @@ public BiMap inverse() { private static final long serialVersionUID = 0; } - private static class SynchronizedAsMap extends SynchronizedMap> { + private static class SynchronizedAsMap + extends SynchronizedMap> { transient @Nullable Set>> asMapEntrySet; transient @Nullable Collection> asMapValues; @@ -1353,7 +1380,7 @@ private static class SynchronizedAsMap extends SynchronizedMap get(Object key) { + public @Nullable Collection get(@Nullable Object key) { synchronized (mutex) { Collection collection = super.get(key); return (collection == null) ? null : typePreservingCollection(collection, mutex); @@ -1381,7 +1408,7 @@ public Collection> values() { } @Override - public boolean containsValue(Object o) { + public boolean containsValue(@Nullable Object o) { // values() and its contains() method are both synchronized. return values().contains(o); } @@ -1389,7 +1416,8 @@ public boolean containsValue(Object o) { private static final long serialVersionUID = 0; } - private static class SynchronizedAsMapValues extends SynchronizedCollection> { + private static class SynchronizedAsMapValues + extends SynchronizedCollection> { SynchronizedAsMapValues(Collection> delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -1422,7 +1450,7 @@ NavigableSet delegate() { } @Override - public E ceiling(E e) { + public @Nullable E ceiling(E e) { synchronized (mutex) { return delegate().ceiling(e); } @@ -1448,7 +1476,7 @@ public NavigableSet descendingSet() { } @Override - public E floor(E e) { + public @Nullable E floor(E e) { synchronized (mutex) { return delegate().floor(e); } @@ -1467,28 +1495,28 @@ public SortedSet headSet(E toElement) { } @Override - public E higher(E e) { + public @Nullable E higher(E e) { synchronized (mutex) { return delegate().higher(e); } } @Override - public E lower(E e) { + public @Nullable E lower(E e) { synchronized (mutex) { return delegate().lower(e); } } @Override - public E pollFirst() { + public @Nullable E pollFirst() { synchronized (mutex) { return delegate().pollFirst(); } } @Override - public E pollLast() { + public @Nullable E pollLast() { synchronized (mutex) { return delegate().pollLast(); } @@ -1524,7 +1552,8 @@ public SortedSet tailSet(E fromElement) { } @GwtIncompatible // NavigableSet - static NavigableSet navigableSet(NavigableSet navigableSet, @Nullable Object mutex) { + static NavigableSet navigableSet( + NavigableSet navigableSet, @Nullable Object mutex) { return new SynchronizedNavigableSet(navigableSet, mutex); } @@ -1534,7 +1563,8 @@ static NavigableSet navigableSet(NavigableSet navigableSet) { } @GwtIncompatible // NavigableMap - static NavigableMap navigableMap(NavigableMap navigableMap) { + static NavigableMap navigableMap( + NavigableMap navigableMap) { return navigableMap(navigableMap, null); } @@ -1546,8 +1576,8 @@ static NavigableMap navigableMap( @GwtIncompatible // NavigableMap @VisibleForTesting - static class SynchronizedNavigableMap extends SynchronizedSortedMap - implements NavigableMap { + static class SynchronizedNavigableMap + extends SynchronizedSortedMap implements NavigableMap { SynchronizedNavigableMap(NavigableMap delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -1559,14 +1589,14 @@ NavigableMap delegate() { } @Override - public Entry ceilingEntry(K key) { + public @Nullable Entry ceilingEntry(K key) { synchronized (mutex) { return nullableSynchronizedEntry(delegate().ceilingEntry(key), mutex); } } @Override - public K ceilingKey(K key) { + public @Nullable K ceilingKey(K key) { synchronized (mutex) { return delegate().ceilingKey(key); } @@ -1597,21 +1627,21 @@ public NavigableMap descendingMap() { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { synchronized (mutex) { return nullableSynchronizedEntry(delegate().firstEntry(), mutex); } } @Override - public Entry floorEntry(K key) { + public @Nullable Entry floorEntry(K key) { synchronized (mutex) { return nullableSynchronizedEntry(delegate().floorEntry(key), mutex); } } @Override - public K floorKey(K key) { + public @Nullable K floorKey(K key) { synchronized (mutex) { return delegate().floorKey(key); } @@ -1630,35 +1660,35 @@ public SortedMap headMap(K toKey) { } @Override - public Entry higherEntry(K key) { + public @Nullable Entry higherEntry(K key) { synchronized (mutex) { return nullableSynchronizedEntry(delegate().higherEntry(key), mutex); } } @Override - public K higherKey(K key) { + public @Nullable K higherKey(K key) { synchronized (mutex) { return delegate().higherKey(key); } } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { synchronized (mutex) { return nullableSynchronizedEntry(delegate().lastEntry(), mutex); } } @Override - public Entry lowerEntry(K key) { + public @Nullable Entry lowerEntry(K key) { synchronized (mutex) { return nullableSynchronizedEntry(delegate().lowerEntry(key), mutex); } } @Override - public K lowerKey(K key) { + public @Nullable K lowerKey(K key) { synchronized (mutex) { return delegate().lowerKey(key); } @@ -1682,14 +1712,14 @@ public NavigableSet navigableKeySet() { } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { synchronized (mutex) { return nullableSynchronizedEntry(delegate().pollFirstEntry(), mutex); } } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { synchronized (mutex) { return nullableSynchronizedEntry(delegate().pollLastEntry(), mutex); } @@ -1724,8 +1754,8 @@ public SortedMap tailMap(K fromKey) { } @GwtIncompatible // works but is needed only for NavigableMap - private static Entry nullableSynchronizedEntry( - @Nullable Entry entry, @Nullable Object mutex) { + private static @Nullable + Entry nullableSynchronizedEntry(@Nullable Entry entry, @Nullable Object mutex) { if (entry == null) { return null; } @@ -1733,7 +1763,8 @@ private static Entry nullableSynchronizedEntry( } @GwtIncompatible // works but is needed only for NavigableMap - private static class SynchronizedEntry extends SynchronizedObject implements Entry { + private static class SynchronizedEntry + extends SynchronizedObject implements Entry { SynchronizedEntry(Entry delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -1746,7 +1777,7 @@ Entry delegate() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { synchronized (mutex) { return delegate().equals(obj); } @@ -1787,7 +1818,8 @@ static Queue queue(Queue queue, @Nullable Object mutex) { return (queue instanceof SynchronizedQueue) ? queue : new SynchronizedQueue(queue, mutex); } - private static class SynchronizedQueue extends SynchronizedCollection implements Queue { + private static class SynchronizedQueue + extends SynchronizedCollection implements Queue { SynchronizedQueue(Queue delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -1813,14 +1845,14 @@ public boolean offer(E e) { } @Override - public E peek() { + public @Nullable E peek() { synchronized (mutex) { return delegate().peek(); } } @Override - public E poll() { + public @Nullable E poll() { synchronized (mutex) { return delegate().poll(); } @@ -1840,7 +1872,8 @@ static Deque deque(Deque deque, @Nullable Object mutex) { return new SynchronizedDeque(deque, mutex); } - private static final class SynchronizedDeque extends SynchronizedQueue implements Deque { + private static final class SynchronizedDeque + extends SynchronizedQueue implements Deque { SynchronizedDeque(Deque delegate, @Nullable Object mutex) { super(delegate, mutex); @@ -1894,14 +1927,14 @@ public E removeLast() { } @Override - public E pollFirst() { + public @Nullable E pollFirst() { synchronized (mutex) { return delegate().pollFirst(); } } @Override - public E pollLast() { + public @Nullable E pollLast() { synchronized (mutex) { return delegate().pollLast(); } @@ -1922,28 +1955,28 @@ public E getLast() { } @Override - public E peekFirst() { + public @Nullable E peekFirst() { synchronized (mutex) { return delegate().peekFirst(); } } @Override - public E peekLast() { + public @Nullable E peekLast() { synchronized (mutex) { return delegate().peekLast(); } } @Override - public boolean removeFirstOccurrence(Object o) { + public boolean removeFirstOccurrence(@Nullable Object o) { synchronized (mutex) { return delegate().removeFirstOccurrence(o); } } @Override - public boolean removeLastOccurrence(Object o) { + public boolean removeLastOccurrence(@Nullable Object o) { synchronized (mutex) { return delegate().removeLastOccurrence(o); } @@ -1973,14 +2006,16 @@ public Iterator descendingIterator() { private static final long serialVersionUID = 0; } - static Table table(Table table, Object mutex) { + static + Table table(Table table, @Nullable Object mutex) { return new SynchronizedTable<>(table, mutex); } - private static final class SynchronizedTable extends SynchronizedObject - implements Table { + private static final class SynchronizedTable< + R, C, V> + extends SynchronizedObject implements Table { - SynchronizedTable(Table delegate, Object mutex) { + SynchronizedTable(Table delegate, @Nullable Object mutex) { super(delegate, mutex); } @@ -2019,7 +2054,7 @@ public boolean containsValue(@Nullable Object value) { } @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { synchronized (mutex) { return delegate().get(rowKey, columnKey); } @@ -2047,7 +2082,7 @@ public void clear() { } @Override - public V put(@Nullable R rowKey, @Nullable C columnKey, @Nullable V value) { + public @Nullable V put(R rowKey, C columnKey, V value) { synchronized (mutex) { return delegate().put(rowKey, columnKey, value); } @@ -2061,21 +2096,21 @@ public void putAll(Table table) { } @Override - public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { synchronized (mutex) { return delegate().remove(rowKey, columnKey); } } @Override - public Map row(@Nullable R rowKey) { + public Map row(R rowKey) { synchronized (mutex) { return map(delegate().row(rowKey), mutex); } } @Override - public Map column(@Nullable C columnKey) { + public Map column(C columnKey) { synchronized (mutex) { return map(delegate().column(columnKey), mutex); } diff --git a/guava/src/com/google/common/collect/Table.java b/guava/src/com/google/common/collect/Table.java index 136ec1742521..57c065bfaed3 100644 --- a/guava/src/com/google/common/collect/Table.java +++ b/guava/src/com/google/common/collect/Table.java @@ -20,7 +20,6 @@ import com.google.common.base.Objects; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CompatibleWith; -import com.google.errorprone.annotations.DoNotMock; import java.util.Collection; import java.util.Map; import java.util.Set; @@ -53,9 +52,9 @@ * @param the type of the mapped values * @since 7.0 */ -@DoNotMock("Use ImmutableTable, HashBasedTable, or another implementation") @GwtCompatible -public interface Table { +public interface Table< + R, C, V> { // TODO(jlevy): Consider adding methods similar to ConcurrentMap methods. // Accessors @@ -253,17 +252,15 @@ V remove( * * @since 7.0 */ - interface Cell { + interface Cell< + R, C, V> { /** Returns the row key of this cell. */ - @Nullable R getRowKey(); /** Returns the column key of this cell. */ - @Nullable C getColumnKey(); /** Returns the value of this cell. */ - @Nullable V getValue(); /** diff --git a/guava/src/com/google/common/collect/Tables.java b/guava/src/com/google/common/collect/Tables.java index fc913ec79745..ba6501d4af72 100644 --- a/guava/src/com/google/common/collect/Tables.java +++ b/guava/src/com/google/common/collect/Tables.java @@ -18,6 +18,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.Beta; import com.google.common.annotations.GwtCompatible; @@ -36,6 +37,7 @@ import java.util.Spliterator; import java.util.function.BinaryOperator; import java.util.stream.Collector; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -63,11 +65,17 @@ private Tables() {} * @since 21.0 */ @Beta - public static > Collector toTable( - java.util.function.Function rowFunction, - java.util.function.Function columnFunction, - java.util.function.Function valueFunction, - java.util.function.Supplier tableSupplier) { + public static < + T, + R, + C, + V, + I extends Table> + Collector toTable( + java.util.function.Function rowFunction, + java.util.function.Function columnFunction, + java.util.function.Function valueFunction, + java.util.function.Supplier tableSupplier) { return toTable( rowFunction, columnFunction, @@ -92,12 +100,18 @@ private Tables() {} * * @since 21.0 */ - public static > Collector toTable( - java.util.function.Function rowFunction, - java.util.function.Function columnFunction, - java.util.function.Function valueFunction, - BinaryOperator mergeFunction, - java.util.function.Supplier tableSupplier) { + public static < + T, + R, + C, + V, + I extends Table> + Collector toTable( + java.util.function.Function rowFunction, + java.util.function.Function columnFunction, + java.util.function.Function valueFunction, + BinaryOperator mergeFunction, + java.util.function.Supplier tableSupplier) { checkNotNull(rowFunction); checkNotNull(columnFunction); checkNotNull(valueFunction); @@ -120,9 +134,23 @@ private Tables() {} }); } - private static void merge( - Table table, R row, C column, V value, BinaryOperator mergeFunction) { - checkNotNull(value); + private static < + R, C, V> + void merge(Table table, R row, C column, V value, BinaryOperator mergeFunction) { + /* + * This check can fail: As the docs of the 5-arg toTable method say, the method will throw if + * valueFunction returns null. + * + * We can't just change to extend @NonNull Object because that would forbid mergeFunction + * from returning null. And if we tried to compensate by changing mergeFunction to return a + * @Nullable V output, then it would have to accept @Nullable V inputs, too, even though it + * would never be called with them. The right way to compensate would be to change it to + * BiFunction, like Map.merge has. But it's too + * late, as we have removed @Beta. + * + * Fortunately, it's unlikely that users will need null values at all. + */ + requireNonNull(value); V oldValue = table.get(row, column); if (oldValue == null) { table.put(row, column, value); @@ -145,17 +173,19 @@ private static void merge( * @param columnKey the column key to be associated with the returned cell * @param value the value to be associated with the returned cell */ - public static Cell immutableCell( - @Nullable R rowKey, @Nullable C columnKey, @Nullable V value) { + public static + Cell immutableCell(R rowKey, C columnKey, V value) { return new ImmutableCell<>(rowKey, columnKey, value); } - static final class ImmutableCell extends AbstractCell implements Serializable { - private final @Nullable R rowKey; - private final @Nullable C columnKey; - private final @Nullable V value; + static final class ImmutableCell< + R, C, V> + extends AbstractCell implements Serializable { + private final R rowKey; + private final C columnKey; + private final V value; - ImmutableCell(@Nullable R rowKey, @Nullable C columnKey, @Nullable V value) { + ImmutableCell(R rowKey, C columnKey, V value) { this.rowKey = rowKey; this.columnKey = columnKey; this.value = value; @@ -179,17 +209,25 @@ public V getValue() { private static final long serialVersionUID = 0; } - abstract static class AbstractCell implements Cell { + abstract static class AbstractCell< + R, C, V> + implements Cell { // needed for serialization AbstractCell() {} @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj == this) { return true; } if (obj instanceof Cell) { - Cell other = (Cell) obj; + Cell + other = + (Cell< + ?, + ?, + ?>) + obj; return Objects.equal(getRowKey(), other.getRowKey()) && Objects.equal(getColumnKey(), other.getColumnKey()) && Objects.equal(getValue(), other.getValue()); @@ -220,13 +258,16 @@ public String toString() { * columnKeySet().iterator()} doesn't. With a transposed {@link HashBasedTable}, it's the other * way around. */ - public static Table transpose(Table table) { + public static + Table transpose(Table table) { return (table instanceof TransposeTable) ? ((TransposeTable) table).original : new TransposeTable(table); } - private static class TransposeTable extends AbstractTable { + private static class TransposeTable< + C, R, V> + extends AbstractTable { final Table original; TransposeTable(Table original) { @@ -274,12 +315,12 @@ public boolean containsValue(@Nullable Object value) { } @Override - public V get(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V get(@Nullable Object rowKey, @Nullable Object columnKey) { return original.get(columnKey, rowKey); } @Override - public V put(C rowKey, R columnKey, V value) { + public @Nullable V put(C rowKey, R columnKey, V value) { return original.put(columnKey, rowKey, value); } @@ -289,7 +330,7 @@ public void putAll(Table table) { } @Override - public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { return original.remove(columnKey, rowKey); } @@ -379,8 +420,9 @@ Spliterator> cellSpliterator() { * @since 10.0 */ @Beta - public static Table newCustomTable( - Map> backingMap, Supplier> factory) { + public static + Table newCustomTable( + Map> backingMap, Supplier> factory) { checkArgument(backingMap.isEmpty()); checkNotNull(factory); // TODO(jlevy): Wrap factory to validate that the supplied maps are empty? @@ -409,12 +451,22 @@ public static Table newCustomTable( * @since 10.0 */ @Beta - public static Table transformValues( - Table fromTable, Function function) { + public static < + R, + C, + V1, + V2> + Table transformValues( + Table fromTable, Function function) { return new TransformedTable<>(fromTable, function); } - private static class TransformedTable extends AbstractTable { + private static class TransformedTable< + R, + C, + V1, + V2> + extends AbstractTable { final Table fromTable; final Function function; @@ -424,15 +476,29 @@ private static class TransformedTable extends AbstractTable V uncheckedCastNullableVToV(@Nullable V value) { + /* + * We can't use requireNonNull because `value` might be null. Specifically, it can be null + * because the table might contain a null value to be returned to the user. This is in + * contrast to the other way for the result of table.get to be null, which is for the map not + * to have a value associated with the given keys. + */ + return value; } @Override @@ -446,7 +512,7 @@ public void clear() { } @Override - public V2 put(R rowKey, C columnKey, V2 value) { + public @Nullable V2 put(R rowKey, C columnKey, V2 value) { throw new UnsupportedOperationException(); } @@ -456,9 +522,9 @@ public void putAll(Table table) { } @Override - public V2 remove(Object rowKey, Object columnKey) { + public @Nullable V2 remove(@Nullable Object rowKey, @Nullable Object columnKey) { return contains(rowKey, columnKey) - ? function.apply(fromTable.remove(rowKey, columnKey)) + ? function.apply(requireNonNull(fromTable.remove(rowKey, columnKey))) : null; } @@ -544,13 +610,14 @@ public Map apply(Map column) { * * @since 11.0 */ - public static Table unmodifiableTable( - Table table) { + public static + Table unmodifiableTable(Table table) { return new UnmodifiableTable<>(table); } - private static class UnmodifiableTable extends ForwardingTable - implements Serializable { + private static class UnmodifiableTable< + R, C, V> + extends ForwardingTable implements Serializable { final Table delegate; UnmodifiableTable(Table delegate) { @@ -574,7 +641,7 @@ public void clear() { } @Override - public Map column(@Nullable C columnKey) { + public Map column(C columnKey) { return Collections.unmodifiableMap(super.column(columnKey)); } @@ -590,7 +657,7 @@ public Map> columnMap() { } @Override - public V put(@Nullable R rowKey, @Nullable C columnKey, @Nullable V value) { + public @Nullable V put(R rowKey, C columnKey, V value) { throw new UnsupportedOperationException(); } @@ -600,12 +667,12 @@ public void putAll(Table table) { } @Override - public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { + public @Nullable V remove(@Nullable Object rowKey, @Nullable Object columnKey) { throw new UnsupportedOperationException(); } @Override - public Map row(@Nullable R rowKey) { + public Map row(R rowKey) { return Collections.unmodifiableMap(super.row(rowKey)); } @@ -641,8 +708,9 @@ public Collection values() { * @since 11.0 */ @Beta - public static RowSortedTable unmodifiableRowSortedTable( - RowSortedTable table) { + public static + RowSortedTable unmodifiableRowSortedTable( + RowSortedTable table) { /* * It's not ? extends R, because it's technically not covariant in R. Specifically, * table.rowMap().comparator() could return a comparator that only works for the ? extends R. @@ -651,8 +719,9 @@ public static RowSortedTable unmodifiableRowSortedTable( return new UnmodifiableRowSortedMap<>(table); } - static final class UnmodifiableRowSortedMap extends UnmodifiableTable - implements RowSortedTable { + static final class UnmodifiableRowSortedMap< + R, C, V> + extends UnmodifiableTable implements RowSortedTable { public UnmodifiableRowSortedMap(RowSortedTable delegate) { super(delegate); @@ -678,7 +747,8 @@ public SortedSet rowKeySet() { } @SuppressWarnings("unchecked") - private static Function, Map> unmodifiableWrapper() { + private static + Function, Map> unmodifiableWrapper() { return (Function) UNMODIFIABLE_WRAPPER; } @@ -719,15 +789,25 @@ public Map apply(Map input) { * @return a synchronized view of the specified table * @since 22.0 */ - public static Table synchronizedTable(Table table) { + public static + Table synchronizedTable(Table table) { return Synchronized.table(table, null); } - static boolean equalsImpl(Table table, @Nullable Object obj) { + static boolean equalsImpl( + Table + table, + @Nullable Object obj) { if (obj == table) { return true; } else if (obj instanceof Table) { - Table that = (Table) obj; + Table + that = + (Table< + ?, + ?, + ?>) + obj; return table.cellSet().equals(that.cellSet()); } else { return false; diff --git a/guava/src/com/google/common/collect/TopKSelector.java b/guava/src/com/google/common/collect/TopKSelector.java index 09f38aa7e4b6..73af73aae44f 100644 --- a/guava/src/com/google/common/collect/TopKSelector.java +++ b/guava/src/com/google/common/collect/TopKSelector.java @@ -18,6 +18,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.GwtCompatible; import com.google.common.math.IntMath; @@ -51,7 +52,8 @@ * * @author Louis Wasserman */ -@GwtCompatible final class TopKSelector { +@GwtCompatible +final class TopKSelector { /** * Returns a {@code TopKSelector} that collects the lowest {@code k} elements added to it, @@ -70,7 +72,8 @@ public static > TopKSelector least(int k) { * * @throws IllegalArgumentException if {@code k < 0} or {@code k > Integer.MAX_VALUE / 2} */ - public static TopKSelector least(int k, Comparator comparator) { + public static TopKSelector least( + int k, Comparator comparator) { return new TopKSelector(comparator, k); } @@ -91,7 +94,8 @@ public static > TopKSelector greatest(int k) * * @throws IllegalArgumentException if {@code k < 0} or {@code k > Integer.MAX_VALUE / 2} */ - public static TopKSelector greatest(int k, Comparator comparator) { + public static TopKSelector greatest( + int k, Comparator comparator) { return new TopKSelector(Ordering.from(comparator).reverse(), k); } @@ -126,7 +130,7 @@ private TopKSelector(Comparator comparator, int k) { * Adds {@code elem} as a candidate for the top {@code k} elements. This operation takes amortized * O(1) time. */ - public void offer(@Nullable T elem) { + public void offer(T elem) { if (k == 0) { return; } else if (bufferSize == 0) { @@ -135,10 +139,12 @@ public void offer(@Nullable T elem) { bufferSize = 1; } else if (bufferSize < k) { buffer[bufferSize++] = elem; - if (comparator.compare(elem, threshold) > 0) { + // requireNonNull is safe because bufferSize > 0. + if (comparator.compare(elem, requireNonNull(threshold)) > 0) { threshold = elem; } - } else if (comparator.compare(elem, threshold) < 0) { + // requireNonNull is safe because bufferSize > 0. + } else if (comparator.compare(elem, requireNonNull(threshold)) < 0) { // Otherwise, we can ignore elem; we've seen k better elements. buffer[bufferSize++] = elem; if (bufferSize == 2 * k) { diff --git a/guava/src/com/google/common/collect/TransformedIterator.java b/guava/src/com/google/common/collect/TransformedIterator.java index b7214b8abd75..b98f5d82b0c8 100644 --- a/guava/src/com/google/common/collect/TransformedIterator.java +++ b/guava/src/com/google/common/collect/TransformedIterator.java @@ -20,6 +20,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An iterator that transforms a backing iterator; for internal use. This avoids the object overhead @@ -28,7 +29,8 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class TransformedIterator implements Iterator { +abstract class TransformedIterator + implements Iterator { final Iterator backingIterator; TransformedIterator(Iterator backingIterator) { diff --git a/guava/src/com/google/common/collect/TransformedListIterator.java b/guava/src/com/google/common/collect/TransformedListIterator.java index ac2eea1e1516..db69335b333a 100644 --- a/guava/src/com/google/common/collect/TransformedListIterator.java +++ b/guava/src/com/google/common/collect/TransformedListIterator.java @@ -19,6 +19,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.base.Function; import java.util.ListIterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An iterator that transforms a backing list iterator; for internal use. This avoids the object @@ -27,8 +28,8 @@ * @author Louis Wasserman */ @GwtCompatible -abstract class TransformedListIterator extends TransformedIterator - implements ListIterator { +abstract class TransformedListIterator + extends TransformedIterator implements ListIterator { TransformedListIterator(ListIterator backingIterator) { super(backingIterator); } diff --git a/guava/src/com/google/common/collect/TreeBasedTable.java b/guava/src/com/google/common/collect/TreeBasedTable.java index 510f75c66b53..c7012b7dec07 100644 --- a/guava/src/com/google/common/collect/TreeBasedTable.java +++ b/guava/src/com/google/common/collect/TreeBasedTable.java @@ -18,6 +18,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.GwtCompatible; import com.google.common.base.Function; @@ -31,6 +32,7 @@ import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -66,7 +68,9 @@ * @since 7.0 */ @GwtCompatible(serializable = true) -public class TreeBasedTable extends StandardRowSortedTable { +public class TreeBasedTable< + R extends @NonNull Object, C extends @NonNull Object, V extends @NonNull Object> + extends StandardRowSortedTable { private final Comparator columnComparator; private static class Factory implements Supplier>, Serializable { @@ -92,7 +96,8 @@ public TreeMap get() { * instead of {@code R extends Comparable}, and the same for {@code C}. That's * necessary to support classes defined without generics. */ - public static TreeBasedTable create() { + public static + TreeBasedTable create() { return new TreeBasedTable<>(Ordering.natural(), Ordering.natural()); } @@ -102,8 +107,9 @@ public static TreeBasedTable TreeBasedTable create( - Comparator rowComparator, Comparator columnComparator) { + public static + TreeBasedTable create( + Comparator rowComparator, Comparator columnComparator) { checkNotNull(rowComparator); checkNotNull(columnComparator); return new TreeBasedTable<>(rowComparator, columnComparator); @@ -113,7 +119,8 @@ public static TreeBasedTable create( * Creates a {@code TreeBasedTable} with the same mappings and sort order as the specified {@code * TreeBasedTable}. */ - public static TreeBasedTable create(TreeBasedTable table) { + public static + TreeBasedTable create(TreeBasedTable table) { TreeBasedTable result = new TreeBasedTable<>(table.rowComparator(), table.columnComparator()); result.putAll(table); @@ -135,7 +142,11 @@ public static TreeBasedTable create(TreeBasedTable rowComparator() { - return rowKeySet().comparator(); + /* + * requireNonNull is safe because the factories require non-null Comparators, which they pass on + * to the backing collections. + */ + return requireNonNull(rowKeySet().comparator()); } /** @@ -231,7 +242,7 @@ public C firstKey() { if (backing == null) { throw new NoSuchElementException(); } - return backingRowMap().firstKey(); + return backing.firstKey(); } @Override @@ -240,7 +251,7 @@ public C lastKey() { if (backing == null) { throw new NoSuchElementException(); } - return backingRowMap().lastKey(); + return backing.lastKey(); } transient @Nullable SortedMap wholeRow; @@ -249,6 +260,7 @@ public C lastKey() { * If the row was previously empty, we check if there's a new row here every * time we're queried. */ + @Nullable SortedMap wholeRow() { if (wholeRow == null || (wholeRow.isEmpty() && backingMap.containsKey(rowKey))) { wholeRow = (SortedMap) backingMap.get(rowKey); @@ -257,11 +269,13 @@ SortedMap wholeRow() { } @Override + @Nullable SortedMap backingRowMap() { return (SortedMap) super.backingRowMap(); } @Override + @Nullable SortedMap computeBackingRowMap() { SortedMap map = wholeRow(); if (map != null) { @@ -278,7 +292,7 @@ SortedMap computeBackingRowMap() { @Override void maintainEmptyInvariant() { - if (wholeRow() != null && wholeRow.isEmpty()) { + if (nonNullButEmpty(wholeRow())) { backingMap.remove(rowKey); wholeRow = null; backingRowMap = null; @@ -286,12 +300,12 @@ void maintainEmptyInvariant() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return rangeContains(key) && super.containsKey(key); } @Override - public V put(C key, V value) { + public @Nullable V put(C key, V value) { checkArgument(rangeContains(checkNotNull(key))); return super.put(key, value); } diff --git a/guava/src/com/google/common/collect/TreeMultimap.java b/guava/src/com/google/common/collect/TreeMultimap.java index 82c97af14fc5..d8d7622a0c1c 100644 --- a/guava/src/com/google/common/collect/TreeMultimap.java +++ b/guava/src/com/google/common/collect/TreeMultimap.java @@ -72,7 +72,8 @@ * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) -public class TreeMultimap extends AbstractSortedKeySortedSetMultimap { +public class TreeMultimap + extends AbstractSortedKeySortedSetMultimap { private transient Comparator keyComparator; private transient Comparator valueComparator; @@ -138,7 +139,7 @@ SortedSet createCollection() { } @Override - Collection createCollection(@Nullable K key) { + Collection createCollection(K key) { if (key == null) { keyComparator().compare(key, key); } @@ -163,7 +164,7 @@ public Comparator valueComparator() { /** @since 14.0 (present with return type {@code SortedSet} since 2.0) */ @Override @GwtIncompatible // NavigableSet - public NavigableSet get(@Nullable K key) { + public NavigableSet get(K key) { return (NavigableSet) super.get(key); } diff --git a/guava/src/com/google/common/collect/TreeMultiset.java b/guava/src/com/google/common/collect/TreeMultiset.java index da3a63cc034d..728c26dd202d 100644 --- a/guava/src/com/google/common/collect/TreeMultiset.java +++ b/guava/src/com/google/common/collect/TreeMultiset.java @@ -18,9 +18,9 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.CollectPreconditions.checkNonnegative; -import static com.google.common.collect.CollectPreconditions.checkRemove; +import static com.google.common.collect.CollectPreconditions.noCallsToNextSinceLastRemove; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -36,6 +36,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.function.ObjIntConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -57,7 +58,8 @@ * @since 2.0 */ @GwtCompatible(emulated = true) -public final class TreeMultiset extends AbstractSortedMultiset implements Serializable { +public final class TreeMultiset extends AbstractSortedMultiset + implements Serializable { /** * Creates a new, empty multiset, sorted according to the elements' natural order. All elements @@ -87,7 +89,8 @@ public static TreeMultiset create() { * indicates that the elements' natural ordering should be used. */ @SuppressWarnings("unchecked") - public static TreeMultiset create(@Nullable Comparator comparator) { + public static TreeMultiset create( + @Nullable Comparator comparator) { return (comparator == null) ? new TreeMultiset((Comparator) Ordering.natural()) : new TreeMultiset(comparator); @@ -122,7 +125,8 @@ public static TreeMultiset create(Iterable comparator) { super(comparator); this.range = GeneralRange.all(comparator); - this.header = new AvlNode(null, 1); + // This is safe as long as we're careful not to access `elem` on the header node. + this.header = new AvlNode(unsafeNull(), 1); successor(header, header); this.rootReference = new Reference<>(); } @@ -173,7 +177,8 @@ private long aggregateBelowRange(Aggregate aggr, @Nullable AvlNode node) { if (node == null) { return 0; } - int cmp = comparator().compare(range.getLowerEndpoint(), node.elem); + // requireNonNull is safe because we call this method only if hasLowerBound(). + int cmp = comparator().compare(requireNonNull(range.getLowerEndpoint()), node.elem); if (cmp < 0) { return aggregateBelowRange(aggr, node.left); } else if (cmp == 0) { @@ -196,7 +201,8 @@ private long aggregateAboveRange(Aggregate aggr, @Nullable AvlNode node) { if (node == null) { return 0; } - int cmp = comparator().compare(range.getUpperEndpoint(), node.elem); + // requireNonNull is safe because we call this method only if hasUpperBound(). + int cmp = comparator().compare(requireNonNull(range.getUpperEndpoint()), node.elem); if (cmp > 0) { return aggregateAboveRange(aggr, node.right); } else if (cmp == 0) { @@ -232,8 +238,8 @@ static int distinctElements(@Nullable AvlNode node) { @Override public int count(@Nullable Object element) { try { - @SuppressWarnings("unchecked") - E e = (E) element; + // Safe because we catch exceptions, and we're not writing, only reading. + E e = uncheckedCastNullableObjectToE(element); AvlNode root = rootReference.get(); if (!range.contains(e) || root == null) { return 0; @@ -244,9 +250,21 @@ public int count(@Nullable Object element) { } } + @SuppressWarnings({"unchecked", "nullness"}) + private static E uncheckedCastNullableObjectToE( + @Nullable Object value) { + /* + * We can't use requireNonNull because `value` might be null. Specifically, it can be null + * because the multiset might contain a null element to be returned to the user. This is in + * contrast to the other way for `value` to be null, which is for the user to pass a null value + * that the multiset does *not* contain. + */ + return (E) value; + } + @CanIgnoreReturnValue @Override - public int add(@Nullable E element, int occurrences) { + public int add(E element, int occurrences) { checkNonnegative(occurrences, "occurrences"); if (occurrences == 0) { return count(element); @@ -277,8 +295,9 @@ public int remove(@Nullable Object element, int occurrences) { int[] result = new int[1]; // used as a mutable int reference to hold result AvlNode newRoot; try { + // Safe because we catch exceptions, and we're not adding, only removing. @SuppressWarnings("unchecked") - E e = (E) element; + E e = uncheckedCastNullableObjectToE(element); if (!range.contains(e) || root == null) { return 0; } @@ -292,7 +311,7 @@ public int remove(@Nullable Object element, int occurrences) { @CanIgnoreReturnValue @Override - public int setCount(@Nullable E element, int count) { + public int setCount(E element, int count) { checkNonnegative(count, "count"); if (!range.contains(element)) { checkArgument(count == 0); @@ -314,7 +333,7 @@ public int setCount(@Nullable E element, int count) { @CanIgnoreReturnValue @Override - public boolean setCount(@Nullable E element, int oldCount, int newCount) { + public boolean setCount(E element, int oldCount, int newCount) { checkNonnegative(newCount, "newCount"); checkNonnegative(oldCount, "oldCount"); checkArgument(range.contains(element)); @@ -347,8 +366,9 @@ public void clear() { // Also clear these fields so that one deleted Entry doesn't retain all elements. current.left = null; current.right = null; - current.pred = null; - current.succ = null; + // See the comments on the pred and succ fields. + current.pred = unsafeNull(); + current.succ = unsafeNull(); current = next; } @@ -387,8 +407,9 @@ public int getCount() { } AvlNode node; if (range.hasLowerBound()) { - E endpoint = range.getLowerEndpoint(); - node = rootReference.get().ceiling(comparator(), endpoint); + // requireNonNull is safe because of the hasLowerBound check. + E endpoint = requireNonNull(range.getLowerEndpoint()); + node = root.ceiling(comparator(), endpoint); if (node == null) { return null; } @@ -409,8 +430,9 @@ && comparator().compare(endpoint, node.getElement()) == 0) { } AvlNode node; if (range.hasUpperBound()) { - E endpoint = range.getUpperEndpoint(); - node = rootReference.get().floor(comparator(), endpoint); + // requireNonNull is safe because of the hasUpperBound check. + E endpoint = requireNonNull(range.getUpperEndpoint()); + node = root.floor(comparator(), endpoint); if (node == null) { return null; } @@ -432,7 +454,7 @@ Iterator elementIterator() { @Override Iterator> entryIterator() { return new Iterator>() { - AvlNode current = firstNode(); + @Nullable AvlNode current = firstNode(); @Nullable Entry prevEntry; @Override @@ -452,7 +474,8 @@ public Entry next() { if (!hasNext()) { throw new NoSuchElementException(); } - Entry result = wrapEntry(current); + // requireNonNull is safe because current is only nulled out after iteration is complete. + Entry result = wrapEntry(requireNonNull(current)); prevEntry = result; if (current.succ == header) { current = null; @@ -464,7 +487,9 @@ public Entry next() { @Override public void remove() { - checkRemove(prevEntry != null); + if (prevEntry == null) { + throw noCallsToNextSinceLastRemove(); + } setCount(prevEntry.getElement(), 0); prevEntry = null; } @@ -474,8 +499,8 @@ public void remove() { @Override Iterator> descendingEntryIterator() { return new Iterator>() { - AvlNode current = lastNode(); - Entry prevEntry = null; + @Nullable AvlNode current = lastNode(); + @Nullable Entry prevEntry = null; @Override public boolean hasNext() { @@ -494,6 +519,8 @@ public Entry next() { if (!hasNext()) { throw new NoSuchElementException(); } + // requireNonNull is safe because of the hasNext check. + requireNonNull(current); Entry result = wrapEntry(current); prevEntry = result; if (current.pred == header) { @@ -506,7 +533,9 @@ public Entry next() { @Override public void remove() { - checkRemove(prevEntry != null); + if (prevEntry == null) { + throw noCallsToNextSinceLastRemove(); + } setCount(prevEntry.getElement(), 0); prevEntry = null; } @@ -529,7 +558,7 @@ public Iterator iterator() { } @Override - public SortedMultiset headMultiset(@Nullable E upperBound, BoundType boundType) { + public SortedMultiset headMultiset(E upperBound, BoundType boundType) { return new TreeMultiset( rootReference, range.intersect(GeneralRange.upTo(comparator(), upperBound, boundType)), @@ -537,21 +566,21 @@ public SortedMultiset headMultiset(@Nullable E upperBound, BoundType boundTyp } @Override - public SortedMultiset tailMultiset(@Nullable E lowerBound, BoundType boundType) { + public SortedMultiset tailMultiset(E lowerBound, BoundType boundType) { return new TreeMultiset( rootReference, range.intersect(GeneralRange.downTo(comparator(), lowerBound, boundType)), header); } - private static final class Reference { + private static final class Reference { private @Nullable T value; public @Nullable T get() { return value; } - public void checkAndSet(@Nullable T expected, T newValue) { + public void checkAndSet(@Nullable T expected, @Nullable T newValue) { if (value != expected) { throw new ConcurrentModificationException(); } @@ -564,7 +593,7 @@ void clear() { } private static final class AvlNode { - private final @Nullable E elem; + private final E elem; // elemCount is 0 iff this node has been deleted. private int elemCount; @@ -574,10 +603,20 @@ private static final class AvlNode { private int height; private @Nullable AvlNode left; private @Nullable AvlNode right; - private @Nullable AvlNode pred; - private @Nullable AvlNode succ; - - AvlNode(@Nullable E elem, int elemCount) { + /* + * pred and succ are nullable after construction, but we always call successor() to initialize + * them immediately thereafter. + * + * They may be subsequently nulled out by TreeMultiset.clear(). However, I think that the place + * that we reference a node whose fields have been cleared is inside the iterator. And while it + * would be nice for us to get nullness checking there, I'm not sure it's worth all the warnings + * checking would create in other methods. + */ + private AvlNode pred; + private AvlNode succ; + + @SuppressWarnings("nullness") // see comment about pred and succ above + AvlNode(E elem, int elemCount) { checkArgument(elemCount > 0); this.elem = elem; this.elemCount = elemCount; @@ -617,7 +656,7 @@ private AvlNode addLeftChild(E e, int count) { return this; } - AvlNode add(Comparator comparator, @Nullable E e, int count, int[] result) { + AvlNode add(Comparator comparator, E e, int count, int[] result) { /* * It speeds things up considerably to unconditionally add count to totalCount here, * but that destroys failure atomicity in the case of count overflow. =( @@ -662,7 +701,8 @@ AvlNode add(Comparator comparator, @Nullable E e, int count, int[] return this; } - AvlNode remove(Comparator comparator, @Nullable E e, int count, int[] result) { + @Nullable + AvlNode remove(Comparator comparator, E e, int count, int[] result) { int cmp = comparator.compare(e, elem); if (cmp < 0) { AvlNode initLeft = left; @@ -713,7 +753,8 @@ AvlNode remove(Comparator comparator, @Nullable E e, int count, in } } - AvlNode setCount(Comparator comparator, @Nullable E e, int count, int[] result) { + @Nullable + AvlNode setCount(Comparator comparator, E e, int count, int[] result) { int cmp = comparator.compare(e, elem); if (cmp < 0) { AvlNode initLeft = left; @@ -761,12 +802,9 @@ AvlNode setCount(Comparator comparator, @Nullable E e, int count, return this; } + @Nullable AvlNode setCount( - Comparator comparator, - @Nullable E e, - int expectedCount, - int newCount, - int[] result) { + Comparator comparator, E e, int expectedCount, int newCount, int[] result) { int cmp = comparator.compare(e, elem); if (cmp < 0) { AvlNode initLeft = left; @@ -824,7 +862,7 @@ AvlNode setCount( return this; } - private AvlNode deleteMe() { + private @Nullable AvlNode deleteMe() { int oldElemCount = this.elemCount; this.elemCount = 0; successor(pred, succ); @@ -851,7 +889,7 @@ private AvlNode deleteMe() { } // Removes the minimum node from this subtree to be reused elsewhere - private AvlNode removeMin(AvlNode node) { + private @Nullable AvlNode removeMin(AvlNode node) { if (left == null) { return right; } else { @@ -863,7 +901,7 @@ private AvlNode removeMin(AvlNode node) { } // Removes the maximum node from this subtree to be reused elsewhere - private AvlNode removeMax(AvlNode node) { + private @Nullable AvlNode removeMax(AvlNode node) { if (right == null) { return left; } else { @@ -892,11 +930,15 @@ private void recompute() { private AvlNode rebalance() { switch (balanceFactor()) { case -2: + // requireNonNull is safe because right must exist in order to get a negative factor. + requireNonNull(right); if (right.balanceFactor() > 0) { right = right.rotateRight(); } return rotateLeft(); case 2: + // requireNonNull is safe because left must exist in order to get a positive factor. + requireNonNull(left); if (left.balanceFactor() < 0) { left = left.rotateLeft(); } @@ -912,7 +954,9 @@ private int balanceFactor() { } private AvlNode rotateLeft() { - checkState(right != null); + if (right == null) { + throw new IllegalStateException(); + } AvlNode newTop = right; this.right = newTop.left; newTop.left = this; @@ -924,7 +968,9 @@ private AvlNode rotateLeft() { } private AvlNode rotateRight() { - checkState(left != null); + if (left == null) { + throw new IllegalStateException(); + } AvlNode newTop = left; this.left = newTop.right; newTop.right = this; @@ -984,7 +1030,8 @@ private static void successor(AvlNode a, AvlNode b) { b.pred = a; } - private static void successor(AvlNode a, AvlNode b, AvlNode c) { + private static void successor( + AvlNode a, AvlNode b, AvlNode c) { successor(a, b); successor(b, c); } @@ -995,6 +1042,11 @@ private static void successor(AvlNode a, AvlNode b, AvlNode c) { * AbstractMultiset.equals() can simply check whether two multisets have equal entry sets. */ + @SuppressWarnings("nullness") + private static E unsafeNull() { + return null; + } + /** * @serialData the comparator, the number of distinct elements, the first element, its count, the * second element, its count, and so on @@ -1017,7 +1069,8 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo .set(this, GeneralRange.all(comparator)); Serialization.getFieldSetter(TreeMultiset.class, "rootReference") .set(this, new Reference>()); - AvlNode header = new AvlNode(null, 1); + // This is safe as long as we're careful not to access `elem` on the header node. + AvlNode header = new AvlNode(unsafeNull(), 1); Serialization.getFieldSetter(TreeMultiset.class, "header").set(this, header); successor(header, header); Serialization.populateMultiset(this, stream); diff --git a/guava/src/com/google/common/collect/TreeRangeMap.java b/guava/src/com/google/common/collect/TreeRangeMap.java index eb52028f2b97..f3b2ebfef82f 100644 --- a/guava/src/com/google/common/collect/TreeRangeMap.java +++ b/guava/src/com/google/common/collect/TreeRangeMap.java @@ -21,6 +21,7 @@ import static com.google.common.base.Predicates.compose; import static com.google.common.base.Predicates.in; import static com.google.common.base.Predicates.not; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -38,6 +39,7 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.function.BiFunction; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -51,7 +53,8 @@ */ @Beta @GwtIncompatible // NavigableMap -public final class TreeRangeMap implements RangeMap { +public final class TreeRangeMap + implements RangeMap { private final NavigableMap, RangeMapEntry> entriesByLowerBound; @@ -63,7 +66,7 @@ private TreeRangeMap() { this.entriesByLowerBound = Maps.newTreeMap(); } - private static final class RangeMapEntry + private static final class RangeMapEntry extends AbstractMapEntry, V> { private final Range range; private final V value; @@ -153,7 +156,7 @@ private Range coalescedRange(Range range, V value) { } /** Returns the range that spans the given range and entry, if the entry can be coalesced. */ - private static Range coalesce( + private static Range coalesce( Range range, V value, @Nullable Entry, RangeMapEntry> entry) { if (entry != null && entry.getValue().getKey().isConnected(range) @@ -178,10 +181,11 @@ public void clear() { @Override public Range span() { Entry, RangeMapEntry> firstEntry = entriesByLowerBound.firstEntry(); - Entry, RangeMapEntry> lastEntry = entriesByLowerBound.lastEntry(); if (firstEntry == null) { throw new NoSuchElementException(); } + // requireNonNull is safe because, if there's a firstEntry, there must be a lastEntry. + Entry, RangeMapEntry> lastEntry = requireNonNull(entriesByLowerBound.lastEntry()); return Range.create( firstEntry.getValue().getKey().lowerBound, lastEntry.getValue().getKey().upperBound); } @@ -263,7 +267,7 @@ private void split(Cut cut) { public void merge( Range range, @Nullable V value, - BiFunction remappingFunction) { + BiFunction remappingFunction) { checkNotNull(range); checkNotNull(remappingFunction); @@ -339,7 +343,7 @@ public boolean containsKey(@Nullable Object key) { } @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { if (key instanceof Range) { Range range = (Range) key; RangeMapEntry rangeMapEntry = entriesByLowerBound.get(range.lowerBound); @@ -393,14 +397,14 @@ public Range span() { } @Override - public void put(Range range, Object value) { + public void put(Range range, @SuppressWarnings("nullness") Object value) { checkNotNull(range); throw new IllegalArgumentException( "Cannot insert range " + range + " into an empty subRangeMap"); } @Override - public void putCoalescing(Range range, Object value) { + public void putCoalescing(Range range, @SuppressWarnings("nullness") Object value) { checkNotNull(range); throw new IllegalArgumentException( "Cannot insert range " + range + " into an empty subRangeMap"); @@ -548,7 +552,7 @@ public void remove(Range range) { public void merge( Range range, @Nullable V value, - BiFunction remappingFunction) { + BiFunction remappingFunction) { checkArgument( subRange.encloses(range), "Cannot merge range %s into a subRangeMap(%s)", @@ -626,12 +630,12 @@ public String toString() { class SubRangeMapAsMap extends AbstractMap, V> { @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return get(key) != null; } @Override - public V get(Object key) { + public @Nullable V get(@Nullable Object key) { try { if (key instanceof Range) { @SuppressWarnings("unchecked") // we catch ClassCastExceptions @@ -664,11 +668,12 @@ public V get(Object key) { } @Override - public V remove(Object key) { + public @Nullable V remove(@Nullable Object key) { V value = get(key); if (value != null) { - @SuppressWarnings("unchecked") // it's definitely in the map, so safe - Range range = (Range) key; + // it's definitely in the map, so the cast and requireNonNull are safe + @SuppressWarnings("unchecked") + Range range = (Range) requireNonNull(key); TreeRangeMap.this.remove(range); return value; } diff --git a/guava/src/com/google/common/collect/TreeRangeSet.java b/guava/src/com/google/common/collect/TreeRangeSet.java index 6ca6382cc926..7aca22f9938a 100644 --- a/guava/src/com/google/common/collect/TreeRangeSet.java +++ b/guava/src/com/google/common/collect/TreeRangeSet.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.Beta; import com.google.common.annotations.GwtIncompatible; @@ -166,6 +167,8 @@ public Range span() { if (firstEntry == null) { throw new NoSuchElementException(); } + // requireNonNull is safe: If there's a firstEntry, there's a lastEntry. + requireNonNull(lastEntry); return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound); } @@ -335,7 +338,7 @@ public boolean containsKey(@Nullable Object key) { } @Override - public Range get(@Nullable Object key) { + public @Nullable Range get(@Nullable Object key) { if (key instanceof Cut) { try { @SuppressWarnings("unchecked") // we catch CCEs @@ -622,7 +625,7 @@ public int size() { } @Override - public @Nullable Range get(Object key) { + public @Nullable Range get(@Nullable Object key) { if (key instanceof Cut) { try { @SuppressWarnings("unchecked") @@ -640,7 +643,7 @@ public int size() { } @Override - public boolean containsKey(Object key) { + public boolean containsKey(@Nullable Object key) { return get(key) != null; } } diff --git a/guava/src/com/google/common/collect/TreeTraverser.java b/guava/src/com/google/common/collect/TreeTraverser.java index 910925240546..43f92357cc8b 100644 --- a/guava/src/com/google/common/collect/TreeTraverser.java +++ b/guava/src/com/google/common/collect/TreeTraverser.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.Queue; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Views elements of a type {@code T} as nodes in a tree, and provides methods to traverse the trees @@ -74,7 +75,7 @@ @Deprecated @Beta @GwtCompatible -public abstract class TreeTraverser { +public abstract class TreeTraverser { /** * Returns a tree traverser that uses the given function to navigate from a node to its children. @@ -87,7 +88,7 @@ public abstract class TreeTraverser { * lambda, these methods have exactly the same signature. */ @Deprecated - public static TreeTraverser using( + public static TreeTraverser using( final Function> nodeToChildrenFunction) { checkNotNull(nodeToChildrenFunction); return new TreeTraverser() { @@ -203,7 +204,7 @@ UnmodifiableIterator postOrderIterator(T root) { return new PostOrderIterator(root); } - private static final class PostOrderNode { + private static final class PostOrderNode { final T root; final Iterator childIterator; diff --git a/guava/src/com/google/common/collect/UnmodifiableIterator.java b/guava/src/com/google/common/collect/UnmodifiableIterator.java index f0f76b2d60b2..eadb396f19d7 100644 --- a/guava/src/com/google/common/collect/UnmodifiableIterator.java +++ b/guava/src/com/google/common/collect/UnmodifiableIterator.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An iterator that does not support {@link #remove}. diff --git a/guava/src/com/google/common/collect/UnmodifiableListIterator.java b/guava/src/com/google/common/collect/UnmodifiableListIterator.java index ec4219c0ceb2..d2efe7ae88f7 100644 --- a/guava/src/com/google/common/collect/UnmodifiableListIterator.java +++ b/guava/src/com/google/common/collect/UnmodifiableListIterator.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtCompatible; import java.util.ListIterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A list iterator that does not support {@link #remove}, {@link #add}, or {@link #set}. @@ -26,8 +27,8 @@ * @author Louis Wasserman */ @GwtCompatible -public abstract class UnmodifiableListIterator extends UnmodifiableIterator - implements ListIterator { +public abstract class UnmodifiableListIterator + extends UnmodifiableIterator implements ListIterator { /** Constructor for use by subclasses. */ protected UnmodifiableListIterator() {} diff --git a/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java b/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java index d7a20cca9dcb..d1887c8d6170 100644 --- a/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java +++ b/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java @@ -70,22 +70,22 @@ public SortedMultiset descendingMultiset() { } @Override - public Entry firstEntry() { + public @Nullable Entry firstEntry() { return delegate().firstEntry(); } @Override - public Entry lastEntry() { + public @Nullable Entry lastEntry() { return delegate().lastEntry(); } @Override - public Entry pollFirstEntry() { + public @Nullable Entry pollFirstEntry() { throw new UnsupportedOperationException(); } @Override - public Entry pollLastEntry() { + public @Nullable Entry pollLastEntry() { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/escape/ArrayBasedCharEscaper.java b/guava/src/com/google/common/escape/ArrayBasedCharEscaper.java index 91e48e6c9c6b..d35239624ff3 100644 --- a/guava/src/com/google/common/escape/ArrayBasedCharEscaper.java +++ b/guava/src/com/google/common/escape/ArrayBasedCharEscaper.java @@ -19,6 +19,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link CharEscaper} that uses an array to quickly look up replacement characters for a given @@ -119,7 +120,7 @@ public final String escape(String s) { * #escapeUnsafe} is called. */ @Override - protected final char[] escape(char c) { + protected final char @Nullable [] escape(char c) { if (c < replacementsLength) { char[] chars = replacements[c]; if (chars != null) { @@ -145,5 +146,5 @@ protected final char[] escape(char c) { * @return the replacement characters, or {@code null} if no escaping was required */ // TODO(dbeaumont,cpovirk): Rename this something better once refactoring done - protected abstract char[] escapeUnsafe(char c); + protected abstract char @Nullable [] escapeUnsafe(char c); } diff --git a/guava/src/com/google/common/escape/ArrayBasedEscaperMap.java b/guava/src/com/google/common/escape/ArrayBasedEscaperMap.java index 400c3b13546e..213bba468ea1 100644 --- a/guava/src/com/google/common/escape/ArrayBasedEscaperMap.java +++ b/guava/src/com/google/common/escape/ArrayBasedEscaperMap.java @@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting; import java.util.Collections; import java.util.Map; +import java.util.Map.Entry; /** * An implementation-specific parameter class suitable for initializing {@link @@ -73,8 +74,8 @@ static char[][] createReplacementArray(Map map) { } char max = Collections.max(map.keySet()); char[][] replacements = new char[max + 1][]; - for (char c : map.keySet()) { - replacements[c] = map.get(c).toCharArray(); + for (Entry entry : map.entrySet()) { + replacements[entry.getKey()] = entry.getValue().toCharArray(); } return replacements; } diff --git a/guava/src/com/google/common/escape/ArrayBasedUnicodeEscaper.java b/guava/src/com/google/common/escape/ArrayBasedUnicodeEscaper.java index 756abcec6658..91efc3039b80 100644 --- a/guava/src/com/google/common/escape/ArrayBasedUnicodeEscaper.java +++ b/guava/src/com/google/common/escape/ArrayBasedUnicodeEscaper.java @@ -159,7 +159,7 @@ public final String escape(String s) { * {@link #escapeUnsafe} is called. */ @Override - protected final char[] escape(int cp) { + protected final char @Nullable [] escape(int cp) { if (cp < replacementsLength) { char[] chars = replacements[cp]; if (chars != null) { @@ -199,5 +199,5 @@ protected final int nextEscapeIndex(CharSequence csq, int index, int end) { * @param cp the Unicode code point to escape * @return the replacement characters, or {@code null} if no escaping was required */ - protected abstract char[] escapeUnsafe(int cp); + protected abstract char @Nullable [] escapeUnsafe(int cp); } diff --git a/guava/src/com/google/common/escape/CharEscaper.java b/guava/src/com/google/common/escape/CharEscaper.java index b8ffee3a978a..af96cf15f610 100644 --- a/guava/src/com/google/common/escape/CharEscaper.java +++ b/guava/src/com/google/common/escape/CharEscaper.java @@ -18,6 +18,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An object that converts literal text into a format safe for inclusion in a particular context @@ -80,7 +81,7 @@ public String escape(String string) { * @param c the character to escape if necessary * @return the replacement characters, or {@code null} if no escaping was needed */ - protected abstract char[] escape(char c); + protected abstract char @Nullable [] escape(char c); /** * Returns the escaped form of a given literal string, starting at the given index. This method is diff --git a/guava/src/com/google/common/escape/CharEscaperBuilder.java b/guava/src/com/google/common/escape/CharEscaperBuilder.java index dba855f36b8a..59000e048424 100644 --- a/guava/src/com/google/common/escape/CharEscaperBuilder.java +++ b/guava/src/com/google/common/escape/CharEscaperBuilder.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Simple helper class to build a "sparse" array of objects based on the indexes that were added to @@ -65,7 +66,7 @@ public String escape(String s) { } @Override - protected char[] escape(char c) { + protected char @Nullable [] escape(char c) { return c < replaceLength ? replacements[c] : null; } } @@ -108,6 +109,7 @@ public CharEscaperBuilder addEscapes(char[] cs, String r) { * * @return a "sparse" array that holds the replacement mappings. */ +@SuppressWarnings("nullness") public char[][] toArray() { char[][] result = new char[max + 1][]; for (Entry entry : map.entrySet()) { diff --git a/guava/src/com/google/common/escape/Escaper.java b/guava/src/com/google/common/escape/Escaper.java index 0d32a09a1e18..97abc7539d39 100644 --- a/guava/src/com/google/common/escape/Escaper.java +++ b/guava/src/com/google/common/escape/Escaper.java @@ -16,7 +16,6 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.base.Function; -import com.google.errorprone.annotations.DoNotMock; /** * An object that converts literal text into a format safe for inclusion in a particular context @@ -54,7 +53,6 @@ * @author David Beaumont * @since 15.0 */ -@DoNotMock("Use Escapers.nullEscaper() or another methods from the *Escapers classes") @GwtCompatible public abstract class Escaper { // TODO(dbeaumont): evaluate custom implementations, considering package private constructor. diff --git a/guava/src/com/google/common/escape/Escapers.java b/guava/src/com/google/common/escape/Escapers.java index 6fa8365f3714..0fb554802ff2 100644 --- a/guava/src/com/google/common/escape/Escapers.java +++ b/guava/src/com/google/common/escape/Escapers.java @@ -52,7 +52,7 @@ public String escape(String string) { } @Override - protected char[] escape(char c) { + protected char @Nullable [] escape(char c) { // TODO: Fix tests not to call this directly and make it throw an error. return null; } @@ -95,7 +95,7 @@ public static final class Builder { private final Map replacementMap = new HashMap<>(); private char safeMin = Character.MIN_VALUE; private char safeMax = Character.MAX_VALUE; - private String unsafeReplacement = null; + private @Nullable String unsafeReplacement = null; // The constructor is exposed via the builder() method above. private Builder() {} @@ -151,11 +151,11 @@ public Builder addEscape(char c, String replacement) { /** Returns a new escaper based on the current state of the builder. */ public Escaper build() { return new ArrayBasedCharEscaper(replacementMap, safeMin, safeMax) { - private final char[] replacementChars = + private final char @Nullable [] replacementChars = unsafeReplacement != null ? unsafeReplacement.toCharArray() : null; @Override - protected char[] escapeUnsafe(char c) { + protected char @Nullable [] escapeUnsafe(char c) { return replacementChars; } }; @@ -198,7 +198,7 @@ static UnicodeEscaper asUnicodeEscaper(Escaper escaper) { * @param c the character to escape if necessary * @return the replacement string, or {@code null} if no escaping was needed */ - public static String computeReplacement(CharEscaper escaper, char c) { + public static @Nullable String computeReplacement(CharEscaper escaper, char c) { return stringOrNull(escaper.escape(c)); } @@ -211,11 +211,11 @@ public static String computeReplacement(CharEscaper escaper, char c) { * @param cp the Unicode code point to escape if necessary * @return the replacement string, or {@code null} if no escaping was needed */ - public static String computeReplacement(UnicodeEscaper escaper, int cp) { + public static @Nullable String computeReplacement(UnicodeEscaper escaper, int cp) { return stringOrNull(escaper.escape(cp)); } - private static String stringOrNull(char[] in) { + private static @Nullable String stringOrNull(char @Nullable [] in) { return (in == null) ? null : new String(in); } @@ -223,7 +223,7 @@ private static String stringOrNull(char[] in) { private static UnicodeEscaper wrap(final CharEscaper escaper) { return new UnicodeEscaper() { @Override - protected char[] escape(int cp) { + protected char @Nullable [] escape(int cp) { // If a code point maps to a single character, just escape that. if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { return escaper.escape((char) cp); diff --git a/guava/src/com/google/common/escape/Platform.java b/guava/src/com/google/common/escape/Platform.java index 99a7d4f0f237..1e66f6508e4b 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; /** @@ -27,7 +29,8 @@ private Platform() {} /** Returns a thread-local 1024-char array. */ static char[] charBufferFromThreadLocal() { - return DEST_TL.get(); + // requireNonNull is safe because of initialValue. + return requireNonNull(DEST_TL.get()); } /** diff --git a/guava/src/com/google/common/escape/UnicodeEscaper.java b/guava/src/com/google/common/escape/UnicodeEscaper.java index 06421624ff1b..5c65404945ea 100644 --- a/guava/src/com/google/common/escape/UnicodeEscaper.java +++ b/guava/src/com/google/common/escape/UnicodeEscaper.java @@ -18,6 +18,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An {@link Escaper} that converts literal text into a format safe for inclusion in a particular @@ -77,7 +78,7 @@ protected UnicodeEscaper() {} * @param cp the Unicode code point to escape if necessary * @return the replacement characters, or {@code null} if no escaping was needed */ - protected abstract char[] escape(int cp); + protected abstract char @Nullable [] escape(int cp); /** * Returns the escaped form of a given literal string. diff --git a/guava/src/com/google/common/eventbus/Dispatcher.java b/guava/src/com/google/common/eventbus/Dispatcher.java index 11e2de191c70..16970ad011ad 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; @@ -96,10 +97,12 @@ protected Boolean initialValue() { void dispatch(Object event, Iterator subscribers) { checkNotNull(event); checkNotNull(subscribers); - Queue queueForThread = queue.get(); + // requireNonNull is safe because of initialValue. + Queue queueForThread = requireNonNull(queue.get()); queueForThread.offer(new Event(event, subscribers)); - if (!dispatching.get()) { + // requireNonNull is safe because of initialValue. + if (!requireNonNull(dispatching.get())) { dispatching.set(true); try { Event nextEvent; diff --git a/guava/src/com/google/common/eventbus/EventBus.java b/guava/src/com/google/common/eventbus/EventBus.java index e5053990b757..6a73fd07505a 100644 --- a/guava/src/com/google/common/eventbus/EventBus.java +++ b/guava/src/com/google/common/eventbus/EventBus.java @@ -101,7 +101,10 @@ public class EventBus { private final Executor executor; private final SubscriberExceptionHandler exceptionHandler; + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) private final SubscriberRegistry subscribers = new SubscriberRegistry(this); + private final Dispatcher dispatcher; /** Creates a new EventBus named "default". */ diff --git a/guava/src/com/google/common/eventbus/Subscriber.java b/guava/src/com/google/common/eventbus/Subscriber.java index ddc4963c9609..959375ef13f9 100644 --- a/guava/src/com/google/common/eventbus/Subscriber.java +++ b/guava/src/com/google/common/eventbus/Subscriber.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.annotations.VisibleForTesting; import com.google.j2objc.annotations.Weak; @@ -71,7 +72,11 @@ public void run() { try { invokeSubscriberMethod(event); } catch (InvocationTargetException e) { - bus.handleSubscriberException(e.getCause(), context(event)); + /* + * requireNonNull should be safe because an InvocationTargetException from reflection + * should have a cause. + */ + bus.handleSubscriberException(requireNonNull(e.getCause()), context(event)); } } }); @@ -90,8 +95,9 @@ void invokeSubscriberMethod(Object event) throws InvocationTargetException { } catch (IllegalAccessException e) { throw new Error("Method became inaccessible: " + event, e); } catch (InvocationTargetException e) { - if (e.getCause() instanceof Error) { - throw (Error) e.getCause(); + Throwable cause = e.getCause(); + if (cause instanceof Error) { + throw (Error) cause; } throw e; } diff --git a/guava/src/com/google/common/eventbus/SubscriberRegistry.java b/guava/src/com/google/common/eventbus/SubscriberRegistry.java index c6990dd8a7a5..8b926b2fee2c 100644 --- a/guava/src/com/google/common/eventbus/SubscriberRegistry.java +++ b/guava/src/com/google/common/eventbus/SubscriberRegistry.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.VisibleForTesting; import com.google.common.base.MoreObjects; @@ -222,7 +223,11 @@ static ImmutableSet> flattenHierarchy(Class concreteClass) { try { return flattenHierarchyCache.getUnchecked(concreteClass); } catch (UncheckedExecutionException e) { - throw Throwables.propagate(e.getCause()); + /* + * requireNonNull is safe: An UncheckedExecutionException from a CacheBuilder Cache + * implementation will have a cause. + */ + throw Throwables.propagate(requireNonNull(e.getCause())); } } diff --git a/guava/src/com/google/common/graph/AbstractBaseGraph.java b/guava/src/com/google/common/graph/AbstractBaseGraph.java index 352df1995fbc..43a359d60474 100644 --- a/guava/src/com/google/common/graph/AbstractBaseGraph.java +++ b/guava/src/com/google/common/graph/AbstractBaseGraph.java @@ -30,6 +30,7 @@ import com.google.common.primitives.Ints; import java.util.AbstractSet; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -41,7 +42,7 @@ * @author James Sexton * @param Node parameter type */ -abstract class AbstractBaseGraph implements BaseGraph { +abstract class AbstractBaseGraph implements BaseGraph { /** * Returns the number of edges in this graph; used to calculate the size of {@link #edges()}. This @@ -76,7 +77,7 @@ public int size() { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/graph/AbstractDirectedNetworkConnections.java b/guava/src/com/google/common/graph/AbstractDirectedNetworkConnections.java index 9afaf3eea799..4e8bf14530e6 100644 --- a/guava/src/com/google/common/graph/AbstractDirectedNetworkConnections.java +++ b/guava/src/com/google/common/graph/AbstractDirectedNetworkConnections.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.graph.Graphs.checkNonNegative; import static com.google.common.graph.Graphs.checkPositive; +import static java.util.Objects.requireNonNull; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; @@ -30,6 +31,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,7 +41,9 @@ * @param Node parameter type * @param Edge parameter type */ -abstract class AbstractDirectedNetworkConnections implements NetworkConnections { +abstract class AbstractDirectedNetworkConnections< + N extends @NonNull Object, E extends @NonNull Object> + implements NetworkConnections { /** Keys are edges incoming to the origin node, values are the source node. */ protected final Map inEdgeMap; @@ -99,7 +103,7 @@ public Set outEdges() { public N adjacentNode(E edge) { // Since the reference node is defined to be 'source' for directed graphs, // we can assume this edge lives in the set of outgoing edges. - return checkNotNull(outEdgeMap.get(edge)); + return requireNonNull(outEdgeMap.get(edge)); } @Override @@ -108,13 +112,13 @@ public N removeInEdge(E edge, boolean isSelfLoop) { checkNonNegative(--selfLoopCount); } N previousNode = inEdgeMap.remove(edge); - return checkNotNull(previousNode); + return requireNonNull(previousNode); } @Override public N removeOutEdge(E edge) { N previousNode = outEdgeMap.remove(edge); - return checkNotNull(previousNode); + return requireNonNull(previousNode); } @Override diff --git a/guava/src/com/google/common/graph/AbstractGraph.java b/guava/src/com/google/common/graph/AbstractGraph.java index 986c94b91d82..b0d52291d58c 100644 --- a/guava/src/com/google/common/graph/AbstractGraph.java +++ b/guava/src/com/google/common/graph/AbstractGraph.java @@ -17,6 +17,7 @@ package com.google.common.graph; import com.google.common.annotations.Beta; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -28,7 +29,8 @@ * @since 20.0 */ @Beta -public abstract class AbstractGraph extends AbstractBaseGraph implements Graph { +public abstract class AbstractGraph extends AbstractBaseGraph + implements Graph { @Override public final boolean equals(@Nullable Object obj) { diff --git a/guava/src/com/google/common/graph/AbstractGraphBuilder.java b/guava/src/com/google/common/graph/AbstractGraphBuilder.java index 84e461a46c37..3c6b7bdf0d52 100644 --- a/guava/src/com/google/common/graph/AbstractGraphBuilder.java +++ b/guava/src/com/google/common/graph/AbstractGraphBuilder.java @@ -17,13 +17,14 @@ package com.google.common.graph; import com.google.common.base.Optional; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A base class for builders that construct graphs with user-defined properties. * * @author James Sexton */ -abstract class AbstractGraphBuilder { +abstract class AbstractGraphBuilder { final boolean directed; boolean allowsSelfLoops = false; ElementOrder nodeOrder = ElementOrder.insertion(); diff --git a/guava/src/com/google/common/graph/AbstractNetwork.java b/guava/src/com/google/common/graph/AbstractNetwork.java index 648ee9bfa0de..4a0d03fc99dd 100644 --- a/guava/src/com/google/common/graph/AbstractNetwork.java +++ b/guava/src/com/google/common/graph/AbstractNetwork.java @@ -35,6 +35,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -50,7 +51,8 @@ * @since 20.0 */ @Beta -public abstract class AbstractNetwork implements Network { +public abstract class AbstractNetwork + implements Network { @Override public Graph asGraph() { @@ -288,7 +290,8 @@ public String toString() { + edgeIncidentNodesMap(this); } - private static Map> edgeIncidentNodesMap(final Network network) { + private static + Map> edgeIncidentNodesMap(final Network network) { Function> edgeToIncidentNodesFn = new Function>() { @Override diff --git a/guava/src/com/google/common/graph/AbstractUndirectedNetworkConnections.java b/guava/src/com/google/common/graph/AbstractUndirectedNetworkConnections.java index 03279d068ec0..0cd217c5e337 100644 --- a/guava/src/com/google/common/graph/AbstractUndirectedNetworkConnections.java +++ b/guava/src/com/google/common/graph/AbstractUndirectedNetworkConnections.java @@ -18,10 +18,13 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A base implementation of {@link NetworkConnections} for undirected networks. @@ -30,7 +33,9 @@ * @param Node parameter type * @param Edge parameter type */ -abstract class AbstractUndirectedNetworkConnections implements NetworkConnections { +abstract class AbstractUndirectedNetworkConnections< + N extends @NonNull Object, E extends @NonNull Object> + implements NetworkConnections { /** Keys are edges incident to the origin node, values are the node at the other end. */ protected final Map incidentEdgeMap; @@ -65,11 +70,11 @@ public Set outEdges() { @Override public N adjacentNode(E edge) { - return checkNotNull(incidentEdgeMap.get(edge)); + return requireNonNull(incidentEdgeMap.get(edge)); } @Override - public N removeInEdge(E edge, boolean isSelfLoop) { + public @Nullable N removeInEdge(E edge, boolean isSelfLoop) { if (!isSelfLoop) { return removeOutEdge(edge); } @@ -79,7 +84,7 @@ public N removeInEdge(E edge, boolean isSelfLoop) { @Override public N removeOutEdge(E edge) { N previousNode = incidentEdgeMap.remove(edge); - return checkNotNull(previousNode); + return requireNonNull(previousNode); } @Override diff --git a/guava/src/com/google/common/graph/AbstractValueGraph.java b/guava/src/com/google/common/graph/AbstractValueGraph.java index c83cff585e32..15e45f563b17 100644 --- a/guava/src/com/google/common/graph/AbstractValueGraph.java +++ b/guava/src/com/google/common/graph/AbstractValueGraph.java @@ -16,12 +16,15 @@ package com.google.common.graph; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; import com.google.common.base.Function; import com.google.common.collect.Maps; import java.util.Map; import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -37,8 +40,8 @@ * @since 20.0 */ @Beta -public abstract class AbstractValueGraph extends AbstractBaseGraph - implements ValueGraph { +public abstract class AbstractValueGraph + extends AbstractBaseGraph implements ValueGraph { @Override public Graph asGraph() { @@ -148,12 +151,14 @@ public String toString() { + edgeValueMap(this); } - private static Map, V> edgeValueMap(final ValueGraph graph) { + private static + Map, V> edgeValueMap(final ValueGraph graph) { Function, V> edgeToValueFn = new Function, V>() { @Override public V apply(EndpointPair edge) { - return graph.edgeValueOrDefault(edge.nodeU(), edge.nodeV(), null); + // requireNonNull is safe because the endpoint pair comes from the graph. + return requireNonNull(graph.edgeValueOrDefault(edge.nodeU(), edge.nodeV(), null)); } }; return Maps.asMap(graph.edges(), edgeToValueFn); diff --git a/guava/src/com/google/common/graph/BaseGraph.java b/guava/src/com/google/common/graph/BaseGraph.java index 1df5de7f174e..06aaeb5c2b7c 100644 --- a/guava/src/com/google/common/graph/BaseGraph.java +++ b/guava/src/com/google/common/graph/BaseGraph.java @@ -17,6 +17,7 @@ package com.google.common.graph; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A non-public interface for the methods shared between {@link Graph} and {@link ValueGraph}. @@ -24,7 +25,8 @@ * @author James Sexton * @param Node parameter type */ -interface BaseGraph extends SuccessorsFunction, PredecessorsFunction { +interface BaseGraph + extends SuccessorsFunction, PredecessorsFunction { // // Graph-level accessors // diff --git a/guava/src/com/google/common/graph/ConfigurableMutableNetwork.java b/guava/src/com/google/common/graph/ConfigurableMutableNetwork.java new file mode 100755 index 000000000000..804b904e55e9 --- /dev/null +++ b/guava/src/com/google/common/graph/ConfigurableMutableNetwork.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2016 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.graph; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.graph.GraphConstants.PARALLEL_EDGES_NOT_ALLOWED; +import static com.google.common.graph.GraphConstants.REUSING_EDGE; +import static com.google.common.graph.GraphConstants.SELF_LOOPS_NOT_ALLOWED; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Configurable implementation of {@link MutableNetwork} that supports both directed and undirected + * graphs. Instances of this class should be constructed with {@link NetworkBuilder}. + * + *

    Time complexities for mutation methods are all O(1) except for {@code removeNode(N node)}, + * which is in O(d_node) where d_node is the degree of {@code node}. + * + * @author James Sexton + * @author Joshua O'Madadhain + * @author Omar Darwish + * @param Node parameter type + * @param Edge parameter type + */ +final class ConfigurableMutableNetwork + extends ConfigurableNetwork implements MutableNetwork { + + /** Constructs a mutable graph with the properties specified in {@code builder}. */ + ConfigurableMutableNetwork(NetworkBuilder builder) { + super(builder); + } + + @Override + @CanIgnoreReturnValue + public boolean addNode(N node) { + checkNotNull(node, "node"); + + if (containsNode(node)) { + return false; + } + + addNodeInternal(node); + return true; + } + + /** + * Adds {@code node} to the graph and returns the associated {@link NetworkConnections}. + * + * @throws IllegalStateException if {@code node} is already present + */ + @CanIgnoreReturnValue + private NetworkConnections addNodeInternal(N node) { + NetworkConnections connections = newConnections(); + checkState(nodeConnections.put(node, connections) == null); + return connections; + } + + @Override + @CanIgnoreReturnValue + public boolean addEdge(N nodeU, N nodeV, E edge) { + checkNotNull(nodeU, "nodeU"); + checkNotNull(nodeV, "nodeV"); + checkNotNull(edge, "edge"); + + if (containsEdge(edge)) { + EndpointPair existingIncidentNodes = incidentNodes(edge); + EndpointPair newIncidentNodes = EndpointPair.of(this, nodeU, nodeV); + checkArgument( + existingIncidentNodes.equals(newIncidentNodes), + REUSING_EDGE, + edge, + existingIncidentNodes, + newIncidentNodes); + return false; + } + NetworkConnections connectionsU = nodeConnections.get(nodeU); + if (!allowsParallelEdges()) { + checkArgument( + !(connectionsU != null && connectionsU.successors().contains(nodeV)), + PARALLEL_EDGES_NOT_ALLOWED, + nodeU, + nodeV); + } + boolean isSelfLoop = nodeU.equals(nodeV); + if (!allowsSelfLoops()) { + checkArgument(!isSelfLoop, SELF_LOOPS_NOT_ALLOWED, nodeU); + } + + if (connectionsU == null) { + connectionsU = addNodeInternal(nodeU); + } + connectionsU.addOutEdge(edge, nodeV); + NetworkConnections connectionsV = nodeConnections.get(nodeV); + if (connectionsV == null) { + connectionsV = addNodeInternal(nodeV); + } + connectionsV.addInEdge(edge, nodeU, isSelfLoop); + edgeToReferenceNode.put(edge, nodeU); + return true; + } + + @Override + @CanIgnoreReturnValue + public boolean addEdge(EndpointPair endpoints, E edge) { + validateEndpoints(endpoints); + return addEdge(endpoints.nodeU(), endpoints.nodeV(), edge); + } + + @Override + @CanIgnoreReturnValue + public boolean removeNode(N node) { + checkNotNull(node, "node"); + + NetworkConnections connections = nodeConnections.get(node); + if (connections == null) { + return false; + } + + // Since views are returned, we need to copy the edges that will be removed. + // Thus we avoid modifying the underlying view while iterating over it. + for (E edge : ImmutableList.copyOf(connections.incidentEdges())) { + removeEdge(edge); + } + nodeConnections.remove(node); + return true; + } + + @Override + @CanIgnoreReturnValue + public boolean removeEdge(E edge) { + checkNotNull(edge, "edge"); + + N nodeU = edgeToReferenceNode.get(edge); + if (nodeU == null) { + return false; + } + + // The requireNonNull calls are safe because we found the edge in the network. + NetworkConnections connectionsU = requireNonNull(nodeConnections.get(nodeU)); + N nodeV = connectionsU.adjacentNode(edge); + NetworkConnections connectionsV = requireNonNull(nodeConnections.get(nodeV)); + connectionsU.removeOutEdge(edge); + connectionsV.removeInEdge(edge, allowsSelfLoops() && nodeU.equals(nodeV)); + edgeToReferenceNode.remove(edge); + return true; + } + + private NetworkConnections newConnections() { + return isDirected() + ? allowsParallelEdges() + ? DirectedMultiNetworkConnections.of() + : DirectedNetworkConnections.of() + : allowsParallelEdges() + ? UndirectedMultiNetworkConnections.of() + : UndirectedNetworkConnections.of(); + } +} diff --git a/guava/src/com/google/common/graph/ConfigurableNetwork.java b/guava/src/com/google/common/graph/ConfigurableNetwork.java new file mode 100755 index 000000000000..ef24e05f019f --- /dev/null +++ b/guava/src/com/google/common/graph/ConfigurableNetwork.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2016 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.graph; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.graph.GraphConstants.DEFAULT_EDGE_COUNT; +import static com.google.common.graph.GraphConstants.DEFAULT_NODE_COUNT; +import static com.google.common.graph.GraphConstants.EDGE_NOT_IN_GRAPH; +import static com.google.common.graph.GraphConstants.NODE_NOT_IN_GRAPH; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Configurable implementation of {@link Network} that supports the options supplied by {@link + * NetworkBuilder}. + * + *

    This class maintains a map of nodes to {@link NetworkConnections}. This class also maintains a + * map of edges to reference nodes. The reference node is defined to be the edge's source node on + * directed graphs, and an arbitrary endpoint of the edge on undirected graphs. + * + *

    Collection-returning accessors return unmodifiable views: the view returned will reflect + * changes to the graph (if the graph is mutable) but may not be modified by the user. + * + *

    The time complexity of all collection-returning accessors is O(1), since views are returned. + * + * @author James Sexton + * @author Joshua O'Madadhain + * @author Omar Darwish + * @param Node parameter type + * @param Edge parameter type + */ +class ConfigurableNetwork + extends AbstractNetwork { + private final boolean isDirected; + private final boolean allowsParallelEdges; + private final boolean allowsSelfLoops; + private final ElementOrder nodeOrder; + private final ElementOrder edgeOrder; + + protected final MapIteratorCache> nodeConnections; + + // We could make this a Map>. It would make incidentNodes(edge) slightly + // faster, but also make Networks consume 5 to 20+% (increasing with average degree) more memory. + protected final MapIteratorCache edgeToReferenceNode; // referenceNode == source if directed + + /** Constructs a graph with the properties specified in {@code builder}. */ + ConfigurableNetwork(NetworkBuilder builder) { + this( + builder, + builder.nodeOrder.>createMap( + builder.expectedNodeCount.or(DEFAULT_NODE_COUNT)), + builder.edgeOrder.createMap(builder.expectedEdgeCount.or(DEFAULT_EDGE_COUNT))); + } + + /** + * Constructs a graph with the properties specified in {@code builder}, initialized with the given + * node and edge maps. + */ + ConfigurableNetwork( + NetworkBuilder builder, + Map> nodeConnections, + Map edgeToReferenceNode) { + this.isDirected = builder.directed; + this.allowsParallelEdges = builder.allowsParallelEdges; + this.allowsSelfLoops = builder.allowsSelfLoops; + this.nodeOrder = builder.nodeOrder.cast(); + this.edgeOrder = builder.edgeOrder.cast(); + // Prefer the heavier "MapRetrievalCache" for nodes if lookup is expensive. This optimizes + // methods that access the same node(s) repeatedly, such as Graphs.removeEdgesConnecting(). + this.nodeConnections = + (nodeConnections instanceof TreeMap) + ? new MapRetrievalCache>(nodeConnections) + : new MapIteratorCache>(nodeConnections); + this.edgeToReferenceNode = new MapIteratorCache<>(edgeToReferenceNode); + } + + @Override + public Set nodes() { + return nodeConnections.unmodifiableKeySet(); + } + + @Override + public Set edges() { + return edgeToReferenceNode.unmodifiableKeySet(); + } + + @Override + public boolean isDirected() { + return isDirected; + } + + @Override + public boolean allowsParallelEdges() { + return allowsParallelEdges; + } + + @Override + public boolean allowsSelfLoops() { + return allowsSelfLoops; + } + + @Override + public ElementOrder nodeOrder() { + return nodeOrder; + } + + @Override + public ElementOrder edgeOrder() { + return edgeOrder; + } + + @Override + public Set incidentEdges(N node) { + return checkedConnections(node).incidentEdges(); + } + + @Override + public EndpointPair incidentNodes(E edge) { + N nodeU = checkedReferenceNode(edge); + // requireNonNull is safe because checkedReferenceNode made sure the edge is in the network. + N nodeV = requireNonNull(nodeConnections.get(nodeU)).adjacentNode(edge); + return EndpointPair.of(this, nodeU, nodeV); + } + + @Override + public Set adjacentNodes(N node) { + return checkedConnections(node).adjacentNodes(); + } + + @Override + public Set edgesConnecting(N nodeU, N nodeV) { + NetworkConnections connectionsU = checkedConnections(nodeU); + if (!allowsSelfLoops && nodeU == nodeV) { // just an optimization, only check reference equality + return ImmutableSet.of(); + } + checkArgument(containsNode(nodeV), NODE_NOT_IN_GRAPH, nodeV); + return connectionsU.edgesConnecting(nodeV); + } + + @Override + public Set inEdges(N node) { + return checkedConnections(node).inEdges(); + } + + @Override + public Set outEdges(N node) { + return checkedConnections(node).outEdges(); + } + + @Override + public Set predecessors(N node) { + return checkedConnections(node).predecessors(); + } + + @Override + public Set successors(N node) { + return checkedConnections(node).successors(); + } + + protected final NetworkConnections checkedConnections(N node) { + NetworkConnections connections = nodeConnections.get(node); + if (connections == null) { + checkNotNull(node); + throw new IllegalArgumentException(String.format(NODE_NOT_IN_GRAPH, node)); + } + return connections; + } + + protected final N checkedReferenceNode(E edge) { + N referenceNode = edgeToReferenceNode.get(edge); + if (referenceNode == null) { + checkNotNull(edge); + throw new IllegalArgumentException(String.format(EDGE_NOT_IN_GRAPH, edge)); + } + return referenceNode; + } + + protected final boolean containsNode(N node) { + return nodeConnections.containsKey(node); + } + + protected final boolean containsEdge(E edge) { + return edgeToReferenceNode.containsKey(edge); + } +} diff --git a/guava/src/com/google/common/graph/ConfigurableValueGraph.java b/guava/src/com/google/common/graph/ConfigurableValueGraph.java new file mode 100755 index 000000000000..cb0f2cdd67d8 --- /dev/null +++ b/guava/src/com/google/common/graph/ConfigurableValueGraph.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2016 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.graph; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.graph.GraphConstants.DEFAULT_NODE_COUNT; +import static com.google.common.graph.Graphs.checkNonNegative; + +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Configurable implementation of {@link ValueGraph} that supports the options supplied by {@link + * AbstractGraphBuilder}. + * + *

    This class maintains a map of nodes to {@link GraphConnections}. + * + *

    Collection-returning accessors return unmodifiable views: the view returned will reflect + * changes to the graph (if the graph is mutable) but may not be modified by the user. + * + *

    The time complexity of all collection-returning accessors is O(1), since views are returned. + * + * @author James Sexton + * @author Joshua O'Madadhain + * @author Omar Darwish + * @param Node parameter type + * @param Value parameter type + */ +class ConfigurableValueGraph + extends AbstractValueGraph { + private final boolean isDirected; + private final boolean allowsSelfLoops; + private final ElementOrder nodeOrder; + + protected final MapIteratorCache> nodeConnections; + + protected long edgeCount; // must be updated when edges are added or removed + + /** Constructs a graph with the properties specified in {@code builder}. */ + ConfigurableValueGraph(AbstractGraphBuilder builder) { + this( + builder, + builder.nodeOrder.>createMap( + builder.expectedNodeCount.or(DEFAULT_NODE_COUNT)), + 0L); + } + + /** + * Constructs a graph with the properties specified in {@code builder}, initialized with the given + * node map. + */ + ConfigurableValueGraph( + AbstractGraphBuilder builder, + Map> nodeConnections, + long edgeCount) { + this.isDirected = builder.directed; + this.allowsSelfLoops = builder.allowsSelfLoops; + this.nodeOrder = builder.nodeOrder.cast(); + // Prefer the heavier "MapRetrievalCache" for nodes if lookup is expensive. + this.nodeConnections = + (nodeConnections instanceof TreeMap) + ? new MapRetrievalCache>(nodeConnections) + : new MapIteratorCache>(nodeConnections); + this.edgeCount = checkNonNegative(edgeCount); + } + + @Override + public Set nodes() { + return nodeConnections.unmodifiableKeySet(); + } + + @Override + public boolean isDirected() { + return isDirected; + } + + @Override + public boolean allowsSelfLoops() { + return allowsSelfLoops; + } + + @Override + public ElementOrder nodeOrder() { + return nodeOrder; + } + + @Override + public Set adjacentNodes(N node) { + return checkedConnections(node).adjacentNodes(); + } + + @Override + public Set predecessors(N node) { + return checkedConnections(node).predecessors(); + } + + @Override + public Set successors(N node) { + return checkedConnections(node).successors(); + } + + @Override + public boolean hasEdgeConnecting(N nodeU, N nodeV) { + return hasEdgeConnecting_internal(checkNotNull(nodeU), checkNotNull(nodeV)); + } + + @Override + public boolean hasEdgeConnecting(EndpointPair endpoints) { + checkNotNull(endpoints); + return isOrderingCompatible(endpoints) + && hasEdgeConnecting_internal(endpoints.nodeU(), endpoints.nodeV()); + } + + @Override + public @Nullable V edgeValueOrDefault(N nodeU, N nodeV, @Nullable V defaultValue) { + return edgeValueOrDefault_internal(checkNotNull(nodeU), checkNotNull(nodeV), defaultValue); + } + + @Override + public @Nullable V edgeValueOrDefault(EndpointPair endpoints, @Nullable V defaultValue) { + validateEndpoints(endpoints); + return edgeValueOrDefault_internal(endpoints.nodeU(), endpoints.nodeV(), defaultValue); + } + + @Override + protected long edgeCount() { + return edgeCount; + } + + protected final GraphConnections checkedConnections(N node) { + GraphConnections connections = nodeConnections.get(node); + if (connections == null) { + checkNotNull(node); + throw new IllegalArgumentException("Node " + node + " is not an element of this graph."); + } + return connections; + } + + protected final boolean containsNode(N node) { + return nodeConnections.containsKey(node); + } + + protected final boolean hasEdgeConnecting_internal(N nodeU, N nodeV) { + GraphConnections connectionsU = nodeConnections.get(nodeU); + return (connectionsU != null) && connectionsU.successors().contains(nodeV); + } + + protected final @Nullable V edgeValueOrDefault_internal( + N nodeU, N nodeV, @Nullable V defaultValue) { + GraphConnections connectionsU = nodeConnections.get(nodeU); + V value = (connectionsU == null) ? null : connectionsU.value(nodeV); + // TODO(cpovirk): Why does our prototype checker (but not CF) reject a ternary? + if (value == null) { + return defaultValue; + } else { + return value; + } + } +} diff --git a/guava/src/com/google/common/graph/DirectedGraphConnections.java b/guava/src/com/google/common/graph/DirectedGraphConnections.java index 3838bcfe8b74..5eff782ae45a 100644 --- a/guava/src/com/google/common/graph/DirectedGraphConnections.java +++ b/guava/src/com/google/common/graph/DirectedGraphConnections.java @@ -40,6 +40,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -50,7 +51,8 @@ * @param Node parameter type * @param Value parameter type */ -final class DirectedGraphConnections implements GraphConnections { +final class DirectedGraphConnections + implements GraphConnections { /** * A wrapper class to indicate a node is both a predecessor and successor while still providing * the successor value. @@ -69,20 +71,20 @@ private static final class PredAndSucc { *

    There can be two types of connections (predecessor and successor), which is represented by * the two implementations. */ - private abstract static class NodeConnection { + private abstract static class NodeConnection { final N node; NodeConnection(N node) { this.node = checkNotNull(node); } - static final class Pred extends NodeConnection { + static final class Pred extends NodeConnection { Pred(N node) { super(node); } @Override - public boolean equals(Object that) { + public boolean equals(@Nullable Object that) { if (that instanceof Pred) { return this.node.equals(((Pred) that).node); } else { @@ -97,13 +99,13 @@ public int hashCode() { } } - static final class Succ extends NodeConnection { + static final class Succ extends NodeConnection { Succ(N node) { super(node); } @Override - public boolean equals(Object that) { + public boolean equals(@Nullable Object that) { if (that instanceof Succ) { return this.node.equals(((Succ) that).node); } else { @@ -133,7 +135,7 @@ public int hashCode() { * LinkedHashMap combines two such edges into a single node-value pair, even though the edges may * not have been inserted consecutively. */ - @Nullable private final List> orderedNodeConnections; + private final @Nullable List> orderedNodeConnections; private int predecessorCount; private int successorCount; @@ -152,7 +154,8 @@ private DirectedGraphConnections( && successorCount <= adjacentNodeValues.size()); } - static DirectedGraphConnections of(ElementOrder incidentEdgeOrder) { + static DirectedGraphConnections of( + ElementOrder incidentEdgeOrder) { // We store predecessors and successors in the same map, so double the initial capacity. int initialCapacity = INNER_CAPACITY * 2; @@ -175,8 +178,11 @@ static DirectedGraphConnections of(ElementOrder incidentEdgeOrde /* successorCount = */ 0); } - static DirectedGraphConnections ofImmutable( - N thisNode, Iterable> incidentEdges, Function successorNodeToValueFn) { + static + DirectedGraphConnections ofImmutable( + N thisNode, + Iterable> incidentEdges, + Function successorNodeToValueFn) { checkNotNull(thisNode); checkNotNull(successorNodeToValueFn); @@ -425,7 +431,7 @@ protected EndpointPair computeNext() { @SuppressWarnings("unchecked") @Override - public V value(N node) { + public @Nullable V value(N node) { checkNotNull(node); Object value = adjacentNodeValues.get(node); if (value == PRED) { @@ -434,7 +440,7 @@ public V value(N node) { if (value instanceof PredAndSucc) { return (V) ((PredAndSucc) value).successorValue; } - return (V) value; + return (@Nullable V) value; } @SuppressWarnings("unchecked") @@ -466,7 +472,7 @@ public void removePredecessor(N node) { @SuppressWarnings("unchecked") @Override - public V removeSuccessor(Object node) { + public @Nullable V removeSuccessor(Object node) { checkNotNull(node); Object previousValue = adjacentNodeValues.get(node); Object removedValue; @@ -489,7 +495,7 @@ public V removeSuccessor(Object node) { } } - return (V) removedValue; + return (@Nullable V) removedValue; } @Override @@ -522,7 +528,7 @@ public void addPredecessor(N node, V unused) { @SuppressWarnings("unchecked") @Override - public V addSuccessor(N node, V value) { + public @Nullable V addSuccessor(N node, V value) { Object previousValue = adjacentNodeValues.put(node, value); Object previousSuccessor; @@ -546,7 +552,7 @@ public V addSuccessor(N node, V value) { } } - return (V) previousSuccessor; + return (@Nullable V) previousSuccessor; } private static boolean isPredecessor(@Nullable Object value) { diff --git a/guava/src/com/google/common/graph/DirectedMultiNetworkConnections.java b/guava/src/com/google/common/graph/DirectedMultiNetworkConnections.java index 4a560aefbd1f..535d91dc5e74 100644 --- a/guava/src/com/google/common/graph/DirectedMultiNetworkConnections.java +++ b/guava/src/com/google/common/graph/DirectedMultiNetworkConnections.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,27 +40,30 @@ * @param Node parameter type * @param Edge parameter type */ -final class DirectedMultiNetworkConnections extends AbstractDirectedNetworkConnections { +final class DirectedMultiNetworkConnections + extends AbstractDirectedNetworkConnections { private DirectedMultiNetworkConnections( Map inEdges, Map outEdges, int selfLoopCount) { super(inEdges, outEdges, selfLoopCount); } - static DirectedMultiNetworkConnections of() { + static + DirectedMultiNetworkConnections of() { return new DirectedMultiNetworkConnections<>( new HashMap(INNER_CAPACITY, INNER_LOAD_FACTOR), new HashMap(INNER_CAPACITY, INNER_LOAD_FACTOR), 0); } - static DirectedMultiNetworkConnections ofImmutable( - Map inEdges, Map outEdges, int selfLoopCount) { + static + DirectedMultiNetworkConnections ofImmutable( + Map inEdges, Map outEdges, int selfLoopCount) { return new DirectedMultiNetworkConnections<>( ImmutableMap.copyOf(inEdges), ImmutableMap.copyOf(outEdges), selfLoopCount); } - @LazyInit private transient Reference> predecessorsReference; + @LazyInit private transient @Nullable Reference> predecessorsReference; @Override public Set predecessors() { @@ -75,7 +79,7 @@ private Multiset predecessorsMultiset() { return predecessors; } - @LazyInit private transient Reference> successorsReference; + @LazyInit private transient @Nullable Reference> successorsReference; @Override public Set successors() { @@ -139,7 +143,8 @@ public void addOutEdge(E edge, N node) { } } - private static @Nullable T getReference(@Nullable Reference reference) { + private static @Nullable T getReference( + @Nullable Reference reference) { return (reference == null) ? null : reference.get(); } } diff --git a/guava/src/com/google/common/graph/DirectedNetworkConnections.java b/guava/src/com/google/common/graph/DirectedNetworkConnections.java index 2a0b010d0998..7b5133a89e67 100644 --- a/guava/src/com/google/common/graph/DirectedNetworkConnections.java +++ b/guava/src/com/google/common/graph/DirectedNetworkConnections.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; /** * An implementation of {@link NetworkConnections} for directed networks. @@ -32,20 +33,23 @@ * @param Node parameter type * @param Edge parameter type */ -final class DirectedNetworkConnections extends AbstractDirectedNetworkConnections { +final class DirectedNetworkConnections + extends AbstractDirectedNetworkConnections { protected DirectedNetworkConnections( Map inEdgeMap, Map outEdgeMap, int selfLoopCount) { super(inEdgeMap, outEdgeMap, selfLoopCount); } - static DirectedNetworkConnections of() { + static + DirectedNetworkConnections of() { return new DirectedNetworkConnections<>( HashBiMap.create(EXPECTED_DEGREE), HashBiMap.create(EXPECTED_DEGREE), 0); } - static DirectedNetworkConnections ofImmutable( - Map inEdges, Map outEdges, int selfLoopCount) { + static + DirectedNetworkConnections ofImmutable( + Map inEdges, Map outEdges, int selfLoopCount) { return new DirectedNetworkConnections<>( ImmutableBiMap.copyOf(inEdges), ImmutableBiMap.copyOf(outEdges), selfLoopCount); } diff --git a/guava/src/com/google/common/graph/EdgesConnecting.java b/guava/src/com/google/common/graph/EdgesConnecting.java index 1c4673544238..ea8df7e8e359 100644 --- a/guava/src/com/google/common/graph/EdgesConnecting.java +++ b/guava/src/com/google/common/graph/EdgesConnecting.java @@ -23,6 +23,7 @@ import com.google.common.collect.UnmodifiableIterator; import java.util.AbstractSet; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -34,7 +35,7 @@ * @author James Sexton * @param Edge parameter type */ -final class EdgesConnecting extends AbstractSet { +final class EdgesConnecting extends AbstractSet { private final Map nodeToOutEdge; private final Object targetNode; diff --git a/guava/src/com/google/common/graph/ElementOrder.java b/guava/src/com/google/common/graph/ElementOrder.java index 257bdd653c52..b5d6b43674ee 100644 --- a/guava/src/com/google/common/graph/ElementOrder.java +++ b/guava/src/com/google/common/graph/ElementOrder.java @@ -28,6 +28,7 @@ import com.google.errorprone.annotations.Immutable; import java.util.Comparator; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -46,7 +47,7 @@ */ @Beta @Immutable -public final class ElementOrder { +public final class ElementOrder { private final Type type; @SuppressWarnings("Immutable") // Hopefully the comparator provided is immutable! @@ -77,7 +78,7 @@ private ElementOrder(Type type, @Nullable Comparator comparator) { } /** Returns an instance which specifies that no ordering is guaranteed. */ - public static ElementOrder unordered() { + public static ElementOrder unordered() { return new ElementOrder(Type.UNORDERED, null); } @@ -117,12 +118,12 @@ public static ElementOrder unordered() { * * @since 29.0 */ - public static ElementOrder stable() { + public static ElementOrder stable() { return new ElementOrder(Type.STABLE, null); } /** Returns an instance which specifies that insertion ordering is guaranteed. */ - public static ElementOrder insertion() { + public static ElementOrder insertion() { return new ElementOrder(Type.INSERTION, null); } @@ -137,7 +138,7 @@ public static > ElementOrder natural() { * Returns an instance which specifies that the ordering of the elements is guaranteed to be * determined by {@code comparator}. */ - public static ElementOrder sorted(Comparator comparator) { + public static ElementOrder sorted(Comparator comparator) { return new ElementOrder(Type.SORTED, checkNotNull(comparator)); } diff --git a/guava/src/com/google/common/graph/EndpointPair.java b/guava/src/com/google/common/graph/EndpointPair.java index c87663474188..9de8b166c4d3 100644 --- a/guava/src/com/google/common/graph/EndpointPair.java +++ b/guava/src/com/google/common/graph/EndpointPair.java @@ -24,6 +24,7 @@ import com.google.common.collect.Iterators; import com.google.common.collect.UnmodifiableIterator; import com.google.errorprone.annotations.Immutable; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,7 +40,7 @@ */ @Beta @Immutable(containerOf = {"N"}) -public abstract class EndpointPair implements Iterable { +public abstract class EndpointPair implements Iterable { private final N nodeU; private final N nodeV; @@ -49,23 +50,23 @@ private EndpointPair(N nodeU, N nodeV) { } /** Returns an {@link EndpointPair} representing the endpoints of a directed edge. */ - public static EndpointPair ordered(N source, N target) { + public static EndpointPair ordered(N source, N target) { return new Ordered(source, target); } /** Returns an {@link EndpointPair} representing the endpoints of an undirected edge. */ - public static EndpointPair unordered(N nodeU, N nodeV) { + public static EndpointPair unordered(N nodeU, N nodeV) { // Swap nodes on purpose to prevent callers from relying on the "ordering" of an unordered pair. return new Unordered(nodeV, nodeU); } /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code graph}. */ - static EndpointPair of(Graph graph, N nodeU, N nodeV) { + static EndpointPair of(Graph graph, N nodeU, N nodeV) { return graph.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV); } /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code network}. */ - static EndpointPair of(Network network, N nodeU, N nodeV) { + static EndpointPair of(Network network, N nodeU, N nodeV) { return network.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV); } @@ -142,7 +143,7 @@ public final UnmodifiableIterator iterator() { @Override public abstract int hashCode(); - private static final class Ordered extends EndpointPair { + private static final class Ordered extends EndpointPair { private Ordered(N source, N target) { super(source, target); } @@ -190,7 +191,7 @@ public String toString() { } } - private static final class Unordered extends EndpointPair { + private static final class Unordered extends EndpointPair { private Unordered(N nodeU, N nodeV) { super(nodeU, nodeV); } diff --git a/guava/src/com/google/common/graph/EndpointPairIterator.java b/guava/src/com/google/common/graph/EndpointPairIterator.java index c4e6e073e93d..e2da21dff127 100644 --- a/guava/src/com/google/common/graph/EndpointPairIterator.java +++ b/guava/src/com/google/common/graph/EndpointPairIterator.java @@ -17,26 +17,31 @@ package com.google.common.graph; import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.Iterator; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A class to facilitate the set returned by {@link Graph#edges()}. * * @author James Sexton */ -abstract class EndpointPairIterator extends AbstractIterator> { +abstract class EndpointPairIterator + extends AbstractIterator> { private final BaseGraph graph; private final Iterator nodeIterator; - protected N node = null; // null is safe as an initial value because graphs don't allow null nodes + protected @Nullable N node = + null; // null is safe as an initial value because graphs don't allow null nodes protected Iterator successorIterator = ImmutableSet.of().iterator(); - static EndpointPairIterator of(BaseGraph graph) { + static EndpointPairIterator of(BaseGraph graph) { return graph.isDirected() ? new Directed(graph) : new Undirected(graph); } @@ -63,7 +68,7 @@ protected final boolean advance() { * If the graph is directed, each ordered [source, target] pair will be visited once if there is * an edge connecting them. */ - private static final class Directed extends EndpointPairIterator { + private static final class Directed extends EndpointPairIterator { private Directed(BaseGraph graph) { super(graph); } @@ -72,7 +77,8 @@ private Directed(BaseGraph graph) { protected EndpointPair computeNext() { while (true) { if (successorIterator.hasNext()) { - return EndpointPair.ordered(node, successorIterator.next()); + // requireNonNull is safe because successorIterator is empty until we set this.node. + return EndpointPair.ordered(requireNonNull(node), successorIterator.next()); } if (!advance()) { return endOfData(); @@ -107,8 +113,9 @@ protected EndpointPair computeNext() { * Visited Nodes = {N1, N2, N3, N4} * */ - private static final class Undirected extends EndpointPairIterator { - private Set visitedNodes; + private static final class Undirected extends EndpointPairIterator { + // It's a little weird that we add `null` to this, but it makes for slightly simpler code. + private @Nullable Set<@Nullable N> visitedNodes; private Undirected(BaseGraph graph) { super(graph); @@ -118,10 +125,16 @@ private Undirected(BaseGraph graph) { @Override protected EndpointPair computeNext() { while (true) { + /* + * requireNonNull is safe because visitedNodes isn't cleared until this method calls + * endOfData() (after which this method is never called again). + */ + requireNonNull(visitedNodes); while (successorIterator.hasNext()) { N otherNode = successorIterator.next(); - if (!visitedNodes.contains(otherNode)) { - return EndpointPair.unordered(node, otherNode); + if (!requireNonNull(visitedNodes).contains(otherNode)) { + // requireNonNull is safe because successorIterator is empty until we set this.node. + return EndpointPair.unordered(requireNonNull(node), otherNode); } } // Add to visited set *after* processing neighbors so we still include self-loops. diff --git a/guava/src/com/google/common/graph/ForwardingGraph.java b/guava/src/com/google/common/graph/ForwardingGraph.java index 4a3ab8c77b3b..0ae1406a371b 100644 --- a/guava/src/com/google/common/graph/ForwardingGraph.java +++ b/guava/src/com/google/common/graph/ForwardingGraph.java @@ -17,6 +17,7 @@ package com.google.common.graph; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A class to allow {@link Graph} implementations to be backed by a {@link BaseGraph}. This is not @@ -24,7 +25,7 @@ * * @author James Sexton */ -abstract class ForwardingGraph extends AbstractGraph { +abstract class ForwardingGraph extends AbstractGraph { protected abstract BaseGraph delegate(); diff --git a/guava/src/com/google/common/graph/ForwardingNetwork.java b/guava/src/com/google/common/graph/ForwardingNetwork.java index 76347b17a7a0..b6aeedf32b70 100644 --- a/guava/src/com/google/common/graph/ForwardingNetwork.java +++ b/guava/src/com/google/common/graph/ForwardingNetwork.java @@ -18,6 +18,8 @@ import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A class to allow {@link Network} implementations to be backed by a provided delegate. This is not @@ -26,7 +28,8 @@ * @author James Sexton * @author Joshua O'Madadhain */ -abstract class ForwardingNetwork extends AbstractNetwork { +abstract class ForwardingNetwork + extends AbstractNetwork { protected abstract Network delegate(); @@ -141,12 +144,12 @@ public Optional edgeConnecting(EndpointPair endpoints) { } @Override - public E edgeConnectingOrNull(N nodeU, N nodeV) { + public @Nullable E edgeConnectingOrNull(N nodeU, N nodeV) { return delegate().edgeConnectingOrNull(nodeU, nodeV); } @Override - public E edgeConnectingOrNull(EndpointPair endpoints) { + public @Nullable E edgeConnectingOrNull(EndpointPair endpoints) { return delegate().edgeConnectingOrNull(endpoints); } diff --git a/guava/src/com/google/common/graph/ForwardingValueGraph.java b/guava/src/com/google/common/graph/ForwardingValueGraph.java index 8db773f923ef..5060aa83f031 100644 --- a/guava/src/com/google/common/graph/ForwardingValueGraph.java +++ b/guava/src/com/google/common/graph/ForwardingValueGraph.java @@ -18,6 +18,7 @@ import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -27,7 +28,8 @@ * @author James Sexton * @author Joshua O'Madadhain */ -abstract class ForwardingValueGraph extends AbstractValueGraph { +abstract class ForwardingValueGraph + extends AbstractValueGraph { protected abstract ValueGraph delegate(); diff --git a/guava/src/com/google/common/graph/Graph.java b/guava/src/com/google/common/graph/Graph.java index 84f9695c45ae..a6e876dff8be 100644 --- a/guava/src/com/google/common/graph/Graph.java +++ b/guava/src/com/google/common/graph/Graph.java @@ -17,9 +17,9 @@ package com.google.common.graph; import com.google.common.annotations.Beta; -import com.google.errorprone.annotations.DoNotMock; import java.util.Collection; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -102,8 +102,7 @@ * @since 20.0 */ @Beta -@DoNotMock("Use GraphBuilder to create a real instance") -public interface Graph extends BaseGraph { +public interface Graph extends BaseGraph { // // Graph-level accessors // diff --git a/guava/src/com/google/common/graph/GraphBuilder.java b/guava/src/com/google/common/graph/GraphBuilder.java index f00d7b1f93be..b8587981107c 100644 --- a/guava/src/com/google/common/graph/GraphBuilder.java +++ b/guava/src/com/google/common/graph/GraphBuilder.java @@ -22,7 +22,7 @@ import com.google.common.annotations.Beta; import com.google.common.base.Optional; -import com.google.errorprone.annotations.DoNotMock; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A builder for constructing instances of {@link MutableGraph} or {@link ImmutableGraph} with @@ -63,8 +63,7 @@ * @since 20.0 */ @Beta -@DoNotMock -public final class GraphBuilder extends AbstractGraphBuilder { +public final class GraphBuilder extends AbstractGraphBuilder { /** Creates a new instance with the specified edge directionality. */ private GraphBuilder(boolean directed) { @@ -88,7 +87,7 @@ public static GraphBuilder undirected() { * such as {@link Graph#isDirected()}. Other properties, such as {@link #expectedNodeCount(int)}, * are not set in the new builder. */ - public static GraphBuilder from(Graph graph) { + public static GraphBuilder from(Graph graph) { return new GraphBuilder(graph.isDirected()) .allowsSelfLoops(graph.allowsSelfLoops()) .nodeOrder(graph.nodeOrder()) diff --git a/guava/src/com/google/common/graph/GraphConnections.java b/guava/src/com/google/common/graph/GraphConnections.java index bed5508a1c8e..34ccb3cbe75e 100644 --- a/guava/src/com/google/common/graph/GraphConnections.java +++ b/guava/src/com/google/common/graph/GraphConnections.java @@ -19,6 +19,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Iterator; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -29,7 +30,7 @@ * @param Node parameter type * @param Value parameter type */ -interface GraphConnections { +interface GraphConnections { Set adjacentNodes(); @@ -59,6 +60,7 @@ interface GraphConnections { * the edge connecting the two nodes. */ @CanIgnoreReturnValue + @Nullable V removeSuccessor(N node); /** @@ -73,5 +75,6 @@ interface GraphConnections { * the value previously associated with the edge connecting the two nodes. */ @CanIgnoreReturnValue + @Nullable V addSuccessor(N node, V value); } diff --git a/guava/src/com/google/common/graph/Graphs.java b/guava/src/com/google/common/graph/Graphs.java index 35f0efecf878..369427245453 100644 --- a/guava/src/com/google/common/graph/Graphs.java +++ b/guava/src/com/google/common/graph/Graphs.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.graph.GraphConstants.NODE_NOT_IN_GRAPH; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.base.Function; @@ -33,6 +34,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -56,7 +58,7 @@ private Graphs() {} * *

    This method will detect any non-empty cycle, including self-loops (a cycle of length 1). */ - public static boolean hasCycle(Graph graph) { + public static boolean hasCycle(Graph graph) { int numEdges = graph.edges().size(); if (numEdges == 0) { return false; // An edge-free graph is acyclic by definition. @@ -98,7 +100,7 @@ public static boolean hasCycle(Network network) { * already visited (following only outgoing edges and without reusing edges), we know there's a * cycle in the graph. */ - private static boolean subgraphHasCycle( + private static boolean subgraphHasCycle( Graph graph, Map visitedNodes, N node, @Nullable N previousNode) { NodeVisitState state = visitedNodes.get(node); if (state == NodeVisitState.COMPLETE) { @@ -145,7 +147,7 @@ private static boolean canTraverseWithoutReusingEdge( * be updated after modifications to {@code graph}. */ // TODO(b/31438252): Consider potential optimizations for this algorithm. - public static Graph transitiveClosure(Graph graph) { + public static Graph transitiveClosure(Graph graph) { MutableGraph transitiveClosure = GraphBuilder.from(graph).allowsSelfLoops(true).build(); // Every node is, at a minimum, reachable from itself. Since the resulting transitive closure // will have no isolated nodes, we can skip adding nodes explicitly and let putEdge() do it. @@ -189,7 +191,7 @@ public static Graph transitiveClosure(Graph graph) { * * @throws IllegalArgumentException if {@code node} is not present in {@code graph} */ - public static Set reachableNodes(Graph graph, N node) { + public static Set reachableNodes(Graph graph, N node) { checkArgument(graph.nodes().contains(node), NODE_NOT_IN_GRAPH, node); return ImmutableSet.copyOf(Traverser.forGraph(graph).breadthFirst(node)); } @@ -202,7 +204,7 @@ public static Set reachableNodes(Graph graph, N node) { * Returns a view of {@code graph} with the direction (if any) of every edge reversed. All other * properties remain intact, and further updates to {@code graph} will be reflected in the view. */ - public static Graph transpose(Graph graph) { + public static Graph transpose(Graph graph) { if (!graph.isDirected()) { return graph; // the transpose of an undirected graph is an identical graph } @@ -218,7 +220,8 @@ public static Graph transpose(Graph graph) { * Returns a view of {@code graph} with the direction (if any) of every edge reversed. All other * properties remain intact, and further updates to {@code graph} will be reflected in the view. */ - public static ValueGraph transpose(ValueGraph graph) { + public static ValueGraph transpose( + ValueGraph graph) { if (!graph.isDirected()) { return graph; // the transpose of an undirected graph is an identical graph } @@ -234,7 +237,8 @@ public static ValueGraph transpose(ValueGraph graph) { * Returns a view of {@code network} with the direction (if any) of every edge reversed. All other * properties remain intact, and further updates to {@code network} will be reflected in the view. */ - public static Network transpose(Network network) { + public static Network transpose( + Network network) { if (!network.isDirected()) { return network; // the transpose of an undirected network is an identical network } @@ -246,7 +250,7 @@ public static Network transpose(Network network) { return new TransposedNetwork<>(network); } - static EndpointPair transpose(EndpointPair endpoints) { + static EndpointPair transpose(EndpointPair endpoints) { if (endpoints.isOrdered()) { return EndpointPair.ordered(endpoints.target(), endpoints.source()); } @@ -255,7 +259,7 @@ static EndpointPair transpose(EndpointPair endpoints) { // NOTE: this should work as long as the delegate graph's implementation of edges() (like that of // AbstractGraph) derives its behavior from calling successors(). - private static class TransposedGraph extends ForwardingGraph { + private static class TransposedGraph extends ForwardingGraph { private final Graph graph; TransposedGraph(Graph graph) { @@ -317,7 +321,8 @@ public boolean hasEdgeConnecting(EndpointPair endpoints) { // NOTE: this should work as long as the delegate graph's implementation of edges() (like that of // AbstractValueGraph) derives its behavior from calling successors(). - private static class TransposedValueGraph extends ForwardingValueGraph { + private static class TransposedValueGraph + extends ForwardingValueGraph { private final ValueGraph graph; TransposedValueGraph(ValueGraph graph) { @@ -380,7 +385,8 @@ public Optional edgeValue(EndpointPair endpoints) { } } - private static class TransposedNetwork extends ForwardingNetwork { + private static class TransposedNetwork + extends ForwardingNetwork { private final Network network; TransposedNetwork(Network network) { @@ -449,12 +455,12 @@ public Optional edgeConnecting(EndpointPair endpoints) { } @Override - public E edgeConnectingOrNull(N nodeU, N nodeV) { + public @Nullable E edgeConnectingOrNull(N nodeU, N nodeV) { return delegate().edgeConnectingOrNull(nodeV, nodeU); // transpose } @Override - public E edgeConnectingOrNull(EndpointPair endpoints) { + public @Nullable E edgeConnectingOrNull(EndpointPair endpoints) { return delegate().edgeConnectingOrNull(transpose(endpoints)); } @@ -478,7 +484,8 @@ public boolean hasEdgeConnecting(EndpointPair endpoints) { * * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph */ - public static MutableGraph inducedSubgraph(Graph graph, Iterable nodes) { + public static MutableGraph inducedSubgraph( + Graph graph, Iterable nodes) { MutableGraph subgraph = (nodes instanceof Collection) ? GraphBuilder.from(graph).expectedNodeCount(((Collection) nodes).size()).build() @@ -504,8 +511,8 @@ public static MutableGraph inducedSubgraph(Graph graph, Iterable MutableValueGraph inducedSubgraph( - ValueGraph graph, Iterable nodes) { + public static + MutableValueGraph inducedSubgraph(ValueGraph graph, Iterable nodes) { MutableValueGraph subgraph = (nodes instanceof Collection) ? ValueGraphBuilder.from(graph).expectedNodeCount(((Collection) nodes).size()).build() @@ -516,8 +523,11 @@ public static MutableValueGraph inducedSubgraph( for (N node : subgraph.nodes()) { for (N successorNode : graph.successors(node)) { if (subgraph.nodes().contains(successorNode)) { + // requireNonNull is safe because the endpoint pair comes from the graph. subgraph.putEdgeValue( - node, successorNode, graph.edgeValueOrDefault(node, successorNode, null)); + node, + successorNode, + requireNonNull(graph.edgeValueOrDefault(node, successorNode, null))); } } } @@ -532,8 +542,8 @@ public static MutableValueGraph inducedSubgraph( * * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph */ - public static MutableNetwork inducedSubgraph( - Network network, Iterable nodes) { + public static + MutableNetwork inducedSubgraph(Network network, Iterable nodes) { MutableNetwork subgraph = (nodes instanceof Collection) ? NetworkBuilder.from(network).expectedNodeCount(((Collection) nodes).size()).build() @@ -553,7 +563,7 @@ public static MutableNetwork inducedSubgraph( } /** Creates a mutable copy of {@code graph} with the same nodes and edges. */ - public static MutableGraph copyOf(Graph graph) { + public static MutableGraph copyOf(Graph graph) { MutableGraph copy = GraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); for (N node : graph.nodes()) { copy.addNode(node); @@ -565,21 +575,26 @@ public static MutableGraph copyOf(Graph graph) { } /** Creates a mutable copy of {@code graph} with the same nodes, edges, and edge values. */ - public static MutableValueGraph copyOf(ValueGraph graph) { + public static + MutableValueGraph copyOf(ValueGraph graph) { MutableValueGraph copy = ValueGraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); for (N node : graph.nodes()) { copy.addNode(node); } for (EndpointPair edge : graph.edges()) { + // requireNonNull is safe because the endpoint pair comes from the graph. copy.putEdgeValue( - edge.nodeU(), edge.nodeV(), graph.edgeValueOrDefault(edge.nodeU(), edge.nodeV(), null)); + edge.nodeU(), + edge.nodeV(), + requireNonNull(graph.edgeValueOrDefault(edge.nodeU(), edge.nodeV(), null))); } return copy; } /** Creates a mutable copy of {@code network} with the same nodes and edges. */ - public static MutableNetwork copyOf(Network network) { + public static MutableNetwork copyOf( + Network network) { MutableNetwork copy = NetworkBuilder.from(network) .expectedNodeCount(network.nodes().size()) diff --git a/guava/src/com/google/common/graph/ImmutableGraph.java b/guava/src/com/google/common/graph/ImmutableGraph.java index 4027ca83de29..67f2d70cf97b 100644 --- a/guava/src/com/google/common/graph/ImmutableGraph.java +++ b/guava/src/com/google/common/graph/ImmutableGraph.java @@ -26,6 +26,7 @@ import com.google.common.graph.GraphConstants.Presence; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A {@link Graph} whose elements and structural relationships will never change. Instances of this @@ -45,7 +46,7 @@ */ @Beta @Immutable(containerOf = {"N"}) -public class ImmutableGraph extends ForwardingGraph { +public class ImmutableGraph extends ForwardingGraph { @SuppressWarnings("Immutable") // The backing graph must be immutable. private final BaseGraph backingGraph; @@ -54,7 +55,7 @@ public class ImmutableGraph extends ForwardingGraph { } /** Returns an immutable copy of {@code graph}. */ - public static ImmutableGraph copyOf(Graph graph) { + public static ImmutableGraph copyOf(Graph graph) { return (graph instanceof ImmutableGraph) ? (ImmutableGraph) graph : new ImmutableGraph( @@ -68,7 +69,7 @@ public static ImmutableGraph copyOf(Graph graph) { * @deprecated no need to use this */ @Deprecated - public static ImmutableGraph copyOf(ImmutableGraph graph) { + public static ImmutableGraph copyOf(ImmutableGraph graph) { return checkNotNull(graph); } @@ -77,8 +78,8 @@ public ElementOrder incidentEdgeOrder() { return ElementOrder.stable(); } - private static ImmutableMap> getNodeConnections( - Graph graph) { + private static + ImmutableMap> getNodeConnections(Graph graph) { // ImmutableMap.Builder maintains the order of the elements as inserted, so the map will have // whatever ordering the graph's nodes do, so ImmutableSortedMap is unnecessary even if the // input nodes are sorted. @@ -90,7 +91,8 @@ private static ImmutableMap> getNodeConnect } @SuppressWarnings("unchecked") - private static GraphConnections connectionsOf(Graph graph, N node) { + private static GraphConnections connectionsOf( + Graph graph, N node) { Function edgeValueFn = (Function) Functions.constant(Presence.EDGE_EXISTS); return graph.isDirected() @@ -125,7 +127,7 @@ protected BaseGraph delegate() { * * @since 28.0 */ - public static class Builder { + public static class Builder { private final MutableGraph mutableGraph; diff --git a/guava/src/com/google/common/graph/ImmutableNetwork.java b/guava/src/com/google/common/graph/ImmutableNetwork.java index b35d7220817d..bfb083fcaa31 100644 --- a/guava/src/com/google/common/graph/ImmutableNetwork.java +++ b/guava/src/com/google/common/graph/ImmutableNetwork.java @@ -25,6 +25,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A {@link Network} whose elements and structural relationships will never change. Instances of @@ -46,7 +47,8 @@ @Beta @Immutable(containerOf = {"N", "E"}) @SuppressWarnings("Immutable") // Extends StandardNetwork but uses ImmutableMaps. -public final class ImmutableNetwork extends StandardNetwork { +public final class ImmutableNetwork + extends StandardNetwork { private ImmutableNetwork(Network network) { super( @@ -54,7 +56,8 @@ private ImmutableNetwork(Network network) { } /** Returns an immutable copy of {@code network}. */ - public static ImmutableNetwork copyOf(Network network) { + public static + ImmutableNetwork copyOf(Network network) { return (network instanceof ImmutableNetwork) ? (ImmutableNetwork) network : new ImmutableNetwork(network); @@ -66,7 +69,8 @@ public static ImmutableNetwork copyOf(Network network) { * @deprecated no need to use this */ @Deprecated - public static ImmutableNetwork copyOf(ImmutableNetwork network) { + public static + ImmutableNetwork copyOf(ImmutableNetwork network) { return checkNotNull(network); } @@ -75,7 +79,8 @@ public ImmutableGraph asGraph() { return new ImmutableGraph(super.asGraph()); // safe because the view is effectively immutable } - private static Map> getNodeConnections(Network network) { + private static + Map> getNodeConnections(Network network) { // ImmutableMap.Builder maintains the order of the elements as inserted, so the map will have // whatever ordering the network's nodes do, so ImmutableSortedMap is unnecessary even if the // input nodes are sorted. @@ -86,7 +91,8 @@ private static Map> getNodeConnections(Networ return nodeConnections.build(); } - private static Map getEdgeToReferenceNode(Network network) { + private static + Map getEdgeToReferenceNode(Network network) { // ImmutableMap.Builder maintains the order of the elements as inserted, so the map will have // whatever ordering the network's edges do, so ImmutableSortedMap is unnecessary even if the // input edges are sorted. @@ -97,7 +103,8 @@ private static Map getEdgeToReferenceNode(Network network) { return edgeToReferenceNode.build(); } - private static NetworkConnections connectionsOf(Network network, N node) { + private static + NetworkConnections connectionsOf(Network network, N node) { if (network.isDirected()) { Map inEdgeMap = Maps.asMap(network.inEdges(node), sourceNodeFn(network)); Map outEdgeMap = Maps.asMap(network.outEdges(node), targetNodeFn(network)); @@ -114,7 +121,8 @@ private static NetworkConnections connectionsOf(Network netwo } } - private static Function sourceNodeFn(final Network network) { + private static Function sourceNodeFn( + final Network network) { return new Function() { @Override public N apply(E edge) { @@ -123,7 +131,8 @@ public N apply(E edge) { }; } - private static Function targetNodeFn(final Network network) { + private static Function targetNodeFn( + final Network network) { return new Function() { @Override public N apply(E edge) { @@ -132,7 +141,8 @@ public N apply(E edge) { }; } - private static Function adjacentNodeFn(final Network network, final N node) { + private static + Function adjacentNodeFn(final Network network, final N node) { return new Function() { @Override public N apply(E edge) { @@ -164,7 +174,7 @@ public N apply(E edge) { * * @since 28.0 */ - public static class Builder { + public static class Builder { private final MutableNetwork mutableNetwork; diff --git a/guava/src/com/google/common/graph/ImmutableValueGraph.java b/guava/src/com/google/common/graph/ImmutableValueGraph.java index f2e2386340eb..0f46ed31456f 100644 --- a/guava/src/com/google/common/graph/ImmutableValueGraph.java +++ b/guava/src/com/google/common/graph/ImmutableValueGraph.java @@ -17,6 +17,7 @@ package com.google.common.graph; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.base.Function; @@ -24,6 +25,7 @@ import com.google.common.collect.Maps; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A {@link ValueGraph} whose elements and structural relationships will never change. Instances of @@ -43,14 +45,16 @@ @Beta @Immutable(containerOf = {"N", "V"}) @SuppressWarnings("Immutable") // Extends StandardValueGraph but uses ImmutableMaps. -public final class ImmutableValueGraph extends StandardValueGraph { +public final class ImmutableValueGraph + extends StandardValueGraph { private ImmutableValueGraph(ValueGraph graph) { super(ValueGraphBuilder.from(graph), getNodeConnections(graph), graph.edges().size()); } /** Returns an immutable copy of {@code graph}. */ - public static ImmutableValueGraph copyOf(ValueGraph graph) { + public static + ImmutableValueGraph copyOf(ValueGraph graph) { return (graph instanceof ImmutableValueGraph) ? (ImmutableValueGraph) graph : new ImmutableValueGraph(graph); @@ -62,7 +66,8 @@ public static ImmutableValueGraph copyOf(ValueGraph graph) { * @deprecated no need to use this */ @Deprecated - public static ImmutableValueGraph copyOf(ImmutableValueGraph graph) { + public static + ImmutableValueGraph copyOf(ImmutableValueGraph graph) { return checkNotNull(graph); } @@ -76,8 +81,8 @@ public ImmutableGraph asGraph() { return new ImmutableGraph(this); // safe because the view is effectively immutable } - private static ImmutableMap> getNodeConnections( - ValueGraph graph) { + private static + ImmutableMap> getNodeConnections(ValueGraph graph) { // ImmutableMap.Builder maintains the order of the elements as inserted, so the map will have // whatever ordering the graph's nodes do, so ImmutableSortedMap is unnecessary even if the // input nodes are sorted. @@ -88,13 +93,14 @@ private static ImmutableMap> getNodeConnections return nodeConnections.build(); } - private static GraphConnections connectionsOf( - final ValueGraph graph, final N node) { + private static + GraphConnections connectionsOf(final ValueGraph graph, final N node) { Function successorNodeToValueFn = new Function() { @Override public V apply(N successorNode) { - return graph.edgeValueOrDefault(node, successorNode, null); + // requireNonNull is safe because the endpoint pair comes from the graph. + return requireNonNull(graph.edgeValueOrDefault(node, successorNode, null)); } }; return graph.isDirected() @@ -125,7 +131,7 @@ public V apply(N successorNode) { * * @since 28.0 */ - public static class Builder { + public static class Builder { private final MutableValueGraph mutableValueGraph; diff --git a/guava/src/com/google/common/graph/IncidentEdgeSet.java b/guava/src/com/google/common/graph/IncidentEdgeSet.java index f306a677ac66..dcff2c343974 100644 --- a/guava/src/com/google/common/graph/IncidentEdgeSet.java +++ b/guava/src/com/google/common/graph/IncidentEdgeSet.java @@ -18,13 +18,14 @@ import java.util.AbstractSet; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** * Abstract base class for an incident edges set that allows different implementations of {@link * AbstractSet#iterator()}. */ -abstract class IncidentEdgeSet extends AbstractSet> { +abstract class IncidentEdgeSet extends AbstractSet> { protected final N node; protected final BaseGraph graph; @@ -34,7 +35,7 @@ abstract class IncidentEdgeSet extends AbstractSet> { } @Override - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { throw new UnsupportedOperationException(); } diff --git a/guava/src/com/google/common/graph/MapIteratorCache.java b/guava/src/com/google/common/graph/MapIteratorCache.java index 182a67fe585f..fce4452a3523 100644 --- a/guava/src/com/google/common/graph/MapIteratorCache.java +++ b/guava/src/com/google/common/graph/MapIteratorCache.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -41,7 +42,7 @@ * * @author James Sexton */ -class MapIteratorCache { +class MapIteratorCache { private final Map backingMap; /* @@ -60,13 +61,13 @@ class MapIteratorCache { } @CanIgnoreReturnValue - public final V put(@Nullable K key, @Nullable V value) { + public final @Nullable V put(K key, V value) { clearCache(); return backingMap.put(key, value); } @CanIgnoreReturnValue - public final V remove(@Nullable Object key) { + public final @Nullable V remove(@Nullable Object key) { clearCache(); return backingMap.remove(key); } @@ -76,12 +77,17 @@ public final void clear() { backingMap.clear(); } - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { V value = getIfCached(key); - return (value != null) ? value : getWithoutCaching(key); + // TODO(cpovirk): Why does our prototype checker (but not CF) reject a ternary? + if (value == null) { + return getWithoutCaching(key); + } else { + return value; + } } - public final V getWithoutCaching(@Nullable Object key) { + public final @Nullable V getWithoutCaching(@Nullable Object key) { return backingMap.get(key); } @@ -124,7 +130,7 @@ public boolean contains(@Nullable Object key) { // Internal methods ('protected' is still package-visible, but treat as only subclass-visible) - protected V getIfCached(@Nullable Object key) { + protected @Nullable V getIfCached(@Nullable Object key) { Entry entry = cacheEntry; // store local reference for thread-safety // Check cache. We use == on purpose because it's cheaper and a cache miss is ok. diff --git a/guava/src/com/google/common/graph/MapRetrievalCache.java b/guava/src/com/google/common/graph/MapRetrievalCache.java index 3a406e94d690..93f3be557d13 100644 --- a/guava/src/com/google/common/graph/MapRetrievalCache.java +++ b/guava/src/com/google/common/graph/MapRetrievalCache.java @@ -16,7 +16,10 @@ package com.google.common.graph; +import static java.util.Objects.requireNonNull; + import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -25,7 +28,8 @@ * * @author James Sexton */ -class MapRetrievalCache extends MapIteratorCache { +class MapRetrievalCache + extends MapIteratorCache { // See the note about volatile in the superclass. private transient volatile @Nullable CacheEntry cacheEntry1; private transient volatile @Nullable CacheEntry cacheEntry2; @@ -36,7 +40,7 @@ class MapRetrievalCache extends MapIteratorCache { @SuppressWarnings("unchecked") // Safe because we only cast if key is found in map. @Override - public V get(@Nullable Object key) { + public @Nullable V get(@Nullable Object key) { V value = getIfCached(key); if (value != null) { return value; @@ -44,7 +48,8 @@ public V get(@Nullable Object key) { value = getWithoutCaching(key); if (value != null) { - addToCache((K) key, value); + // requireNonNull is safe because the key is in the map. + addToCache((K) requireNonNull(key), value); } return value; } @@ -52,7 +57,7 @@ public V get(@Nullable Object key) { // Internal methods ('protected' is still package-visible, but treat as only subclass-visible) @Override - protected V getIfCached(@Nullable Object key) { + protected @Nullable V getIfCached(@Nullable Object key) { V value = super.getIfCached(key); if (value != null) { return value; diff --git a/guava/src/com/google/common/graph/MutableGraph.java b/guava/src/com/google/common/graph/MutableGraph.java index 8324079f6c08..67253342de0f 100644 --- a/guava/src/com/google/common/graph/MutableGraph.java +++ b/guava/src/com/google/common/graph/MutableGraph.java @@ -18,6 +18,7 @@ import com.google.common.annotations.Beta; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A subinterface of {@link Graph} which adds mutation methods. When mutation is not required, users @@ -29,7 +30,7 @@ * @since 20.0 */ @Beta -public interface MutableGraph extends Graph { +public interface MutableGraph extends Graph { /** * Adds {@code node} if it is not already present. diff --git a/guava/src/com/google/common/graph/MutableNetwork.java b/guava/src/com/google/common/graph/MutableNetwork.java index d702903604cf..2dbc2e2cf854 100644 --- a/guava/src/com/google/common/graph/MutableNetwork.java +++ b/guava/src/com/google/common/graph/MutableNetwork.java @@ -18,6 +18,7 @@ import com.google.common.annotations.Beta; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A subinterface of {@link Network} which adds mutation methods. When mutation is not required, @@ -30,7 +31,8 @@ * @since 20.0 */ @Beta -public interface MutableNetwork extends Network { +public interface MutableNetwork + extends Network { /** * Adds {@code node} if it is not already present. diff --git a/guava/src/com/google/common/graph/MutableValueGraph.java b/guava/src/com/google/common/graph/MutableValueGraph.java index 70b286dee185..ebea25e7e6ac 100644 --- a/guava/src/com/google/common/graph/MutableValueGraph.java +++ b/guava/src/com/google/common/graph/MutableValueGraph.java @@ -18,6 +18,8 @@ import com.google.common.annotations.Beta; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A subinterface of {@link ValueGraph} which adds mutation methods. When mutation is not required, @@ -29,7 +31,8 @@ * @since 20.0 */ @Beta -public interface MutableValueGraph extends ValueGraph { +public interface MutableValueGraph + extends ValueGraph { /** * Adds {@code node} if it is not already present. @@ -59,6 +62,7 @@ public interface MutableValueGraph extends ValueGraph { * #allowsSelfLoops()} */ @CanIgnoreReturnValue + @Nullable V putEdgeValue(N nodeU, N nodeV, V value); /** @@ -83,6 +87,7 @@ public interface MutableValueGraph extends ValueGraph { * @since 27.1 */ @CanIgnoreReturnValue + @Nullable V putEdgeValue(EndpointPair endpoints, V value); /** @@ -100,6 +105,7 @@ public interface MutableValueGraph extends ValueGraph { * nodeV}, or null if there was no such edge. */ @CanIgnoreReturnValue + @Nullable V removeEdge(N nodeU, N nodeV); /** @@ -112,5 +118,6 @@ public interface MutableValueGraph extends ValueGraph { * @since 27.1 */ @CanIgnoreReturnValue + @Nullable V removeEdge(EndpointPair endpoints); } diff --git a/guava/src/com/google/common/graph/Network.java b/guava/src/com/google/common/graph/Network.java index 6bb845228001..9b56dccfaa18 100644 --- a/guava/src/com/google/common/graph/Network.java +++ b/guava/src/com/google/common/graph/Network.java @@ -17,9 +17,9 @@ package com.google.common.graph; import com.google.common.annotations.Beta; -import com.google.errorprone.annotations.DoNotMock; import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -103,8 +103,8 @@ * @since 20.0 */ @Beta -@DoNotMock("Use NetworkBuilder to create a real instance") -public interface Network extends SuccessorsFunction, PredecessorsFunction { +public interface Network + extends SuccessorsFunction, PredecessorsFunction { // // Network-level accessors // diff --git a/guava/src/com/google/common/graph/NetworkBuilder.java b/guava/src/com/google/common/graph/NetworkBuilder.java index d289ee2d53d6..e90fd4bc6730 100644 --- a/guava/src/com/google/common/graph/NetworkBuilder.java +++ b/guava/src/com/google/common/graph/NetworkBuilder.java @@ -21,6 +21,7 @@ import com.google.common.annotations.Beta; import com.google.common.base.Optional; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A builder for constructing instances of {@link MutableNetwork} or {@link ImmutableNetwork} with @@ -67,7 +68,8 @@ * @since 20.0 */ @Beta -public final class NetworkBuilder extends AbstractGraphBuilder { +public final class NetworkBuilder + extends AbstractGraphBuilder { boolean allowsParallelEdges = false; ElementOrder edgeOrder = ElementOrder.insertion(); Optional expectedEdgeCount = Optional.absent(); @@ -95,7 +97,8 @@ public static NetworkBuilder undirected() { * such as {@link Network#isDirected()}. Other properties, such as {@link * #expectedNodeCount(int)}, are not set in the new builder. */ - public static NetworkBuilder from(Network network) { + public static NetworkBuilder from( + Network network) { return new NetworkBuilder(network.isDirected()) .allowsParallelEdges(network.allowsParallelEdges()) .allowsSelfLoops(network.allowsSelfLoops()) diff --git a/guava/src/com/google/common/graph/NetworkConnections.java b/guava/src/com/google/common/graph/NetworkConnections.java index 16a68d6cb830..36c01e3379b6 100644 --- a/guava/src/com/google/common/graph/NetworkConnections.java +++ b/guava/src/com/google/common/graph/NetworkConnections.java @@ -18,6 +18,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An interface for representing and manipulating an origin node's adjacent nodes and incident edges @@ -27,7 +29,7 @@ * @param Node parameter type * @param Edge parameter type */ -interface NetworkConnections { +interface NetworkConnections { Set adjacentNodes(); @@ -60,6 +62,7 @@ interface NetworkConnections { *

    In the undirected case, returns {@code null} if {@code isSelfLoop} is true. */ @CanIgnoreReturnValue + @Nullable N removeInEdge(E edge, boolean isSelfLoop); /** Remove {@code edge} from the set of outgoing edges. Returns the former successor node. */ diff --git a/guava/src/com/google/common/graph/PredecessorsFunction.java b/guava/src/com/google/common/graph/PredecessorsFunction.java index f9ca48ae77b9..a540eb1defec 100644 --- a/guava/src/com/google/common/graph/PredecessorsFunction.java +++ b/guava/src/com/google/common/graph/PredecessorsFunction.java @@ -17,7 +17,7 @@ package com.google.common.graph; import com.google.common.annotations.Beta; -import com.google.errorprone.annotations.DoNotMock; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A functional interface for { +public interface PredecessorsFunction { /** * Returns all nodes in this graph adjacent to {@code node} which can be reached by traversing diff --git a/guava/src/com/google/common/graph/StandardMutableGraph.java b/guava/src/com/google/common/graph/StandardMutableGraph.java index 41acccff5963..4e4ff0311547 100644 --- a/guava/src/com/google/common/graph/StandardMutableGraph.java +++ b/guava/src/com/google/common/graph/StandardMutableGraph.java @@ -17,6 +17,7 @@ package com.google.common.graph; import com.google.common.graph.GraphConstants.Presence; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Standard implementation of {@link MutableGraph} that supports both directed and undirected @@ -28,7 +29,8 @@ * @author James Sexton * @param Node parameter type */ -final class StandardMutableGraph extends ForwardingGraph implements MutableGraph { +final class StandardMutableGraph extends ForwardingGraph + implements MutableGraph { private final MutableValueGraph backingValueGraph; /** Constructs a {@link MutableGraph} with the properties specified in {@code builder}. */ diff --git a/guava/src/com/google/common/graph/StandardMutableNetwork.java b/guava/src/com/google/common/graph/StandardMutableNetwork.java index 8cfe9c526021..897322eb3032 100644 --- a/guava/src/com/google/common/graph/StandardMutableNetwork.java +++ b/guava/src/com/google/common/graph/StandardMutableNetwork.java @@ -22,9 +22,11 @@ import static com.google.common.graph.GraphConstants.PARALLEL_EDGES_NOT_ALLOWED; import static com.google.common.graph.GraphConstants.REUSING_EDGE; import static com.google.common.graph.GraphConstants.SELF_LOOPS_NOT_ALLOWED; +import static java.util.Objects.requireNonNull; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Standard implementation of {@link MutableNetwork} that supports both directed and undirected @@ -39,8 +41,8 @@ * @param Node parameter type * @param Edge parameter type */ -final class StandardMutableNetwork extends StandardNetwork - implements MutableNetwork { +final class StandardMutableNetwork + extends StandardNetwork implements MutableNetwork { /** Constructs a mutable graph with the properties specified in {@code builder}. */ StandardMutableNetwork(NetworkBuilder builder) { @@ -152,9 +154,10 @@ public boolean removeEdge(E edge) { return false; } - NetworkConnections connectionsU = nodeConnections.get(nodeU); + // requireNonNull is safe because of the edgeToReferenceNode check above. + NetworkConnections connectionsU = requireNonNull(nodeConnections.get(nodeU)); N nodeV = connectionsU.adjacentNode(edge); - NetworkConnections connectionsV = nodeConnections.get(nodeV); + NetworkConnections connectionsV = requireNonNull(nodeConnections.get(nodeV)); connectionsU.removeOutEdge(edge); connectionsV.removeInEdge(edge, allowsSelfLoops() && nodeU.equals(nodeV)); edgeToReferenceNode.remove(edge); diff --git a/guava/src/com/google/common/graph/StandardMutableValueGraph.java b/guava/src/com/google/common/graph/StandardMutableValueGraph.java index 558d8d60976e..00bbec5a2137 100644 --- a/guava/src/com/google/common/graph/StandardMutableValueGraph.java +++ b/guava/src/com/google/common/graph/StandardMutableValueGraph.java @@ -22,8 +22,11 @@ import static com.google.common.graph.GraphConstants.SELF_LOOPS_NOT_ALLOWED; import static com.google.common.graph.Graphs.checkNonNegative; import static com.google.common.graph.Graphs.checkPositive; +import static java.util.Objects.requireNonNull; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Standard implementation of {@link MutableValueGraph} that supports both directed and undirected @@ -38,8 +41,8 @@ * @param Node parameter type * @param Value parameter type */ -final class StandardMutableValueGraph extends StandardValueGraph - implements MutableValueGraph { +final class StandardMutableValueGraph + extends StandardValueGraph implements MutableValueGraph { private final ElementOrder incidentEdgeOrder; @@ -81,7 +84,7 @@ private GraphConnections addNodeInternal(N node) { @Override @CanIgnoreReturnValue - public V putEdgeValue(N nodeU, N nodeV, V value) { + public @Nullable V putEdgeValue(N nodeU, N nodeV, V value) { checkNotNull(nodeU, "nodeU"); checkNotNull(nodeV, "nodeV"); checkNotNull(value, "value"); @@ -108,7 +111,7 @@ public V putEdgeValue(N nodeU, N nodeV, V value) { @Override @CanIgnoreReturnValue - public V putEdgeValue(EndpointPair endpoints, V value) { + public @Nullable V putEdgeValue(EndpointPair endpoints, V value) { validateEndpoints(endpoints); return putEdgeValue(endpoints.nodeU(), endpoints.nodeV(), value); } @@ -132,12 +135,16 @@ public boolean removeNode(N node) { } for (N successor : connections.successors()) { - nodeConnections.getWithoutCaching(successor).removePredecessor(node); + // requireNonNull is safe because the node is a successor. + requireNonNull(nodeConnections.getWithoutCaching(successor)).removePredecessor(node); --edgeCount; } if (isDirected()) { // In undirected graphs, the successor and predecessor sets are equal. for (N predecessor : connections.predecessors()) { - checkState(nodeConnections.getWithoutCaching(predecessor).removeSuccessor(node) != null); + // requireNonNull is safe because the node is a predecessor. + checkState( + requireNonNull(nodeConnections.getWithoutCaching(predecessor)).removeSuccessor(node) + != null); --edgeCount; } } @@ -148,7 +155,7 @@ public boolean removeNode(N node) { @Override @CanIgnoreReturnValue - public V removeEdge(N nodeU, N nodeV) { + public @Nullable V removeEdge(N nodeU, N nodeV) { checkNotNull(nodeU, "nodeU"); checkNotNull(nodeV, "nodeV"); @@ -168,7 +175,7 @@ public V removeEdge(N nodeU, N nodeV) { @Override @CanIgnoreReturnValue - public V removeEdge(EndpointPair endpoints) { + public @Nullable V removeEdge(EndpointPair endpoints) { validateEndpoints(endpoints); return removeEdge(endpoints.nodeU(), endpoints.nodeV()); } diff --git a/guava/src/com/google/common/graph/StandardNetwork.java b/guava/src/com/google/common/graph/StandardNetwork.java index 1b82301f91f8..7497d9ac371e 100644 --- a/guava/src/com/google/common/graph/StandardNetwork.java +++ b/guava/src/com/google/common/graph/StandardNetwork.java @@ -22,12 +22,13 @@ import static com.google.common.graph.GraphConstants.DEFAULT_NODE_COUNT; import static com.google.common.graph.GraphConstants.EDGE_NOT_IN_GRAPH; import static com.google.common.graph.GraphConstants.NODE_NOT_IN_GRAPH; +import static java.util.Objects.requireNonNull; import com.google.common.collect.ImmutableSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Standard implementation of {@link Network} that supports the options supplied by {@link @@ -48,7 +49,8 @@ * @param Node parameter type * @param Edge parameter type */ -class StandardNetwork extends AbstractNetwork { +class StandardNetwork + extends AbstractNetwork { private final boolean isDirected; private final boolean allowsParallelEdges; private final boolean allowsSelfLoops; @@ -135,7 +137,8 @@ public Set incidentEdges(N node) { @Override public EndpointPair incidentNodes(E edge) { N nodeU = checkedReferenceNode(edge); - N nodeV = nodeConnections.get(nodeU).adjacentNode(edge); + // requireNonNull is safe because checkedReferenceNode made sure the edge is in the network. + N nodeV = requireNonNull(nodeConnections.get(nodeU)).adjacentNode(edge); return EndpointPair.of(this, nodeU, nodeV); } @@ -192,11 +195,11 @@ protected final N checkedReferenceNode(E edge) { return referenceNode; } - protected final boolean containsNode(@Nullable N node) { + protected final boolean containsNode(N node) { return nodeConnections.containsKey(node); } - protected final boolean containsEdge(@Nullable E edge) { + protected final boolean containsEdge(E edge) { return edgeToReferenceNode.containsKey(edge); } } diff --git a/guava/src/com/google/common/graph/StandardValueGraph.java b/guava/src/com/google/common/graph/StandardValueGraph.java index 8da0b0ff19b9..0a5233091431 100644 --- a/guava/src/com/google/common/graph/StandardValueGraph.java +++ b/guava/src/com/google/common/graph/StandardValueGraph.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -43,7 +44,8 @@ * @param Node parameter type * @param Value parameter type */ -class StandardValueGraph extends AbstractValueGraph { +class StandardValueGraph + extends AbstractValueGraph { private final boolean isDirected; private final boolean allowsSelfLoops; private final ElementOrder nodeOrder; @@ -164,7 +166,7 @@ protected final GraphConnections checkedConnections(N node) { return connections; } - protected final boolean containsNode(@Nullable N node) { + protected final boolean containsNode(N node) { return nodeConnections.containsKey(node); } @@ -173,9 +175,15 @@ protected final boolean hasEdgeConnecting_internal(N nodeU, N nodeV) { return (connectionsU != null) && connectionsU.successors().contains(nodeV); } - protected final V edgeValueOrDefault_internal(N nodeU, N nodeV, V defaultValue) { + protected final @Nullable V edgeValueOrDefault_internal( + N nodeU, N nodeV, @Nullable V defaultValue) { GraphConnections connectionsU = nodeConnections.get(nodeU); V value = (connectionsU == null) ? null : connectionsU.value(nodeV); - return value == null ? defaultValue : value; + // TODO(cpovirk): Why does our prototype checker (but not CF) reject a ternary? + if (value == null) { + return defaultValue; + } else { + return value; + } } } diff --git a/guava/src/com/google/common/graph/SuccessorsFunction.java b/guava/src/com/google/common/graph/SuccessorsFunction.java index f74f437c2937..1b98951f898f 100644 --- a/guava/src/com/google/common/graph/SuccessorsFunction.java +++ b/guava/src/com/google/common/graph/SuccessorsFunction.java @@ -17,7 +17,7 @@ package com.google.common.graph; import com.google.common.annotations.Beta; -import com.google.errorprone.annotations.DoNotMock; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A functional interface for { +public interface SuccessorsFunction { /** * Returns all nodes in this graph adjacent to {@code node} which can be reached by traversing diff --git a/guava/src/com/google/common/graph/Traverser.java b/guava/src/com/google/common/graph/Traverser.java index 1a53dc673dc3..434b2d92bd0e 100644 --- a/guava/src/com/google/common/graph/Traverser.java +++ b/guava/src/com/google/common/graph/Traverser.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -30,6 +31,7 @@ import java.util.Iterator; import java.util.Queue; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -62,7 +64,7 @@ * @since 23.1 */ @Beta -public abstract class Traverser { +public abstract class Traverser { /** * Creates a new traverser for the given general {@code graph}. @@ -88,7 +90,7 @@ public abstract class Traverser { * * @param graph {@link SuccessorsFunction} representing a general graph that may have cycles. */ - public static Traverser forGraph(SuccessorsFunction graph) { + public static Traverser forGraph(SuccessorsFunction graph) { checkNotNull(graph); return new GraphTraverser<>(graph); } @@ -166,7 +168,7 @@ public static Traverser forGraph(SuccessorsFunction graph) { * @param tree {@link SuccessorsFunction} representing a directed acyclic graph that has at most * one path between any two nodes */ - public static Traverser forTree(SuccessorsFunction tree) { + public static Traverser forTree(SuccessorsFunction tree) { checkNotNull(tree); if (tree instanceof BaseGraph) { checkArgument(((BaseGraph) tree).isDirected(), "Undirected graphs can never be trees."); @@ -315,7 +317,7 @@ public static Traverser forTree(SuccessorsFunction tree) { // Avoid subclasses outside of this class private Traverser() {} - private static final class GraphTraverser extends Traverser { + private static final class GraphTraverser extends Traverser { private final SuccessorsFunction graph; GraphTraverser(SuccessorsFunction graph) { @@ -430,7 +432,8 @@ public N next() { private final class DepthFirstIterator extends AbstractIterator { private final Deque stack = new ArrayDeque<>(); - private final Set visited = new HashSet<>(); + // It's a little weird that we add `null` to this, but it makes for slightly simpler code. + private final Set<@Nullable N> visited = new HashSet<>(); private final Order order; DepthFirstIterator(Iterable roots, Order order) { @@ -481,7 +484,7 @@ private final class NodeAndSuccessors { } } - private static final class TreeTraverser extends Traverser { + private static final class TreeTraverser extends Traverser { private final SuccessorsFunction tree; TreeTraverser(SuccessorsFunction tree) { @@ -601,7 +604,8 @@ public boolean hasNext() { @Override public N next() { Iterator iterator = stack.getLast(); // throws NoSuchElementException if empty - N result = checkNotNull(iterator.next()); + // TODO(cpovirk): Why does our prototype checker (but not stock CF) need ? + N result = Preconditions.checkNotNull(iterator.next()); if (!iterator.hasNext()) { stack.removeLast(); } diff --git a/guava/src/com/google/common/graph/UndirectedGraphConnections.java b/guava/src/com/google/common/graph/UndirectedGraphConnections.java index 49689f9d8aec..2b570cfa05b9 100644 --- a/guava/src/com/google/common/graph/UndirectedGraphConnections.java +++ b/guava/src/com/google/common/graph/UndirectedGraphConnections.java @@ -29,6 +29,8 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An implementation of {@link GraphConnections} for undirected graphs. @@ -37,14 +39,16 @@ * @param Node parameter type * @param Value parameter type */ -final class UndirectedGraphConnections implements GraphConnections { +final class UndirectedGraphConnections + implements GraphConnections { private final Map adjacentNodeValues; private UndirectedGraphConnections(Map adjacentNodeValues) { this.adjacentNodeValues = checkNotNull(adjacentNodeValues); } - static UndirectedGraphConnections of(ElementOrder incidentEdgeOrder) { + static UndirectedGraphConnections of( + ElementOrder incidentEdgeOrder) { switch (incidentEdgeOrder.type()) { case UNORDERED: return new UndirectedGraphConnections<>( @@ -57,7 +61,8 @@ static UndirectedGraphConnections of(ElementOrder incidentEdgeOr } } - static UndirectedGraphConnections ofImmutable(Map adjacentNodeValues) { + static + UndirectedGraphConnections ofImmutable(Map adjacentNodeValues) { return new UndirectedGraphConnections<>(ImmutableMap.copyOf(adjacentNodeValues)); } @@ -89,7 +94,7 @@ public EndpointPair apply(N incidentNode) { } @Override - public V value(N node) { + public @Nullable V value(N node) { return adjacentNodeValues.get(node); } @@ -100,7 +105,7 @@ public void removePredecessor(N node) { } @Override - public V removeSuccessor(N node) { + public @Nullable V removeSuccessor(N node) { return adjacentNodeValues.remove(node); } @@ -111,7 +116,7 @@ public void addPredecessor(N node, V value) { } @Override - public V addSuccessor(N node, V value) { + public @Nullable V addSuccessor(N node, V value) { return adjacentNodeValues.put(node, value); } } diff --git a/guava/src/com/google/common/graph/UndirectedMultiNetworkConnections.java b/guava/src/com/google/common/graph/UndirectedMultiNetworkConnections.java index a96a59593e39..d8b3b4662714 100644 --- a/guava/src/com/google/common/graph/UndirectedMultiNetworkConnections.java +++ b/guava/src/com/google/common/graph/UndirectedMultiNetworkConnections.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,23 +40,25 @@ * @param Node parameter type * @param Edge parameter type */ -final class UndirectedMultiNetworkConnections +final class UndirectedMultiNetworkConnections extends AbstractUndirectedNetworkConnections { private UndirectedMultiNetworkConnections(Map incidentEdges) { super(incidentEdges); } - static UndirectedMultiNetworkConnections of() { + static + UndirectedMultiNetworkConnections of() { return new UndirectedMultiNetworkConnections<>( new HashMap(INNER_CAPACITY, INNER_LOAD_FACTOR)); } - static UndirectedMultiNetworkConnections ofImmutable(Map incidentEdges) { + static + UndirectedMultiNetworkConnections ofImmutable(Map incidentEdges) { return new UndirectedMultiNetworkConnections<>(ImmutableMap.copyOf(incidentEdges)); } - @LazyInit private transient Reference> adjacentNodesReference; + @LazyInit private transient @Nullable Reference> adjacentNodesReference; @Override public Set adjacentNodes() { @@ -82,7 +85,7 @@ public int size() { } @Override - public N removeInEdge(E edge, boolean isSelfLoop) { + public @Nullable N removeInEdge(E edge, boolean isSelfLoop) { if (!isSelfLoop) { return removeOutEdge(edge); } @@ -115,7 +118,8 @@ public void addOutEdge(E edge, N node) { } } - private static @Nullable T getReference(@Nullable Reference reference) { + private static @Nullable T getReference( + @Nullable Reference reference) { return (reference == null) ? null : reference.get(); } } diff --git a/guava/src/com/google/common/graph/UndirectedNetworkConnections.java b/guava/src/com/google/common/graph/UndirectedNetworkConnections.java index 1e253dd05703..479a8298abfb 100644 --- a/guava/src/com/google/common/graph/UndirectedNetworkConnections.java +++ b/guava/src/com/google/common/graph/UndirectedNetworkConnections.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; /** * An implementation of {@link NetworkConnections} for undirected networks. @@ -32,17 +33,20 @@ * @param Node parameter type * @param Edge parameter type */ -final class UndirectedNetworkConnections extends AbstractUndirectedNetworkConnections { +final class UndirectedNetworkConnections + extends AbstractUndirectedNetworkConnections { protected UndirectedNetworkConnections(Map incidentEdgeMap) { super(incidentEdgeMap); } - static UndirectedNetworkConnections of() { + static + UndirectedNetworkConnections of() { return new UndirectedNetworkConnections<>(HashBiMap.create(EXPECTED_DEGREE)); } - static UndirectedNetworkConnections ofImmutable(Map incidentEdges) { + static + UndirectedNetworkConnections ofImmutable(Map incidentEdges) { return new UndirectedNetworkConnections<>(ImmutableBiMap.copyOf(incidentEdges)); } diff --git a/guava/src/com/google/common/graph/ValueGraph.java b/guava/src/com/google/common/graph/ValueGraph.java index ed27058fb1e5..d66cddebcc48 100644 --- a/guava/src/com/google/common/graph/ValueGraph.java +++ b/guava/src/com/google/common/graph/ValueGraph.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Optional; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -108,7 +109,8 @@ * @since 20.0 */ @Beta -public interface ValueGraph extends BaseGraph { +public interface ValueGraph + extends BaseGraph { // // ValueGraph-level accessors // diff --git a/guava/src/com/google/common/graph/ValueGraphBuilder.java b/guava/src/com/google/common/graph/ValueGraphBuilder.java index 4fc752da1f4a..8a64d4c21f58 100644 --- a/guava/src/com/google/common/graph/ValueGraphBuilder.java +++ b/guava/src/com/google/common/graph/ValueGraphBuilder.java @@ -22,6 +22,7 @@ import com.google.common.annotations.Beta; import com.google.common.base.Optional; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A builder for constructing instances of {@link MutableValueGraph} or {@link ImmutableValueGraph} @@ -66,7 +67,8 @@ * @since 20.0 */ @Beta -public final class ValueGraphBuilder extends AbstractGraphBuilder { +public final class ValueGraphBuilder + extends AbstractGraphBuilder { /** Creates a new instance with the specified edge directionality. */ private ValueGraphBuilder(boolean directed) { @@ -91,7 +93,8 @@ public static ValueGraphBuilder undirected() { * interface, such as {@link ValueGraph#isDirected()}. Other properties, such as {@link * #expectedNodeCount(int)}, are not set in the new builder. */ - public static ValueGraphBuilder from(ValueGraph graph) { + public static ValueGraphBuilder from( + ValueGraph graph) { return new ValueGraphBuilder(graph.isDirected()) .allowsSelfLoops(graph.allowsSelfLoops()) .nodeOrder(graph.nodeOrder()) diff --git a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java index 525ead84c1d0..f3aff8b7c1c0 100644 --- a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java +++ b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java @@ -20,6 +20,7 @@ import com.google.errorprone.annotations.Immutable; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An abstract composition of multiple hash functions. {@linkplain #newHasher()} delegates to the diff --git a/guava/src/com/google/common/hash/AbstractHashFunction.java b/guava/src/com/google/common/hash/AbstractHashFunction.java index 61841894aafc..54e7ef66dbf0 100644 --- a/guava/src/com/google/common/hash/AbstractHashFunction.java +++ b/guava/src/com/google/common/hash/AbstractHashFunction.java @@ -20,6 +20,7 @@ import com.google.errorprone.annotations.Immutable; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Skeleton implementation of {@link HashFunction} in terms of {@link #newHasher()}. diff --git a/guava/src/com/google/common/hash/AbstractHasher.java b/guava/src/com/google/common/hash/AbstractHasher.java index 3452fb3c93df..7a290e72b251 100644 --- a/guava/src/com/google/common/hash/AbstractHasher.java +++ b/guava/src/com/google/common/hash/AbstractHasher.java @@ -18,6 +18,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An abstract implementation of {@link Hasher}, which only requires subtypes to implement {@link diff --git a/guava/src/com/google/common/hash/BloomFilter.java b/guava/src/com/google/common/hash/BloomFilter.java index 97e0f0ba92d4..7baddf2491d2 100644 --- a/guava/src/com/google/common/hash/BloomFilter.java +++ b/guava/src/com/google/common/hash/BloomFilter.java @@ -274,7 +274,8 @@ public boolean equals(@Nullable Object object) { return true; } if (object instanceof BloomFilter) { - BloomFilter that = (BloomFilter) object; + BloomFilter that = + (BloomFilter) object; return this.numHashFunctions == that.numHashFunctions && this.funnel.equals(that.funnel) && this.bits.equals(that.bits) @@ -451,7 +452,8 @@ static BloomFilter create( * BloomFilter}; must be positive * @return a {@code BloomFilter} */ - public static BloomFilter create(Funnel funnel, int expectedInsertions) { + public static BloomFilter create( + Funnel funnel, int expectedInsertions) { return create(funnel, (long) expectedInsertions); } @@ -475,7 +477,8 @@ public static BloomFilter create(Funnel funnel, int expectedIn * @return a {@code BloomFilter} * @since 19.0 */ - public static BloomFilter create(Funnel funnel, long expectedInsertions) { + public static BloomFilter create( + Funnel funnel, long expectedInsertions) { return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions } @@ -581,8 +584,8 @@ public void writeTo(OutputStream out) throws IOException { * @throws IOException if the InputStream throws an {@code IOException}, or if its data does not * appear to be a BloomFilter serialized using the {@linkplain #writeTo(OutputStream)} method. */ - public static BloomFilter readFrom(InputStream in, Funnel funnel) - throws IOException { + public static BloomFilter readFrom( + InputStream in, Funnel funnel) throws IOException { checkNotNull(in, "InputStream"); checkNotNull(funnel, "Funnel"); int strategyOrdinal = -1; diff --git a/guava/src/com/google/common/hash/Funnel.java b/guava/src/com/google/common/hash/Funnel.java index 2c6a7b9820f5..16e46f1e325f 100644 --- a/guava/src/com/google/common/hash/Funnel.java +++ b/guava/src/com/google/common/hash/Funnel.java @@ -15,8 +15,8 @@ package com.google.common.hash; import com.google.common.annotations.Beta; -import com.google.errorprone.annotations.DoNotMock; import java.io.Serializable; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An object which can send data from an object of type {@code T} into a {@code PrimitiveSink}. @@ -42,7 +42,6 @@ * @since 11.0 */ @Beta -@DoNotMock("Implement with a lambda") public interface Funnel extends Serializable { /** diff --git a/guava/src/com/google/common/hash/Funnels.java b/guava/src/com/google/common/hash/Funnels.java index 6051bfd7c3ec..b49c94ac246d 100644 --- a/guava/src/com/google/common/hash/Funnels.java +++ b/guava/src/com/google/common/hash/Funnels.java @@ -164,11 +164,13 @@ public String toString() { * * @since 15.0 */ - public static Funnel> sequentialFunnel(Funnel elementFunnel) { + public static Funnel> sequentialFunnel( + Funnel elementFunnel) { return new SequentialFunnel(elementFunnel); } - private static class SequentialFunnel implements Funnel>, Serializable { + private static class SequentialFunnel + implements Funnel>, Serializable { private final Funnel elementFunnel; SequentialFunnel(Funnel elementFunnel) { @@ -190,7 +192,8 @@ public String toString() { @Override public boolean equals(@Nullable Object o) { if (o instanceof SequentialFunnel) { - SequentialFunnel funnel = (SequentialFunnel) o; + SequentialFunnel funnel = + (SequentialFunnel) o; return elementFunnel.equals(funnel.elementFunnel); } return false; diff --git a/guava/src/com/google/common/hash/HashFunction.java b/guava/src/com/google/common/hash/HashFunction.java index 78842595f692..cd93675472bd 100644 --- a/guava/src/com/google/common/hash/HashFunction.java +++ b/guava/src/com/google/common/hash/HashFunction.java @@ -19,6 +19,7 @@ import com.google.errorprone.annotations.Immutable; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A hash function is a collision-averse pure function that maps an arbitrary block of data to a diff --git a/guava/src/com/google/common/hash/Hasher.java b/guava/src/com/google/common/hash/Hasher.java index ae9ae5f68ff6..8a8321d89a51 100644 --- a/guava/src/com/google/common/hash/Hasher.java +++ b/guava/src/com/google/common/hash/Hasher.java @@ -18,6 +18,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link PrimitiveSink} that can compute a hash code after reading the input. Each hasher should diff --git a/guava/src/com/google/common/hash/Hashing.java b/guava/src/com/google/common/hash/Hashing.java index a5340a6f1300..e62ad05128e0 100644 --- a/guava/src/com/google/common/hash/Hashing.java +++ b/guava/src/com/google/common/hash/Hashing.java @@ -161,8 +161,7 @@ public static HashFunction sipHash24(long k0, long k1) { * despite its deprecation. But if you can choose your hash function, avoid MD5, which is * neither fast nor secure. As of January 2017, we suggest: *

    */ @@ -182,8 +181,7 @@ private static class Md5Holder { * despite its deprecation. But if you can choose your hash function, avoid SHA-1, which is * neither fast nor secure. As of January 2017, we suggest: *
      - *
    • For security: - * {@link Hashing#sha256} or a higher-level API. + *
    • For security: {@link Hashing#sha256} or a higher-level API. *
    • For speed: {@link Hashing#goodFastHash}, though see its docs for caveats. *
    */ @@ -234,7 +232,6 @@ private static class Sha512Holder { * Returns a hash function implementing the Message Authentication Code (MAC) algorithm, using the * MD5 (128 hash bits) hash function and the given secret key. * - * * @param key the secret key * @throws IllegalArgumentException if the given key is inappropriate for initializing this MAC * @since 20.0 @@ -248,7 +245,6 @@ public static HashFunction hmacMd5(Key key) { * MD5 (128 hash bits) hash function and a {@link SecretKeySpec} created from the given byte array * and the MD5 algorithm. * - * * @param key the key material of the secret key * @since 20.0 */ @@ -260,7 +256,6 @@ public static HashFunction hmacMd5(byte[] key) { * Returns a hash function implementing the Message Authentication Code (MAC) algorithm, using the * SHA-1 (160 hash bits) hash function and the given secret key. * - * * @param key the secret key * @throws IllegalArgumentException if the given key is inappropriate for initializing this MAC * @since 20.0 @@ -274,7 +269,6 @@ public static HashFunction hmacSha1(Key key) { * SHA-1 (160 hash bits) hash function and a {@link SecretKeySpec} created from the given byte * array and the SHA-1 algorithm. * - * * @param key the key material of the secret key * @since 20.0 */ @@ -286,7 +280,6 @@ public static HashFunction hmacSha1(byte[] key) { * Returns a hash function implementing the Message Authentication Code (MAC) algorithm, using the * SHA-256 (256 hash bits) hash function and the given secret key. * - * * @param key the secret key * @throws IllegalArgumentException if the given key is inappropriate for initializing this MAC * @since 20.0 @@ -300,7 +293,6 @@ public static HashFunction hmacSha256(Key key) { * SHA-256 (256 hash bits) hash function and a {@link SecretKeySpec} created from the given byte * array and the SHA-256 algorithm. * - * * @param key the key material of the secret key * @since 20.0 */ @@ -312,7 +304,6 @@ public static HashFunction hmacSha256(byte[] key) { * Returns a hash function implementing the Message Authentication Code (MAC) algorithm, using the * SHA-512 (512 hash bits) hash function and the given secret key. * - * * @param key the secret key * @throws IllegalArgumentException if the given key is inappropriate for initializing this MAC * @since 20.0 @@ -326,7 +317,6 @@ public static HashFunction hmacSha512(Key key) { * SHA-512 (512 hash bits) hash function and a {@link SecretKeySpec} created from the given byte * array and the SHA-512 algorithm. * - * * @param key the key material of the secret key * @since 20.0 */ @@ -403,6 +393,8 @@ public Checksum get() { public final HashFunction hashFunction; + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) ChecksumType(String toString) { this.hashFunction = new ChecksumHashFunction(this, 32, toString); } @@ -457,7 +449,6 @@ public static HashFunction farmHashFingerprint64() { * traffic to {@code charlie}, rather than letting {@code bravo} keep its traffic. * * - * *

    See the Wikipedia article on * consistent hashing for more information. */ @@ -492,7 +483,6 @@ public static int consistentHash(HashCode hashCode, int buckets) { * traffic to {@code charlie}, rather than letting {@code bravo} keep its traffic. * * - * *

    See the Wikipedia article on * consistent hashing for more information. */ diff --git a/guava/src/com/google/common/hash/LittleEndianByteArray.java b/guava/src/com/google/common/hash/LittleEndianByteArray.java index 91f57371d998..7e67dfec09b6 100644 --- a/guava/src/com/google/common/hash/LittleEndianByteArray.java +++ b/guava/src/com/google/common/hash/LittleEndianByteArray.java @@ -178,7 +178,8 @@ public sun.misc.Unsafe run() throws Exception { Class k = sun.misc.Unsafe.class; for (java.lang.reflect.Field f : k.getDeclaredFields()) { f.setAccessible(true); - Object x = f.get(null); + // unsafeNull is safe because we're reading a static field. + Object x = f.get(unsafeNull()); if (k.isInstance(x)) { return k.cast(x); } @@ -202,6 +203,11 @@ public sun.misc.Unsafe run() throws Exception { } } + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } + /** Fallback implementation for when Unsafe is not available in our current environment. */ private enum JavaLittleEndianBytes implements LittleEndianBytes { INSTANCE { diff --git a/guava/src/com/google/common/hash/Striped64.java b/guava/src/com/google/common/hash/Striped64.java index 3f6cf1b06be2..5f5da94578fb 100644 --- a/guava/src/com/google/common/hash/Striped64.java +++ b/guava/src/com/google/common/hash/Striped64.java @@ -125,7 +125,7 @@ final boolean cas(long cmp, long val) { * class, we use a suboptimal int[] representation to avoid introducing a new type that can impede * class-unloading when ThreadLocals are not removed. */ - static final ThreadLocal threadHashCode = new ThreadLocal<>(); + static final ThreadLocal threadHashCode = new ThreadLocal<>(); /** Generator of new random hash codes */ static final Random rng = new Random(); @@ -298,7 +298,8 @@ public sun.misc.Unsafe run() throws Exception { Class k = sun.misc.Unsafe.class; for (java.lang.reflect.Field f : k.getDeclaredFields()) { f.setAccessible(true); - Object x = f.get(null); + // unsafeNull is safe because we're reading a static field. + Object x = f.get(unsafeNull()); if (k.isInstance(x)) return k.cast(x); } throw new NoSuchFieldError("the Unsafe"); @@ -308,4 +309,9 @@ public sun.misc.Unsafe run() throws Exception { throw new RuntimeException("Could not initialize intrinsics", e.getCause()); } } + + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } } diff --git a/guava/src/com/google/common/html/HtmlEscapers.java b/guava/src/com/google/common/html/HtmlEscapers.java index 29eebe8aaa46..56b065c8ec11 100644 --- a/guava/src/com/google/common/html/HtmlEscapers.java +++ b/guava/src/com/google/common/html/HtmlEscapers.java @@ -21,9 +21,9 @@ /** * {@code Escaper} instances suitable for strings to be included in HTML attribute values and * most elements' text contents. When possible, avoid manual escaping by using templating - * systems and high-level APIs that provide autoescaping. - * One Google-authored templating system available for external use is Closure Templates. + * systems and high-level APIs that provide autoescaping. One Google-authored templating system + * available for external use is Closure + * Templates. * *

    HTML escaping is particularly tricky: For example, some * elements' text contents must not be HTML escaped. As a result, it is impossible to escape an diff --git a/guava/src/com/google/common/html/package-info.java b/guava/src/com/google/common/html/package-info.java index f84d7f23d0ca..93c105c105e1 100644 --- a/guava/src/com/google/common/html/package-info.java +++ b/guava/src/com/google/common/html/package-info.java @@ -13,9 +13,7 @@ */ /** - * Escapers - * for - * HTML. + * Escapers for HTML. * *

    This package is a part of the open-source Guava * library. diff --git a/guava/src/com/google/common/io/AppendableWriter.java b/guava/src/com/google/common/io/AppendableWriter.java index 85b137e8040d..00d831ef8e6b 100644 --- a/guava/src/com/google/common/io/AppendableWriter.java +++ b/guava/src/com/google/common/io/AppendableWriter.java @@ -68,13 +68,15 @@ public void write(int c) throws IOException { } @Override - public void write(@Nullable String str) throws IOException { + public void write(String str) throws IOException { + checkNotNull(str); checkNotClosed(); target.append(str); } @Override - public void write(@Nullable String str, int off, int len) throws IOException { + public void write(String str, int off, int len) throws IOException { + checkNotNull(str); checkNotClosed(); // tricky: append takes start, end pair... target.append(str, off, off + len); diff --git a/guava/src/com/google/common/io/BaseEncoding.java b/guava/src/com/google/common/io/BaseEncoding.java index c0874e78407a..35f4f27be037 100644 --- a/guava/src/com/google/common/io/BaseEncoding.java +++ b/guava/src/com/google/common/io/BaseEncoding.java @@ -226,8 +226,8 @@ public final byte[] decode(CharSequence chars) { * * @throws DecodingException if the input is not a valid encoded string according to this * encoding. - */ final byte[] decodeChecked(CharSequence chars) - throws DecodingException { + */ + final byte[] decodeChecked(CharSequence chars) throws DecodingException { chars = trimTrailingPadding(chars); byte[] tmp = new byte[maxDecodedSize(chars.length())]; int len = decodeTo(tmp, chars); diff --git a/guava/src/com/google/common/io/ByteArrayDataInput.java b/guava/src/com/google/common/io/ByteArrayDataInput.java index bef1431e2b23..e34008fe0fcd 100644 --- a/guava/src/com/google/common/io/ByteArrayDataInput.java +++ b/guava/src/com/google/common/io/ByteArrayDataInput.java @@ -18,6 +18,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.DataInput; import java.io.IOException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An extension of {@code DataInput} for reading from in-memory byte arrays; its methods offer @@ -86,6 +87,7 @@ public interface ByteArrayDataInput extends DataInput { @CanIgnoreReturnValue // to skip a line @Override + @Nullable String readLine(); @CanIgnoreReturnValue // to skip a field diff --git a/guava/src/com/google/common/io/ByteProcessor.java b/guava/src/com/google/common/io/ByteProcessor.java index 115c73571555..00d040489dbe 100644 --- a/guava/src/com/google/common/io/ByteProcessor.java +++ b/guava/src/com/google/common/io/ByteProcessor.java @@ -17,8 +17,8 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.io.IOException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A callback interface to process bytes from a stream. @@ -30,7 +30,6 @@ * @since 1.0 */ @Beta -@DoNotMock("Implement it normally") @GwtIncompatible public interface ByteProcessor { /** diff --git a/guava/src/com/google/common/io/ByteSource.java b/guava/src/com/google/common/io/ByteSource.java index 19f3a43027de..c9ac84514972 100644 --- a/guava/src/com/google/common/io/ByteSource.java +++ b/guava/src/com/google/common/io/ByteSource.java @@ -40,6 +40,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Iterator; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A readable source of bytes, such as a file. Unlike an {@link InputStream}, a {@code ByteSource} diff --git a/guava/src/com/google/common/io/ByteStreams.java b/guava/src/com/google/common/io/ByteStreams.java index 868d200ca6f9..d9d62904dfa7 100644 --- a/guava/src/com/google/common/io/ByteStreams.java +++ b/guava/src/com/google/common/io/ByteStreams.java @@ -41,6 +41,7 @@ import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Provides utility methods for working with byte arrays and I/O streams. @@ -438,7 +439,7 @@ public double readDouble() { } @Override - public String readLine() { + public @Nullable String readLine() { try { return input.readLine(); } catch (IOException e) { @@ -869,7 +870,8 @@ private static long skipSafely(InputStream in, long n) throws IOException { */ @Beta @CanIgnoreReturnValue // some processors won't return a useful result - public static T readBytes(InputStream input, ByteProcessor processor) throws IOException { + public static T readBytes( + InputStream input, ByteProcessor processor) throws IOException { checkNotNull(input); checkNotNull(processor); diff --git a/guava/src/com/google/common/io/CharSequenceReader.java b/guava/src/com/google/common/io/CharSequenceReader.java index 4cbeda1fb365..dcb112764c86 100644 --- a/guava/src/com/google/common/io/CharSequenceReader.java +++ b/guava/src/com/google/common/io/CharSequenceReader.java @@ -124,6 +124,7 @@ public synchronized void reset() throws IOException { } @Override + @SuppressWarnings("nullness") // Other methods call checkOpen before reading seq. public synchronized void close() throws IOException { seq = null; } diff --git a/guava/src/com/google/common/io/CharSource.java b/guava/src/com/google/common/io/CharSource.java index ac3df0c87cc1..53ce47a9a92a 100644 --- a/guava/src/com/google/common/io/CharSource.java +++ b/guava/src/com/google/common/io/CharSource.java @@ -582,7 +582,7 @@ public Stream lines() { } @Override - public String readFirstLine() { + public @Nullable String readFirstLine() { Iterator lines = linesIterator(); return lines.hasNext() ? lines.next() : null; } diff --git a/guava/src/com/google/common/io/CharStreams.java b/guava/src/com/google/common/io/CharStreams.java index 458f40d525cb..5651470d3dee 100644 --- a/guava/src/com/google/common/io/CharStreams.java +++ b/guava/src/com/google/common/io/CharStreams.java @@ -215,7 +215,8 @@ public static List readLines(Readable r) throws IOException { */ @Beta @CanIgnoreReturnValue // some processors won't return a useful result - public static T readLines(Readable readable, LineProcessor processor) throws IOException { + public static T readLines( + Readable readable, LineProcessor processor) throws IOException { checkNotNull(readable); checkNotNull(processor); diff --git a/guava/src/com/google/common/io/Closer.java b/guava/src/com/google/common/io/Closer.java index 82cfcb48dc86..b88c7009ff97 100644 --- a/guava/src/com/google/common/io/Closer.java +++ b/guava/src/com/google/common/io/Closer.java @@ -15,6 +15,7 @@ package com.google.common.io; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -120,7 +121,7 @@ public static Closer create() { */ // close. this word no longer has any meaning to me. @CanIgnoreReturnValue - public C register(@Nullable C closeable) { + public C register(C closeable) { if (closeable != null) { stack.addFirst(closeable); } @@ -264,9 +265,9 @@ static boolean isAvailable() { return addSuppressed != null; } - static final Method addSuppressed = addSuppressedMethodOrNull(); + static final @Nullable Method addSuppressed = addSuppressedMethodOrNull(); - private static Method addSuppressedMethodOrNull() { + private static @Nullable Method addSuppressedMethodOrNull() { try { return Throwable.class.getMethod("addSuppressed", Throwable.class); } catch (Throwable e) { @@ -281,7 +282,8 @@ public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed return; } try { - addSuppressed.invoke(thrown, suppressed); + // requireNonNull is safe because this method is used only if isAvailable(). + requireNonNull(addSuppressed).invoke(thrown, suppressed); } catch (Throwable e) { // if, somehow, IllegalAccessException or another exception is thrown, fall back to logging LoggingSuppressor.INSTANCE.suppress(closeable, thrown, suppressed); diff --git a/guava/src/com/google/common/io/FileBackedOutputStream.java b/guava/src/com/google/common/io/FileBackedOutputStream.java index 8d8effc70fb4..be1f8d139dc1 100644 --- a/guava/src/com/google/common/io/FileBackedOutputStream.java +++ b/guava/src/com/google/common/io/FileBackedOutputStream.java @@ -14,6 +14,8 @@ package com.google.common.io; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.VisibleForTesting; @@ -54,13 +56,13 @@ public final class FileBackedOutputStream extends OutputStream { private final int fileThreshold; private final boolean resetOnFinalize; private final ByteSource source; - @Nullable private final File parentDirectory; + private final @Nullable File parentDirectory; @GuardedBy("this") private OutputStream out; @GuardedBy("this") - private MemoryOutput memory; + private @Nullable MemoryOutput memory; @GuardedBy("this") private @Nullable File file; @@ -78,7 +80,7 @@ int getCount() { /** Returns the file holding the data (possibly null). */ @VisibleForTesting - synchronized File getFile() { + synchronized @Nullable File getFile() { return file; } @@ -153,6 +155,8 @@ private synchronized InputStream openInputStream() throws IOException { if (file != null) { return new FileInputStream(file); } else { + // requireNonNull is safe because we always have either `file` or `memory`. + requireNonNull(memory); return new ByteArrayInputStream(memory.getBuffer(), 0, memory.getCount()); } } @@ -216,7 +220,7 @@ public synchronized void flush() throws IOException { */ @GuardedBy("this") private void update(int len) throws IOException { - if (file == null && (memory.getCount() + len > fileThreshold)) { + if (memory != null && (memory.getCount() + len > fileThreshold)) { File temp = File.createTempFile("FileBackedOutputStream", null, parentDirectory); if (resetOnFinalize) { // Finalizers are not guaranteed to be called on system shutdown; diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java index a23cd96b3963..4a7cf0bfb339 100644 --- a/guava/src/com/google/common/io/Files.java +++ b/guava/src/com/google/common/io/Files.java @@ -52,6 +52,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Provides utility methods for working with {@linkplain File files}. @@ -339,8 +340,7 @@ public static void copy(File from, File to) throws IOException { */ @Beta @Deprecated - public - static void copy(File from, Charset charset, Appendable to) throws IOException { + public static void copy(File from, Charset charset, Appendable to) throws IOException { asCharSource(from, charset).copyTo(to); } @@ -357,8 +357,7 @@ static void copy(File from, Charset charset, Appendable to) throws IOException { */ @Beta @Deprecated - public - static void append(CharSequence from, File to, Charset charset) throws IOException { + public static void append(CharSequence from, File to, Charset charset) throws IOException { asCharSink(to, charset, FileWriteMode.APPEND).write(from); } @@ -517,8 +516,7 @@ public static void move(File from, File to) throws IOException { */ @Beta @Deprecated - public - static String readFirstLine(File file, Charset charset) throws IOException { + public static @Nullable String readFirstLine(File file, Charset charset) throws IOException { return asCharSource(file, charset).readFirstLine(); } @@ -576,8 +574,8 @@ public List getResult() { @Beta @Deprecated @CanIgnoreReturnValue // some processors won't return a useful result - public - static T readLines(File file, Charset charset, LineProcessor callback) throws IOException { + public static T readLines( + File file, Charset charset, LineProcessor callback) throws IOException { return asCharSource(file, charset).readLines(callback); } @@ -596,8 +594,8 @@ static T readLines(File file, Charset charset, LineProcessor callback) th @Beta @Deprecated @CanIgnoreReturnValue // some processors won't return a useful result - public - static T readBytes(File file, ByteProcessor processor) throws IOException { + public static T readBytes(File file, ByteProcessor processor) + throws IOException { return asByteSource(file).read(processor); } @@ -614,8 +612,7 @@ static T readBytes(File file, ByteProcessor processor) throws IOException */ @Beta @Deprecated - public - static HashCode hash(File file, HashFunction hashFunction) throws IOException { + public static HashCode hash(File file, HashFunction hashFunction) throws IOException { return asByteSource(file).hash(hashFunction); } diff --git a/guava/src/com/google/common/io/LineProcessor.java b/guava/src/com/google/common/io/LineProcessor.java index 65ded53a4701..2940ecd60982 100644 --- a/guava/src/com/google/common/io/LineProcessor.java +++ b/guava/src/com/google/common/io/LineProcessor.java @@ -18,6 +18,7 @@ import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A callback to be used with the streaming {@code readLines} methods. diff --git a/guava/src/com/google/common/io/LineReader.java b/guava/src/com/google/common/io/LineReader.java index 1ccb4d12b8b9..ebafb5b8f654 100644 --- a/guava/src/com/google/common/io/LineReader.java +++ b/guava/src/com/google/common/io/LineReader.java @@ -68,7 +68,7 @@ public LineReader(Readable readable) { * @throws IOException if an I/O error occurs */ @CanIgnoreReturnValue // to skip a line - public String readLine() throws IOException { + public @Nullable String readLine() throws IOException { while (lines.peek() == null) { cbuf.clear(); // The default implementation of Reader#read(CharBuffer) allocates a diff --git a/guava/src/com/google/common/io/MultiInputStream.java b/guava/src/com/google/common/io/MultiInputStream.java index 71a97d37d401..66bed0ed1e4f 100644 --- a/guava/src/com/google/common/io/MultiInputStream.java +++ b/guava/src/com/google/common/io/MultiInputStream.java @@ -90,7 +90,7 @@ public int read() throws IOException { } @Override - public int read(byte @Nullable [] b, int off, int len) throws IOException { + public int read(byte[] b, int off, int len) throws IOException { while (in != null) { int result = in.read(b, off, len); if (result != -1) { diff --git a/guava/src/com/google/common/io/MultiReader.java b/guava/src/com/google/common/io/MultiReader.java index 135f32e4a097..c73b905cc7f5 100644 --- a/guava/src/com/google/common/io/MultiReader.java +++ b/guava/src/com/google/common/io/MultiReader.java @@ -46,7 +46,7 @@ private void advance() throws IOException { } @Override - public int read(char @Nullable [] cbuf, int off, int len) throws IOException { + public int read(char[] cbuf, int off, int len) throws IOException { if (current == null) { return -1; } diff --git a/guava/src/com/google/common/io/PatternFilenameFilter.java b/guava/src/com/google/common/io/PatternFilenameFilter.java index 4058e7d29602..e648cf879554 100644 --- a/guava/src/com/google/common/io/PatternFilenameFilter.java +++ b/guava/src/com/google/common/io/PatternFilenameFilter.java @@ -56,7 +56,19 @@ public PatternFilenameFilter(Pattern pattern) { } @Override - public boolean accept(@Nullable File dir, String fileName) { + /* + * Our implementation works fine with a null `dir`. However, there's nothing in the documentation + * of the supertype that suggests that implementations are expected to tolerate null. That said, I + * see calls in Google code that pass a null `dir` to a FilenameFilter.... So let's declare the + * parameter as non-nullable (since passing null to a FilenameFilter is unsafe in general), but if + * someone still manages to pass null, let's continue to have the method work. + * + * (PatternFilenameFilter is of course one of those classes that shouldn't be a publicly visible + * class to begin with but rather something returned from a static factory method whose declared + * return type is plain FilenameFilter. If we made such a change, then the annotation we choose + * here would have no significance to end users.) + */ + public boolean accept(File dir, String fileName) { return pattern.matcher(fileName).matches(); } } diff --git a/guava/src/com/google/common/io/Resources.java b/guava/src/com/google/common/io/Resources.java index d64bf3d51d65..9809f60d5ab1 100644 --- a/guava/src/com/google/common/io/Resources.java +++ b/guava/src/com/google/common/io/Resources.java @@ -14,7 +14,6 @@ package com.google.common.io; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; @@ -29,6 +28,7 @@ import java.net.URL; import java.nio.charset.Charset; import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Provides utility methods for working with resources in the classpath. Note that even though these @@ -121,8 +121,8 @@ public static String toString(URL url, Charset charset) throws IOException { * @throws IOException if an I/O error occurs */ @CanIgnoreReturnValue // some processors won't return a useful result - public static T readLines(URL url, Charset charset, LineProcessor callback) - throws IOException { + public static T readLines( + URL url, Charset charset, LineProcessor callback) throws IOException { return asCharSource(url, charset).readLines(callback); } @@ -192,7 +192,9 @@ public static URL getResource(String resourceName) { MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader()); URL url = loader.getResource(resourceName); - checkArgument(url != null, "resource %s not found.", resourceName); + if (url == null) { + throw new IllegalArgumentException("resource " + resourceName + " not found."); + } return url; } @@ -205,8 +207,10 @@ public static URL getResource(String resourceName) { @CanIgnoreReturnValue // being used to check if a resource exists public static URL getResource(Class contextClass, String resourceName) { URL url = contextClass.getResource(resourceName); - checkArgument( - url != null, "resource %s relative to %s not found.", resourceName, contextClass.getName()); + if (url == null) { + throw new IllegalArgumentException( + "resource " + resourceName + " relative to " + contextClass.getName() + " not found."); + } return url; } } diff --git a/guava/src/com/google/common/math/LinearTransformation.java b/guava/src/com/google/common/math/LinearTransformation.java index 485b04660902..f31d45939950 100644 --- a/guava/src/com/google/common/math/LinearTransformation.java +++ b/guava/src/com/google/common/math/LinearTransformation.java @@ -21,6 +21,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.concurrent.LazyInit; +import org.checkerframework.checker.nullness.qual.Nullable; /** * The representation of a linear transformation between real numbers {@code x} and {@code y}. @@ -161,7 +162,7 @@ private static final class RegularLinearTransformation extends LinearTransformat final double slope; final double yIntercept; - @LazyInit LinearTransformation inverse; + @LazyInit @Nullable LinearTransformation inverse; RegularLinearTransformation(double slope, double yIntercept) { this.slope = slope; @@ -219,7 +220,7 @@ private static final class VerticalLinearTransformation extends LinearTransforma final double x; - @LazyInit LinearTransformation inverse; + @LazyInit @Nullable LinearTransformation inverse; VerticalLinearTransformation(double x) { this.x = x; diff --git a/guava/src/com/google/common/net/HostAndPort.java b/guava/src/com/google/common/net/HostAndPort.java index c01b87a15cd5..c926fcf49746 100644 --- a/guava/src/com/google/common/net/HostAndPort.java +++ b/guava/src/com/google/common/net/HostAndPort.java @@ -21,7 +21,6 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Objects; -import com.google.common.base.Strings; import com.google.errorprone.annotations.Immutable; import java.io.Serializable; import org.checkerframework.checker.nullness.qual.Nullable; @@ -186,7 +185,7 @@ public static HostAndPort fromString(String hostPortString) { } int port = NO_PORT; - if (!Strings.isNullOrEmpty(portString)) { + if (portString != null && !portString.isEmpty()) { // Try to parse the whole port string as a number. // JDK7 accepts leading plus signs. We don't want to. checkArgument(!portString.startsWith("+"), "Unparseable port number: %s", hostPortString); diff --git a/guava/src/com/google/common/net/HttpHeaders.java b/guava/src/com/google/common/net/HttpHeaders.java index 0f664978e247..c52b69a32b04 100644 --- a/guava/src/com/google/common/net/HttpHeaders.java +++ b/guava/src/com/google/common/net/HttpHeaders.java @@ -28,7 +28,6 @@ *

  • RFC 5988 * * - * * @author Kurt Alfred Kluever * @since 11.0 */ diff --git a/guava/src/com/google/common/net/InetAddresses.java b/guava/src/com/google/common/net/InetAddresses.java index 7af7e974319b..331e25ab2fb3 100644 --- a/guava/src/com/google/common/net/InetAddresses.java +++ b/guava/src/com/google/common/net/InetAddresses.java @@ -161,7 +161,10 @@ public static boolean isInetAddress(String ipString) { } /** Returns {@code null} if unable to parse into a {@code byte[]}. */ - private static byte @Nullable [] ipStringToBytes(String ipString) { + private static byte @Nullable [] ipStringToBytes(String ipStringParam) { + // Declare a "true" local variable so that the Checker Framework will infer nullness. + String ipString = ipStringParam; + // Make a first pass to categorize the characters in this string. boolean hasColon = false; boolean hasDot = false; diff --git a/guava/src/com/google/common/net/InternetDomainName.java b/guava/src/com/google/common/net/InternetDomainName.java index c5414137af47..106e6b179a8e 100644 --- a/guava/src/com/google/common/net/InternetDomainName.java +++ b/guava/src/com/google/common/net/InternetDomainName.java @@ -200,7 +200,6 @@ private int findSuffixOfType(Optional desiredType) { * href="https://tools.ietf.org/html/rfc1123#section-2">RFC 1123. * * - * * @param domain A domain name (not IP address) * @throws IllegalArgumentException if {@code domain} is not syntactically valid according to * {@link #isValid} @@ -354,7 +353,7 @@ public boolean hasPublicSuffix() { * * @since 6.0 */ - public InternetDomainName publicSuffix() { + public @Nullable InternetDomainName publicSuffix() { return hasPublicSuffix() ? ancestor(publicSuffixIndex) : null; } @@ -462,7 +461,7 @@ public boolean hasRegistrySuffix() { * * @since 23.3 */ - public InternetDomainName registrySuffix() { + public @Nullable InternetDomainName registrySuffix() { return hasRegistrySuffix() ? ancestor(registrySuffixIndex) : null; } diff --git a/guava/src/com/google/common/net/MediaType.java b/guava/src/com/google/common/net/MediaType.java index 27babd858d23..41c3de281174 100644 --- a/guava/src/com/google/common/net/MediaType.java +++ b/guava/src/com/google/common/net/MediaType.java @@ -699,11 +699,11 @@ private static MediaType addKnownType(MediaType mediaType) { private final String subtype; private final ImmutableListMultimap parameters; - @LazyInit private String toString; + @LazyInit private @Nullable String toString; @LazyInit private int hashCode; - @LazyInit private Optional parsedCharset; + @LazyInit private @Nullable Optional parsedCharset; private MediaType(String type, String subtype, ImmutableListMultimap parameters) { this.type = type; diff --git a/guava/src/com/google/common/net/PercentEscaper.java b/guava/src/com/google/common/net/PercentEscaper.java index 554d04d78d7a..27ede9b67ae4 100644 --- a/guava/src/com/google/common/net/PercentEscaper.java +++ b/guava/src/com/google/common/net/PercentEscaper.java @@ -19,6 +19,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.escape.UnicodeEscaper; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@code UnicodeEscaper} that escapes some set of Java characters using a UTF-8 based percent @@ -155,7 +156,7 @@ public String escape(String s) { /** Escapes the given Unicode code point in UTF-8. */ @Override - protected char[] escape(int cp) { + protected char @Nullable [] escape(int cp) { // We should never get negative values here but if we do it will throw an // IndexOutOfBoundsException, so at least it will get spotted. if (cp < safeOctets.length && safeOctets[cp]) { diff --git a/guava/src/com/google/common/net/UrlEscapers.java b/guava/src/com/google/common/net/UrlEscapers.java index d4b9f94aac42..fead824191e0 100644 --- a/guava/src/com/google/common/net/UrlEscapers.java +++ b/guava/src/com/google/common/net/UrlEscapers.java @@ -24,7 +24,6 @@ * escaping with {@link com.google.common.html.HtmlEscapers} or {@link * com.google.common.xml.XmlEscapers}. * - * * @author David Beaumont * @author Chris Povirk * @since 15.0 @@ -69,7 +68,6 @@ private UrlEscapers() {} * *

    Note: Unlike other escapers, URL escapers produce uppercase hexadecimal sequences. - * */ public static Escaper urlFormParameterEscaper() { return URL_FORM_PARAMETER_ESCAPER; diff --git a/guava/src/com/google/common/primitives/Booleans.java b/guava/src/com/google/common/primitives/Booleans.java index 11ce0623dd5d..44c9503e5ddd 100644 --- a/guava/src/com/google/common/primitives/Booleans.java +++ b/guava/src/com/google/common/primitives/Booleans.java @@ -340,6 +340,7 @@ public String toString() { * to primitives * @throws NullPointerException if {@code collection} or any of its elements is null */ +@SuppressWarnings("nullness") public static boolean[] toArray(Collection collection) { if (collection instanceof BooleanArrayAsList) { return ((BooleanArrayAsList) collection).toBooleanArray(); @@ -408,14 +409,14 @@ public Boolean get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Boolean) && Booleans.indexOf(array, (Boolean) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Boolean) { int i = Booleans.indexOf(array, (Boolean) target, start, end); @@ -427,7 +428,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Boolean) { int i = Booleans.lastIndexOf(array, (Boolean) target, start, end); diff --git a/guava/src/com/google/common/primitives/Bytes.java b/guava/src/com/google/common/primitives/Bytes.java index dd8aea0d02db..2440460249d0 100644 --- a/guava/src/com/google/common/primitives/Bytes.java +++ b/guava/src/com/google/common/primitives/Bytes.java @@ -202,6 +202,7 @@ public static byte[] ensureCapacity(byte[] array, int minLength, int padding) { * @throws NullPointerException if {@code collection} or any of its elements is null * @since 1.0 (parameter was {@code Collection} before 12.0) */ +@SuppressWarnings("nullness") public static byte[] toArray(Collection collection) { if (collection instanceof ByteArrayAsList) { return ((ByteArrayAsList) collection).toByteArray(); @@ -270,13 +271,13 @@ public Byte get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Byte) && Bytes.indexOf(array, (Byte) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Byte) { int i = Bytes.indexOf(array, (Byte) target, start, end); @@ -288,7 +289,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Byte) { int i = Bytes.lastIndexOf(array, (Byte) target, start, end); diff --git a/guava/src/com/google/common/primitives/Chars.java b/guava/src/com/google/common/primitives/Chars.java index 4cdc2ff48612..b08f6a2ac74d 100644 --- a/guava/src/com/google/common/primitives/Chars.java +++ b/guava/src/com/google/common/primitives/Chars.java @@ -418,6 +418,7 @@ public String toString() { * to primitives * @throws NullPointerException if {@code collection} or any of its elements is null */ +@SuppressWarnings("nullness") public static char[] toArray(Collection collection) { if (collection instanceof CharArrayAsList) { return ((CharArrayAsList) collection).toCharArray(); @@ -540,14 +541,14 @@ public Character get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Character) && Chars.indexOf(array, (Character) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Character) { int i = Chars.indexOf(array, (Character) target, start, end); @@ -559,7 +560,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Character) { int i = Chars.lastIndexOf(array, (Character) target, start, end); diff --git a/guava/src/com/google/common/primitives/Doubles.java b/guava/src/com/google/common/primitives/Doubles.java index eb865da9043a..7610628312f3 100644 --- a/guava/src/com/google/common/primitives/Doubles.java +++ b/guava/src/com/google/common/primitives/Doubles.java @@ -475,6 +475,7 @@ public static void reverse(double[] array, int fromIndex, int toIndex) { * @throws NullPointerException if {@code collection} or any of its elements is null * @since 1.0 (parameter was {@code Collection} before 12.0) */ +@SuppressWarnings("nullness") public static double[] toArray(Collection collection) { if (collection instanceof DoubleArrayAsList) { return ((DoubleArrayAsList) collection).toDoubleArray(); @@ -554,14 +555,14 @@ public Spliterator.OfDouble spliterator() { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Double) && Doubles.indexOf(array, (Double) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Double) { int i = Doubles.indexOf(array, (Double) target, start, end); @@ -573,7 +574,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Double) { int i = Doubles.lastIndexOf(array, (Double) target, start, end); @@ -656,14 +657,10 @@ public String toString() { * that pass this regex are valid -- only a performance hit is incurred, not a semantics bug. */ @GwtIncompatible // regular expressions - static final - java.util.regex.Pattern - FLOATING_POINT_PATTERN = fpPattern(); + static final java.util.regex.Pattern FLOATING_POINT_PATTERN = fpPattern(); @GwtIncompatible // regular expressions - private static - java.util.regex.Pattern - fpPattern() { + private static java.util.regex.Pattern fpPattern() { /* * We use # instead of * for possessive quantifiers. This lets us strip them out when building * the regex for RE2 (which doesn't support them) but leave them in when building it for @@ -674,14 +671,8 @@ public String toString() { String hex = "(?:[0-9a-fA-F]+#(?:\\.[0-9a-fA-F]*#)?|\\.[0-9a-fA-F]+#)"; String completeHex = "0[xX]" + hex + "[pP][+-]?\\d+#[fFdD]?"; String fpPattern = "[+-]?(?:NaN|Infinity|" + completeDec + "|" + completeHex + ")"; - fpPattern = - fpPattern.replace( - "#", - "+" - ); - return - java.util.regex.Pattern - .compile(fpPattern); + fpPattern = fpPattern.replace("#", "+"); + return java.util.regex.Pattern.compile(fpPattern); } /** diff --git a/guava/src/com/google/common/primitives/Floats.java b/guava/src/com/google/common/primitives/Floats.java index 1a99f41ebe2b..084c1f53efa4 100644 --- a/guava/src/com/google/common/primitives/Floats.java +++ b/guava/src/com/google/common/primitives/Floats.java @@ -470,6 +470,7 @@ public static void reverse(float[] array, int fromIndex, int toIndex) { * @throws NullPointerException if {@code collection} or any of its elements is null * @since 1.0 (parameter was {@code Collection} before 12.0) */ +@SuppressWarnings("nullness") public static float[] toArray(Collection collection) { if (collection instanceof FloatArrayAsList) { return ((FloatArrayAsList) collection).toFloatArray(); @@ -541,13 +542,13 @@ public Float get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Float) && Floats.indexOf(array, (Float) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Float) { int i = Floats.indexOf(array, (Float) target, start, end); @@ -559,7 +560,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Float) { int i = Floats.lastIndexOf(array, (Float) target, start, end); diff --git a/guava/src/com/google/common/primitives/ImmutableDoubleArray.java b/guava/src/com/google/common/primitives/ImmutableDoubleArray.java index f2111cb1b4b6..2ca62d8804f9 100644 --- a/guava/src/com/google/common/primitives/ImmutableDoubleArray.java +++ b/guava/src/com/google/common/primitives/ImmutableDoubleArray.java @@ -427,6 +427,7 @@ public DoubleStream stream() { } /** Returns a new, mutable copy of this array's values, as a primitive {@code double[]}. */ +@SuppressWarnings("nullness") public double[] toArray() { return Arrays.copyOfRange(array, start, end); } @@ -485,17 +486,17 @@ public Double get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { return indexOf(target) >= 0; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { return target instanceof Double ? parent.indexOf((Double) target) : -1; } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { return target instanceof Double ? parent.lastIndexOf((Double) target) : -1; } diff --git a/guava/src/com/google/common/primitives/ImmutableIntArray.java b/guava/src/com/google/common/primitives/ImmutableIntArray.java index 6d1e8a06bcd4..252c48a1ab32 100644 --- a/guava/src/com/google/common/primitives/ImmutableIntArray.java +++ b/guava/src/com/google/common/primitives/ImmutableIntArray.java @@ -422,6 +422,7 @@ public IntStream stream() { } /** Returns a new, mutable copy of this array's values, as a primitive {@code int[]}. */ +@SuppressWarnings("nullness") public int[] toArray() { return Arrays.copyOfRange(array, start, end); } @@ -480,17 +481,17 @@ public Integer get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { return indexOf(target) >= 0; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { return target instanceof Integer ? parent.indexOf((Integer) target) : -1; } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { return target instanceof Integer ? parent.lastIndexOf((Integer) target) : -1; } diff --git a/guava/src/com/google/common/primitives/ImmutableLongArray.java b/guava/src/com/google/common/primitives/ImmutableLongArray.java index 280afd0eafc8..5d29bac5cfb2 100644 --- a/guava/src/com/google/common/primitives/ImmutableLongArray.java +++ b/guava/src/com/google/common/primitives/ImmutableLongArray.java @@ -424,6 +424,7 @@ public LongStream stream() { } /** Returns a new, mutable copy of this array's values, as a primitive {@code long[]}. */ +@SuppressWarnings("nullness") public long[] toArray() { return Arrays.copyOfRange(array, start, end); } @@ -482,17 +483,17 @@ public Long get(int index) { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { return indexOf(target) >= 0; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { return target instanceof Long ? parent.indexOf((Long) target) : -1; } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { return target instanceof Long ? parent.lastIndexOf((Long) target) : -1; } diff --git a/guava/src/com/google/common/primitives/Ints.java b/guava/src/com/google/common/primitives/Ints.java index ad8c8c123cf4..909361733178 100644 --- a/guava/src/com/google/common/primitives/Ints.java +++ b/guava/src/com/google/common/primitives/Ints.java @@ -524,6 +524,7 @@ public static void reverse(int[] array, int fromIndex, int toIndex) { * @throws NullPointerException if {@code collection} or any of its elements is null * @since 1.0 (parameter was {@code Collection} before 12.0) */ +@SuppressWarnings("nullness") public static int[] toArray(Collection collection) { if (collection instanceof IntArrayAsList) { return ((IntArrayAsList) collection).toIntArray(); @@ -600,13 +601,13 @@ public Spliterator.OfInt spliterator() { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Integer) && Ints.indexOf(array, (Integer) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Integer) { int i = Ints.indexOf(array, (Integer) target, start, end); @@ -618,7 +619,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Integer) { int i = Ints.lastIndexOf(array, (Integer) target, start, end); diff --git a/guava/src/com/google/common/primitives/Longs.java b/guava/src/com/google/common/primitives/Longs.java index e496f006b527..34c7745a62cd 100644 --- a/guava/src/com/google/common/primitives/Longs.java +++ b/guava/src/com/google/common/primitives/Longs.java @@ -618,6 +618,7 @@ public static void reverse(long[] array, int fromIndex, int toIndex) { * @throws NullPointerException if {@code collection} or any of its elements is null * @since 1.0 (parameter was {@code Collection} before 12.0) */ +@SuppressWarnings("nullness") public static long[] toArray(Collection collection) { if (collection instanceof LongArrayAsList) { return ((LongArrayAsList) collection).toLongArray(); @@ -694,13 +695,13 @@ public Spliterator.OfLong spliterator() { } @Override - public boolean contains(Object target) { + public boolean contains(@Nullable Object target) { // Overridden to prevent a ton of boxing return (target instanceof Long) && Longs.indexOf(array, (Long) target, start, end) != -1; } @Override - public int indexOf(Object target) { + public int indexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Long) { int i = Longs.indexOf(array, (Long) target, start, end); @@ -712,7 +713,7 @@ public int indexOf(Object target) { } @Override - public int lastIndexOf(Object target) { + public int lastIndexOf(@Nullable Object target) { // Overridden to prevent a ton of boxing if (target instanceof Long) { int i = Longs.lastIndexOf(array, (Long) target, start, end); diff --git a/guava/src/com/google/common/primitives/Platform.java b/guava/src/com/google/common/primitives/Platform.java index 1273c043bc1c..7bcb0df1b658 100644 --- a/guava/src/com/google/common/primitives/Platform.java +++ b/guava/src/com/google/common/primitives/Platform.java @@ -41,7 +41,6 @@ static void checkGwtRpcEnabled() { + " warning because you are sending a Guava type over GWT-RPC, which will break. You" + " can identify which type by looking at the class name in the attached stack trace.", new Throwable()); - } private Platform() {} diff --git a/guava/src/com/google/common/primitives/Primitives.java b/guava/src/com/google/common/primitives/Primitives.java index 1bdc7400f330..dd6b6b76a8ae 100644 --- a/guava/src/com/google/common/primitives/Primitives.java +++ b/guava/src/com/google/common/primitives/Primitives.java @@ -21,6 +21,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Contains static utility methods pertaining to primitive types and their corresponding wrapper @@ -59,11 +60,15 @@ private Primitives() {} WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim); } + /* + * Someday, when our nullness-checking project has evolved further, we will revert the instances + * of raw Class below. They are here to work around the Checker Framework's unusual handling of + * Void/void.class. (Specifically, it treats those objects as always having type Class<@Nullable + * Void>. That's a problem because we expect to treat Class as always having its parameter be + * @NonNull.) + */ private static void add( - Map, Class> forward, - Map, Class> backward, - Class key, - Class value) { + Map, Class> forward, Map, Class> backward, Class key, Class value) { forward.put(key, value); backward.put(value, key); } @@ -108,7 +113,7 @@ public static boolean isWrapperType(Class type) { * wrap(String.class) == String.class * */ - public static Class wrap(Class type) { + public static Class wrap(Class type) { checkNotNull(type); // cast is safe: long.class and Long.class are both of type Class @@ -127,7 +132,7 @@ public static Class wrap(Class type) { * unwrap(String.class) == String.class * */ - public static Class unwrap(Class type) { + public static Class unwrap(Class type) { checkNotNull(type); // cast is safe: long.class and Long.class are both of type Class diff --git a/guava/src/com/google/common/primitives/Shorts.java b/guava/src/com/google/common/primitives/Shorts.java index fa480dd13ed9..6245f1b0412c 100644 --- a/guava/src/com/google/common/primitives/Shorts.java +++ b/guava/src/com/google/common/primitives/Shorts.java @@ -524,6 +524,7 @@ public static void reverse(short[] array, int fromIndex, int toIndex) { * @throws NullPointerException if {@code collection} or any of its elements is null * @since 1.0 (parameter was {@code Collection} before 12.0) */ +@SuppressWarnings("nullness") public static short[] toArray(Collection collection) { if (collection instanceof ShortArrayAsList) { return ((ShortArrayAsList) collection).toShortArray(); diff --git a/guava/src/com/google/common/primitives/UnsignedBytes.java b/guava/src/com/google/common/primitives/UnsignedBytes.java index 4275f8a6ecc5..d94331300145 100644 --- a/guava/src/com/google/common/primitives/UnsignedBytes.java +++ b/guava/src/com/google/common/primitives/UnsignedBytes.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndexes; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -348,7 +349,8 @@ public sun.misc.Unsafe run() throws Exception { Class k = sun.misc.Unsafe.class; for (java.lang.reflect.Field f : k.getDeclaredFields()) { f.setAccessible(true); - Object x = f.get(null); + // unsafeNull is safe because we're reading a static field. + Object x = f.get(unsafeNull()); if (k.isInstance(x)) { return k.cast(x); } @@ -361,6 +363,11 @@ public sun.misc.Unsafe run() throws Exception { } } + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } + @Override public int compare(byte[] left, byte[] right) { final int stride = 8; @@ -437,9 +444,13 @@ static Comparator getBestComparator() { try { Class theClass = Class.forName(UNSAFE_COMPARATOR_NAME); + // requireNonNull is safe because the class is an enum. + // Inlining this causes a crash: https://github.com/typetools/checker-framework/issues/3020 + Object[] constants = requireNonNull(theClass.getEnumConstants()); + // yes, UnsafeComparator does implement Comparator @SuppressWarnings("unchecked") - Comparator comparator = (Comparator) theClass.getEnumConstants()[0]; + Comparator comparator = (Comparator) constants[0]; return comparator; } catch (Throwable t) { // ensure we really catch *everything* return lexicographicalComparatorJavaImpl(); diff --git a/guava/src/com/google/common/reflect/AbstractInvocationHandler.java b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java index 45aea776f9cc..6440411b4c25 100644 --- a/guava/src/com/google/common/reflect/AbstractInvocationHandler.java +++ b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java @@ -59,8 +59,8 @@ public abstract class AbstractInvocationHandler implements InvocationHandler { * */ @Override - public final Object invoke(Object proxy, Method method, Object @Nullable [] args) - throws Throwable { + public final @Nullable Object invoke( + Object proxy, Method method, @Nullable Object @Nullable [] args) throws Throwable { if (args == null) { args = NO_ARGS; } @@ -94,8 +94,8 @@ public final Object invoke(Object proxy, Method method, Object @Nullable [] args *

    Unlike {@link #invoke}, {@code args} will never be null. When the method has no parameter, * an empty array is passed in. */ - protected abstract Object handleInvocation(Object proxy, Method method, Object[] args) - throws Throwable; + protected abstract @Nullable Object handleInvocation( + Object proxy, Method method, @Nullable Object[] args) throws Throwable; /** * By default delegates to {@link Object#equals} so instances are only equal if they are @@ -109,7 +109,7 @@ protected abstract Object handleInvocation(Object proxy, Method method, Object[] *

    Subclasses can override this method to provide custom equality. */ @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { return super.equals(obj); } diff --git a/guava/src/com/google/common/reflect/ClassPath.java b/guava/src/com/google/common/reflect/ClassPath.java index fb950234579f..2cee78f04b67 100644 --- a/guava/src/com/google/common/reflect/ClassPath.java +++ b/guava/src/com/google/common/reflect/ClassPath.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH; import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR; +import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import com.google.common.annotations.Beta; @@ -245,7 +246,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof ResourceInfo) { ResourceInfo that = (ResourceInfo) obj; return resourceName.equals(that.resourceName) && loader == that.loader; @@ -475,7 +476,15 @@ private static ImmutableList getClassLoaderUrls(ClassLoader classloader) { @VisibleForTesting // TODO(b/65488446): Make this a public API. static ImmutableList parseJavaClassPath() { ImmutableList.Builder urls = ImmutableList.builder(); - for (String entry : Splitter.on(PATH_SEPARATOR.value()).split(JAVA_CLASS_PATH.value())) { + /* + * requireNonNull should be safe: Values are always supposed to exist for the system + * properties that we use. If they don't, we could consider returning an empty list instead of + * throwing NullPointerException. But it's not clear at the moment which behavior would be + * more helpful. + */ + for (String entry : + Splitter.on(requireNonNull(PATH_SEPARATOR.value())) + .split(requireNonNull(JAVA_CLASS_PATH.value()))) { try { try { urls.add(new File(entry).toURI().toURL()); diff --git a/guava/src/com/google/common/reflect/Element.java b/guava/src/com/google/common/reflect/Element.java index c63c09aaff31..903b3af50cf6 100644 --- a/guava/src/com/google/common/reflect/Element.java +++ b/guava/src/com/google/common/reflect/Element.java @@ -52,7 +52,7 @@ public final boolean isAnnotationPresent(Class annotationC } @Override - public final A getAnnotation(Class annotationClass) { + public final @Nullable A getAnnotation(Class annotationClass) { return accessibleObject.getAnnotation(annotationClass); } diff --git a/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java index 354fd19835bd..b6c5ec50c327 100644 --- a/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java +++ b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java @@ -14,11 +14,15 @@ package com.google.common.reflect; +import static java.util.Collections.unmodifiableMap; + import com.google.common.annotations.Beta; import com.google.common.collect.ForwardingMap; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A type-to-instance map backed by an {@link ImmutableMap}. See also {@link @@ -28,16 +32,16 @@ * @since 13.0 */ @Beta -public final class ImmutableTypeToInstanceMap extends ForwardingMap, B> - implements TypeToInstanceMap { +public final class ImmutableTypeToInstanceMap + extends ForwardingMap, @Nullable B> implements TypeToInstanceMap { /** Returns an empty type to instance map. */ - public static ImmutableTypeToInstanceMap of() { + public static ImmutableTypeToInstanceMap of() { return new ImmutableTypeToInstanceMap(ImmutableMap., B>of()); } /** Returns a new builder. */ - public static Builder builder() { + public static Builder builder() { return new Builder(); } @@ -58,7 +62,7 @@ public static Builder builder() { * @since 13.0 */ @Beta - public static final class Builder { + public static final class Builder { private final ImmutableMap.Builder, B> mapBuilder = ImmutableMap.builder(); @@ -94,19 +98,20 @@ public ImmutableTypeToInstanceMap build() { } } - private final ImmutableMap, B> delegate; + private final Map, @Nullable B> delegate; private ImmutableTypeToInstanceMap(ImmutableMap, B> delegate) { - this.delegate = delegate; + // Convert from Map<..., B> to Map<..., @Nullable B>. + this.delegate = unmodifiableMap(delegate); } @Override - public T getInstance(TypeToken type) { + public @Nullable T getInstance(TypeToken type) { return trustedGet(type.rejectTypeVariables()); } @Override - public T getInstance(Class type) { + public @Nullable T getInstance(Class type) { return trustedGet(TypeToken.of(type)); } @@ -119,7 +124,7 @@ public T getInstance(Class type) { @CanIgnoreReturnValue @Deprecated @Override - public T putInstance(TypeToken type, T value) { + public @Nullable T putInstance(TypeToken type, @Nullable T value) { throw new UnsupportedOperationException(); } @@ -132,7 +137,7 @@ public T putInstance(TypeToken type, T value) { @CanIgnoreReturnValue @Deprecated @Override - public T putInstance(Class type, T value) { + public @Nullable T putInstance(Class type, @Nullable T value) { throw new UnsupportedOperationException(); } @@ -145,7 +150,7 @@ public T putInstance(Class type, T value) { @CanIgnoreReturnValue @Deprecated @Override - public B put(TypeToken key, B value) { + public @Nullable B put(TypeToken key, @Nullable B value) { throw new UnsupportedOperationException(); } @@ -157,17 +162,17 @@ public B put(TypeToken key, B value) { */ @Deprecated @Override - public void putAll(Map, ? extends B> map) { + public void putAll(Map, ? extends @Nullable B> map) { throw new UnsupportedOperationException(); } @Override - protected Map, B> delegate() { + protected Map, @Nullable B> delegate() { return delegate; } @SuppressWarnings("unchecked") // value could not get in if not a T - private T trustedGet(TypeToken type) { + private @Nullable T trustedGet(TypeToken type) { return (T) delegate.get(type); } } diff --git a/guava/src/com/google/common/reflect/Invokable.java b/guava/src/com/google/common/reflect/Invokable.java index e0a9ab509b2d..d6202db16984 100644 --- a/guava/src/com/google/common/reflect/Invokable.java +++ b/guava/src/com/google/common/reflect/Invokable.java @@ -31,6 +31,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.Arrays; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -56,7 +57,8 @@ * @since 14.0 */ @Beta -public abstract class Invokable extends Element implements GenericDeclaration { +public abstract class Invokable + extends Element implements GenericDeclaration { Invokable(M member) { super(member); @@ -68,7 +70,7 @@ public static Invokable from(Method method) { } /** Returns {@link Invokable} of {@code constructor}. */ - public static Invokable from(Constructor constructor) { + public static Invokable from(Constructor constructor) { return new ConstructorInvokable(constructor); } @@ -94,12 +96,12 @@ public static Invokable from(Constructor constructor) { * invocation conversion. * @throws InvocationTargetException if the underlying method or constructor throws an exception. */ - // All subclasses are owned by us and we'll make sure to get the R type right. - @SuppressWarnings("unchecked") + // All subclasses are owned by us and we'll make sure to get the R type right, including nullness. + @SuppressWarnings({"unchecked", "nullness"}) @CanIgnoreReturnValue - public final R invoke(@Nullable T receiver, Object... args) + public final @Nullable R invoke(@Nullable T receiver, Object... args) throws InvocationTargetException, IllegalAccessException { - return (R) invokeInternal(receiver, checkNotNull(args)); + return (@Nullable R) invokeInternal(receiver, checkNotNull(args)); } /** Returns the return type of this {@code Invokable}. */ @@ -177,7 +179,7 @@ public TypeToken getOwnerType() { return (TypeToken) TypeToken.of(getDeclaringClass()); } - abstract Object invokeInternal(@Nullable Object receiver, Object[] args) + abstract @Nullable Object invokeInternal(@Nullable Object receiver, Object[] args) throws InvocationTargetException, IllegalAccessException; abstract Type[] getGenericParameterTypes(); @@ -193,7 +195,7 @@ abstract Object invokeInternal(@Nullable Object receiver, Object[] args) public abstract AnnotatedType getAnnotatedReturnType(); - static class MethodInvokable extends Invokable { + static class MethodInvokable extends Invokable { final Method method; @@ -203,9 +205,15 @@ static class MethodInvokable extends Invokable { } @Override - final Object invokeInternal(@Nullable Object receiver, Object[] args) + final @Nullable Object invokeInternal(@Nullable Object receiver, Object[] args) throws InvocationTargetException, IllegalAccessException { - return method.invoke(receiver, args); + /* + * If the method is an instance method, invoke() will throw NullPointerException. That's the + * best we can do without having separate user-visible types for static and instance methods. + */ + @SuppressWarnings("nullness") + Object result = method.invoke(receiver, args); + return result; } @Override @@ -257,7 +265,7 @@ public final boolean isVarArgs() { } } - static class ConstructorInvokable extends Invokable { + static class ConstructorInvokable extends Invokable { final Constructor constructor; @@ -292,6 +300,7 @@ Type getGenericReturnType() { } @Override + @SuppressWarnings("return.type.incompatible") // arrays Type[] getGenericParameterTypes() { Type[] types = constructor.getGenericParameterTypes(); if (types.length > 0 && mayNeedHiddenThis()) { diff --git a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java index c7fe512a59bd..05b5929b05ac 100644 --- a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java +++ b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java @@ -27,6 +27,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -36,10 +37,10 @@ * @since 13.0 */ @Beta -public final class MutableTypeToInstanceMap extends ForwardingMap, B> - implements TypeToInstanceMap { +public final class MutableTypeToInstanceMap + extends ForwardingMap, @Nullable B> implements TypeToInstanceMap { - private final Map, B> backingMap = Maps.newHashMap(); + private final Map, @Nullable B> backingMap = Maps.newHashMap(); @Override public @Nullable T getInstance(Class type) { @@ -72,7 +73,7 @@ public final class MutableTypeToInstanceMap extends ForwardingMap key, B value) { + public @Nullable B put(TypeToken key, @Nullable B value) { throw new UnsupportedOperationException("Please use putInstance() instead."); } @@ -84,17 +85,17 @@ public B put(TypeToken key, B value) { */ @Deprecated @Override - public void putAll(Map, ? extends B> map) { + public void putAll(Map, ? extends @Nullable B> map) { throw new UnsupportedOperationException("Please use putInstance() instead."); } @Override - public Set, B>> entrySet() { + public Set, @Nullable B>> entrySet() { return UnmodifiableEntry.transformEntries(super.entrySet()); } @Override - protected Map, B> delegate() { + protected Map, @Nullable B> delegate() { return backingMap; } @@ -108,7 +109,8 @@ protected Map, B> delegate() { return (T) backingMap.get(type); } - private static final class UnmodifiableEntry extends ForwardingMapEntry { + private static final class UnmodifiableEntry + extends ForwardingMapEntry { private final Entry delegate; @@ -125,18 +127,21 @@ public Iterator> iterator() { } @Override +@SuppressWarnings("nullness") public Object[] toArray() { return standardToArray(); } @Override +@SuppressWarnings("nullness") public T[] toArray(T[] array) { return standardToArray(array); } }; } - private static Iterator> transformEntries(Iterator> entries) { + private static Iterator> transformEntries( + Iterator> entries) { return Iterators.transform( entries, new Function, Entry>() { diff --git a/guava/src/com/google/common/reflect/Reflection.java b/guava/src/com/google/common/reflect/Reflection.java index 4ad5dff78a72..a4f5dc86274c 100644 --- a/guava/src/com/google/common/reflect/Reflection.java +++ b/guava/src/com/google/common/reflect/Reflection.java @@ -20,6 +20,7 @@ import com.google.common.annotations.Beta; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Static utilities relating to Java reflection. @@ -78,7 +79,8 @@ public static void initialize(Class... classes) { * @throws IllegalArgumentException if {@code interfaceType} does not specify the type of a Java * interface */ - public static T newProxy(Class interfaceType, InvocationHandler handler) { + public static T newProxy( + Class interfaceType, InvocationHandler handler) { checkNotNull(handler); checkArgument(interfaceType.isInterface(), "%s is not an interface", interfaceType); Object object = diff --git a/guava/src/com/google/common/reflect/TypeCapture.java b/guava/src/com/google/common/reflect/TypeCapture.java index effb382b2826..42cfcdac0203 100644 --- a/guava/src/com/google/common/reflect/TypeCapture.java +++ b/guava/src/com/google/common/reflect/TypeCapture.java @@ -14,22 +14,23 @@ package com.google.common.reflect; -import static com.google.common.base.Preconditions.checkArgument; - import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Captures the actual type of {@code T}. * * @author Ben Yu */ -abstract class TypeCapture { +abstract class TypeCapture { /** Returns the captured type. */ final Type capture() { Type superclass = getClass().getGenericSuperclass(); - checkArgument(superclass instanceof ParameterizedType, "%s isn't parameterized", superclass); + if (!(superclass instanceof ParameterizedType)) { + throw new IllegalArgumentException(superclass + " isn't parameterized"); + } return ((ParameterizedType) superclass).getActualTypeArguments()[0]; } } diff --git a/guava/src/com/google/common/reflect/TypeParameter.java b/guava/src/com/google/common/reflect/TypeParameter.java index 586c912ae857..fcf575bcfda7 100644 --- a/guava/src/com/google/common/reflect/TypeParameter.java +++ b/guava/src/com/google/common/reflect/TypeParameter.java @@ -19,6 +19,7 @@ import com.google.common.annotations.Beta; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -35,7 +36,15 @@ * @since 12.0 */ @Beta -public abstract class TypeParameter extends TypeCapture { +/* + * A nullable bound would let users create a TypeParameter instance for a parameter with a nullable + * bound. However, it would also let them create `new TypeParameter<@Nullable T>() {}`, which + * wouldn't behave as users might expect. Additionally, it's not clear how the TypeToken API could + * support even a "normal" `TypeParameter` when `` has a nullable bound. (See the discussion + * on TypeToken.where.) So, in the interest of failing fast and encouraging the user to switch to a + * non-null bound if possible, let's require a non-null bound here. + */ +public abstract class TypeParameter extends TypeCapture { final TypeVariable typeVariable; diff --git a/guava/src/com/google/common/reflect/TypeResolver.java b/guava/src/com/google/common/reflect/TypeResolver.java index 339eb43b5850..b5b3bd394ad9 100644 --- a/guava/src/com/google/common/reflect/TypeResolver.java +++ b/guava/src/com/google/common/reflect/TypeResolver.java @@ -35,6 +35,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -162,10 +163,10 @@ void visitParameterizedType(ParameterizedType fromParameterizedType) { return; // Okay to say Foo is } ParameterizedType toParameterizedType = expectArgument(ParameterizedType.class, to); - if (fromParameterizedType.getOwnerType() != null - && toParameterizedType.getOwnerType() != null) { - populateTypeMappings( - mappings, fromParameterizedType.getOwnerType(), toParameterizedType.getOwnerType()); + Type fromOwner = fromParameterizedType.getOwnerType(); + Type toOwner = toParameterizedType.getOwnerType(); + if (fromOwner != null && toOwner != null) { + populateTypeMappings(mappings, fromOwner, toOwner); } checkArgument( fromParameterizedType.getRawType().equals(toParameterizedType.getRawType()), @@ -190,7 +191,9 @@ void visitGenericArrayType(GenericArrayType fromArrayType) { return; // Okay to say A[] is } Type componentType = Types.getComponentType(to); - checkArgument(componentType != null, "%s is not an array type.", to); + if (componentType == null) { + throw new IllegalArgumentException(to + " is not an array type."); + } populateTypeMappings(mappings, fromArrayType.getGenericComponentType(), componentType); } @@ -265,7 +268,7 @@ private ParameterizedType resolveParameterizedType(ParameterizedType type) { resolvedOwner, (Class) resolvedRawType, resolvedArgs); } - private static T expectArgument(Class type, Object arg) { + private static T expectArgument(Class type, Object arg) { try { return type.cast(arg); } catch (ClassCastException e) { @@ -527,7 +530,7 @@ private WildcardCapturer notForTypeVariable() { return new WildcardCapturer(id); } - private Type captureNullable(@Nullable Type type) { + private @Nullable Type captureNullable(@Nullable Type type) { if (type == null) { return null; } @@ -561,7 +564,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof TypeVariableKey) { TypeVariableKey that = (TypeVariableKey) obj; return equalsTypeVariable(that.var); @@ -576,7 +579,7 @@ public String toString() { } /** Wraps {@code t} in a {@code TypeVariableKey} if it's a type variable. */ - static TypeVariableKey forLookup(Type t) { + static @Nullable TypeVariableKey forLookup(Type t) { if (t instanceof TypeVariable) { return new TypeVariableKey((TypeVariable) t); } else { diff --git a/guava/src/com/google/common/reflect/TypeToInstanceMap.java b/guava/src/com/google/common/reflect/TypeToInstanceMap.java index 443b2580cfc5..eadd8d08b54a 100644 --- a/guava/src/com/google/common/reflect/TypeToInstanceMap.java +++ b/guava/src/com/google/common/reflect/TypeToInstanceMap.java @@ -16,8 +16,8 @@ import com.google.common.annotations.Beta; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -40,8 +40,8 @@ * @since 13.0 */ @Beta -@DoNotMock("Use ImmutableTypeToInstanceMap or MutableTypeToInstanceMap") -public interface TypeToInstanceMap extends Map, B> { +public interface TypeToInstanceMap + extends Map, @Nullable B> { /** * Returns the value the specified class is mapped to, or {@code null} if no entry for this class diff --git a/guava/src/com/google/common/reflect/TypeToken.java b/guava/src/com/google/common/reflect/TypeToken.java index 88deff3f4f10..bf79aeacc7c2 100644 --- a/guava/src/com/google/common/reflect/TypeToken.java +++ b/guava/src/com/google/common/reflect/TypeToken.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; @@ -46,6 +47,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -98,7 +100,8 @@ */ @Beta @SuppressWarnings("serial") // SimpleTypeToken is the serialized form. -public abstract class TypeToken extends TypeCapture implements Serializable { +public abstract class TypeToken extends TypeCapture + implements Serializable { private final Type runtimeType; @@ -165,7 +168,7 @@ private TypeToken(Type type) { } /** Returns an instance of type token that wraps {@code type}. */ - public static TypeToken of(Class type) { + public static TypeToken of(Class type) { return new SimpleTypeToken(type); } @@ -220,7 +223,17 @@ public final Type getType() { * @param typeParam the parameter type variable * @param typeArg the actual type to substitute */ - public final TypeToken where(TypeParameter typeParam, TypeToken typeArg) { + /* + * TODO(cpovirk): Is there any way for us to support TypeParameter instances for type parameters + * that have nullable bounds? Unfortunately, if we change the parameter to TypeParameter, then users might pass a TypeParameter, where Y is a subtype of X, while still + * passing a TypeToken. This would be invalid. Maybe we could accept a TypeParameter<@PolyNull + * X> if we support such a thing? It would be weird or misleading for users to be able to pass + * `new TypeParameter<@Nullable T>() {}` and have it act as a plain `TypeParameter`, but + * hopefully no one would do that, anyway. See also the comment on TypeParameter itself. + */ + public final TypeToken where( + TypeParameter typeParam, TypeToken typeArg) { TypeResolver resolver = new TypeResolver() .where( @@ -248,7 +261,12 @@ public final TypeToken where(TypeParameter typeParam, TypeToken typ * @param typeParam the parameter type variable * @param typeArg the actual type to substitute */ - public final TypeToken where(TypeParameter typeParam, Class typeArg) { + /* + * TODO(cpovirk): Is there any way for us to support TypeParameter instances for type parameters + * that have nullable bounds? See discussion on the other overload of this method. + */ + public final TypeToken where( + TypeParameter typeParam, Class typeArg) { return where(typeParam, of(typeArg)); } @@ -905,7 +923,8 @@ private boolean isSubtypeOfParameterizedType(ParameterizedType supertype) { // supertype's owner. return Modifier.isStatic(((Class) supertype.getRawType()).getModifiers()) || supertype.getOwnerType() == null - || isOwnedBySubtypeOf(supertype.getOwnerType()); + // requireNonNull is safe because of the check on the line above. + || isOwnedBySubtypeOf(requireNonNull(supertype.getOwnerType())); } private boolean isSubtypeOfArrayType(GenericArrayType supertype) { @@ -914,7 +933,8 @@ private boolean isSubtypeOfArrayType(GenericArrayType supertype) { if (!fromClass.isArray()) { return false; } - return of(fromClass.getComponentType()).isSubtypeOf(supertype.getGenericComponentType()); + // requireNonNull is safe because of the isArray() check. + return of(requireNonNull(fromClass.getComponentType())).isSubtypeOf(supertype.getGenericComponentType()); } else if (runtimeType instanceof GenericArrayType) { GenericArrayType fromArrayType = (GenericArrayType) runtimeType; return of(fromArrayType.getGenericComponentType()) @@ -930,7 +950,8 @@ private boolean isSupertypeOfArray(GenericArrayType subtype) { if (!thisClass.isArray()) { return thisClass.isAssignableFrom(Object[].class); } - return of(subtype.getGenericComponentType()).isSubtypeOf(thisClass.getComponentType()); + // requireNonNull is safe because of the isArray() check. + return of(subtype.getGenericComponentType()).isSubtypeOf(requireNonNull(thisClass.getComponentType())); } else if (runtimeType instanceof GenericArrayType) { return of(subtype.getGenericComponentType()) .isSubtypeOf(((GenericArrayType) runtimeType).getGenericComponentType()); @@ -1148,12 +1169,13 @@ private boolean isOwnedBySubtypeOf(Type supertype) { * returned. */ @VisibleForTesting - static TypeToken toGenericType(Class cls) { + static TypeToken toGenericType(Class cls) { if (cls.isArray()) { Type arrayOfGenericType = Types.newArrayType( // If we are passed with int[].class, don't turn it to GenericArrayType - toGenericType(cls.getComponentType()).runtimeType); + // requireNonNull is safe because of the isArray() check. + toGenericType(requireNonNull(cls.getComponentType())).runtimeType); @SuppressWarnings("unchecked") // array is covariant TypeToken result = (TypeToken) of(arrayOfGenericType); return result; @@ -1161,7 +1183,8 @@ static TypeToken toGenericType(Class cls) { TypeVariable>[] typeParams = cls.getTypeParameters(); Type ownerType = cls.isMemberClass() && !Modifier.isStatic(cls.getModifiers()) - ? toGenericType(cls.getEnclosingClass()).runtimeType + // requireNonNull is safe because of the isMemberClass() check. + ? toGenericType(requireNonNull(cls.getEnclosingClass())).runtimeType : null; if ((typeParams.length > 0) || ((ownerType != null) && ownerType != cls.getEnclosingClass())) { @@ -1219,11 +1242,15 @@ private TypeToken getArraySupertype(Class supertype) { // with component type, we have lost generic type information // Use raw type so that compiler allows us to call getSupertype() @SuppressWarnings("rawtypes") - TypeToken componentType = - checkNotNull(getComponentType(), "%s isn't a super type of %s", supertype, this); + TypeToken componentType = getComponentType(); + if (componentType == null) { + throw new IllegalArgumentException(supertype + " isn't a super type of " + this); + } // array is covariant. component type is super type, so is the array type. @SuppressWarnings("unchecked") // going from raw type back to generics - TypeToken componentSupertype = componentType.getSupertype(supertype.getComponentType()); + // requireNonNull is safe because we call this only after checking supertype.isArray(). + TypeToken componentSupertype = + componentType.getSupertype(requireNonNull(supertype.getComponentType())); @SuppressWarnings("unchecked") // component type is super type, so is array type. TypeToken result = (TypeToken) @@ -1233,8 +1260,14 @@ private TypeToken getArraySupertype(Class supertype) { } private TypeToken getArraySubtype(Class subclass) { + Class subclassComponentType = subclass.getComponentType(); + if (subclassComponentType == null) { + throw new IllegalArgumentException(subclass + " does not appear to be a subtype of " + this); + } // array is covariant. component type is subtype, so is the array type. - TypeToken componentSubtype = getComponentType().getSubtype(subclass.getComponentType()); + // requireNonNull is safe as long as we're careful to call this method only when isArray(). + TypeToken componentSubtype = + requireNonNull(getComponentType()).getSubtype(subclassComponentType); @SuppressWarnings("unchecked") // component type is subtype, so is array type. TypeToken result = (TypeToken) @@ -1278,7 +1311,7 @@ private static Type newArrayClassOrGenericArrayType(Type componentType) { return Types.JavaVersion.JAVA7.newArrayType(componentType); } - private static final class SimpleTypeToken extends TypeToken { + private static final class SimpleTypeToken extends TypeToken { SimpleTypeToken(Type type) { super(type); @@ -1292,7 +1325,7 @@ private static final class SimpleTypeToken extends TypeToken { * * @param The type "kind". Either a TypeToken, or Class. */ - private abstract static class TypeCollector { + private abstract static class TypeCollector { static final TypeCollector> FOR_GENERIC_TYPE = new TypeCollector>() { @@ -1392,13 +1425,16 @@ private int collectTypes(K type, Map map) { return aboveMe + 1; } - private static ImmutableList sortKeysByValue( - final Map map, final Comparator valueComparator) { + private static + ImmutableList sortKeysByValue( + final Map map, final Comparator valueComparator) { Ordering keyOrdering = new Ordering() { @Override public int compare(K left, K right) { - return valueComparator.compare(map.get(left), map.get(right)); + // requireNonNull is safe because we are passing keys in the map. + return valueComparator.compare( + requireNonNull(map.get(left)), requireNonNull(map.get(right))); } }; return keyOrdering.immutableSortedCopy(map.keySet()); @@ -1410,7 +1446,8 @@ public int compare(K left, K right) { abstract @Nullable K getSuperclass(K type); - private static class ForwardingTypeCollector extends TypeCollector { + private static class ForwardingTypeCollector + extends TypeCollector { private final TypeCollector delegate; @@ -1429,6 +1466,7 @@ Iterable getInterfaces(K type) { } @Override + @Nullable K getSuperclass(K type) { return delegate.getSuperclass(type); } diff --git a/guava/src/com/google/common/reflect/TypeVisitor.java b/guava/src/com/google/common/reflect/TypeVisitor.java index 3e8436dad189..db3d4a71b527 100644 --- a/guava/src/com/google/common/reflect/TypeVisitor.java +++ b/guava/src/com/google/common/reflect/TypeVisitor.java @@ -21,6 +21,7 @@ import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; import java.util.Set; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Based on what a {@link Type} is, dispatch it to the corresponding {@code visit*} method. By @@ -61,7 +62,7 @@ abstract class TypeVisitor { * Visits the given types. Null types are ignored. This allows subclasses to call {@code * visit(parameterizedType.getOwnerType())} safely without having to check nulls. */ - public final void visit(Type... types) { + public final void visit(@Nullable Type... types) { for (Type type : types) { if (type == null || !visited.add(type)) { // null owner type, or already visited; diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java index 42a1f7883db3..b70597720d3b 100644 --- a/guava/src/com/google/common/reflect/Types.java +++ b/guava/src/com/google/common/reflect/Types.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.transform; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; @@ -130,7 +131,9 @@ Class getOwnerType(Class rawType) { private static ClassOwnership detectJvmBehavior() { class LocalClass {} Class subclass = new LocalClass() {}.getClass(); - ParameterizedType parameterizedType = (ParameterizedType) subclass.getGenericSuperclass(); + // requireNonNull is safe because we're examining a type that's known to have a superclass. + ParameterizedType parameterizedType = + requireNonNull((ParameterizedType) subclass.getGenericSuperclass()); for (ClassOwnership behavior : ClassOwnership.values()) { if (behavior.getOwnerType(LocalClass.class) == parameterizedType.getOwnerType()) { return behavior; @@ -173,7 +176,7 @@ static String toString(Type type) { static @Nullable Type getComponentType(Type type) { checkNotNull(type); - final AtomicReference result = new AtomicReference<>(); + final AtomicReference<@Nullable Type> result = new AtomicReference<>(); new TypeVisitor() { @Override void visitTypeVariable(TypeVariable t) { @@ -244,7 +247,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof GenericArrayType) { GenericArrayType that = (GenericArrayType) obj; return Objects.equal(getGenericComponentType(), that.getGenericComponentType()); @@ -281,7 +284,7 @@ public Type getRawType() { } @Override - public Type getOwnerType() { + public @Nullable Type getOwnerType() { return ownerType; } @@ -307,7 +310,7 @@ public int hashCode() { } @Override - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (!(other instanceof ParameterizedType)) { return false; } @@ -383,19 +386,39 @@ private static final class TypeVariableInvocationHandler implements InvocationHa } @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + public @Nullable Object invoke(Object proxy, Method method, @Nullable Object @Nullable [] args) + throws Throwable { String methodName = method.getName(); Method typeVariableMethod = typeVariableMethods.get(methodName); if (typeVariableMethod == null) { throw new UnsupportedOperationException(methodName); } else { + if (args == null) { + /* + * Method.invoke can run succesfully when given a null args argument -- as long as the + * method is a no-arg method, which is, thankfully, the only case in which + * InvocationHandler.invoke is passed a null args argument. + * + * However, nullness checkers may well define Method.invoke to *forbid* a null args + * argument: That ensures that callers don't pass null by accident through, e.g., a + * default-initialized field. Callers who intend to pass no arguments can do so explicitly + * by passing an empty array. So we do that here to accommodate more nullness checkers. + */ + args = NO_ARGS; + } try { return typeVariableMethod.invoke(typeVariableImpl, args); } catch (InvocationTargetException e) { - throw e.getCause(); + /* + * requireNonNull should be safe because an InvocationTargetException from reflection + * should have a cause. + */ + throw requireNonNull(e.getCause()); } } } + + private static final Object[] NO_ARGS = new Object[0]; } private static final class TypeVariableImpl { @@ -438,7 +461,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) { // equal only to our TypeVariable implementation with identical bounds if (obj != null @@ -487,7 +510,7 @@ public Type[] getUpperBounds() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof WildcardType) { WildcardType that = (WildcardType) obj; return lowerBounds.equals(Arrays.asList(that.getLowerBounds())) @@ -555,7 +578,8 @@ Type usedInGenericType(Type type) { if (type instanceof Class) { Class cls = (Class) type; if (cls.isArray()) { - return new GenericArrayTypeImpl(cls.getComponentType()); + // requireNonNull is safe because of the isArray() check. + return new GenericArrayTypeImpl(requireNonNull(cls.getComponentType())); } } return type; @@ -591,7 +615,8 @@ Type usedInGenericType(Type type) { String typeName(Type type) { try { Method getTypeName = Type.class.getMethod("getTypeName"); - return (String) getTypeName.invoke(type); + // requireNonNull should be safe, given the definition of Type.getTypeName. + return requireNonNull((String) getTypeName.invoke(type)); } catch (NoSuchMethodException e) { throw new AssertionError("Type.getTypeName should be available in Java 8"); /* diff --git a/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java b/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java index 850e31088f8a..4bc619acfe6f 100644 --- a/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java +++ b/guava/src/com/google/common/util/concurrent/AbstractCatchingFuture.java @@ -26,11 +26,16 @@ import com.google.errorprone.annotations.ForOverride; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** Implementations of {@code Futures.catching*}. */ @GwtCompatible -abstract class AbstractCatchingFuture +abstract class AbstractCatchingFuture< + V, + X extends Throwable, + F extends @NonNull Object, + T> extends FluentFuture.TrustedFuture implements Runnable { static ListenableFuture create( ListenableFuture input, @@ -72,7 +77,7 @@ public final void run() { ListenableFuture localInputFuture = inputFuture; Class localExceptionType = exceptionType; F localFallback = fallback; - if (localInputFuture == null | localExceptionType == null | localFallback == null + if (localInputFuture == null || localExceptionType == null || localFallback == null // This check, unlike all the others, is a volatile read || isCancelled()) { return; @@ -107,7 +112,11 @@ public final void run() { } if (throwable == null) { - set(sourceResult); + /* + * The cast is safe: There was no exception, so the assignment from getDone must have + * succeeded. + */ + set(uncheckedCastNullableVToV(sourceResult)); return; } @@ -134,7 +143,7 @@ public final void run() { } @Override - protected String pendingToString() { + protected @Nullable String pendingToString() { ListenableFuture localInputFuture = inputFuture; Class localExceptionType = exceptionType; F localFallback = fallback; @@ -158,11 +167,11 @@ protected String pendingToString() { /** Template method for subtypes to actually run the fallback. */ @ForOverride - abstract @Nullable T doFallback(F fallback, X throwable) throws Exception; + abstract T doFallback(F fallback, X throwable) throws Exception; /** Template method for subtypes to actually set the result. */ @ForOverride - abstract void setResult(@Nullable T result); + abstract void setResult(T result); @Override protected final void afterDone() { @@ -218,14 +227,24 @@ private static final class CatchingFuture } @Override - @Nullable V doFallback(Function fallback, X cause) throws Exception { return fallback.apply(cause); } @Override - void setResult(@Nullable V result) { + void setResult(V result) { set(result); } } + + @SuppressWarnings("nullness") + private static V uncheckedCastNullableVToV(@Nullable V result) { + /* + * We can't use requireNonNull because `result` might be null. Specifically, it can be null + * because the future might produce a null value to be returned to the user. This is in contrast + * to the other way for `result` to be null, which is for the future to have failed, leaving the + * variable with its initial null value. + */ + return result; + } } diff --git a/guava/src/com/google/common/util/concurrent/AbstractFuture.java b/guava/src/com/google/common/util/concurrent/AbstractFuture.java index 9cace28eac4c..aee8504fc2ab 100644 --- a/guava/src/com/google/common/util/concurrent/AbstractFuture.java +++ b/guava/src/com/google/common/util/concurrent/AbstractFuture.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.throwIfUnchecked; +import static java.util.Objects.requireNonNull; import static java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater; import com.google.common.annotations.Beta; @@ -67,7 +68,7 @@ @ReflectionSupport(value = ReflectionSupport.Level.FULL) public abstract class AbstractFuture extends InternalFutureFailureAccess implements ListenableFuture { - // NOTE: Whenever both tests are cheap and functional, it's faster to use &, | instead of &&, || + // NOTE: Whenever both tests are cheap and functional, it's faster to use &, || instead of &&, || private static final boolean GENERATE_CANCELLATION_CAUSES; @@ -95,7 +96,8 @@ interface Trusted extends ListenableFuture {} * A less abstract subclass of AbstractFuture. This can be used to optimize setFuture by ensuring * that {@link #get} calls exactly the implementation of {@link AbstractFuture#get}. */ - abstract static class TrustedFuture extends AbstractFuture implements Trusted { + abstract static class TrustedFuture extends AbstractFuture + implements Trusted { @CanIgnoreReturnValue @Override public final V get() throws InterruptedException, ExecutionException { @@ -205,7 +207,7 @@ private static final class Waiter { // non-volatile write to the next field. Should be made visible by subsequent CAS on waiters // field. - void setNext(Waiter next) { + void setNext(@Nullable Waiter next) { ATOMIC_HELPER.putNext(this, next); } @@ -262,7 +264,9 @@ private void removeWaiter(Waiter node) { /** Listeners also form a stack through the {@link #listeners} field. */ private static final class Listener { + @SuppressWarnings("nullness") // Special instance that we promise to be careful with. static final Listener TOMBSTONE = new Listener(null, null); + final Runnable task; final Executor executor; @@ -303,8 +307,9 @@ private static final class Cancellation { static { if (GENERATE_CANCELLATION_CAUSES) { - CAUSELESS_CANCELLED = null; - CAUSELESS_INTERRUPTED = null; + // Storing null is safe because we won't use the fields under GENERATE_CANCELLATION_CAUSES. + CAUSELESS_CANCELLED = unsafeNullCancellation(); + CAUSELESS_INTERRUPTED = unsafeNullCancellation(); } else { CAUSELESS_CANCELLED = new Cancellation(false, null); CAUSELESS_INTERRUPTED = new Cancellation(true, null); @@ -320,6 +325,11 @@ private static final class Cancellation { } } + @SuppressWarnings("nullness") + private static Cancellation unsafeNullCancellation() { + return null; + } + /** A special value that encodes the 'setFuture' state. */ private static final class SetFuture implements Runnable { final AbstractFuture owner; @@ -415,7 +425,7 @@ public V get(long timeout, TimeUnit unit) throw new InterruptedException(); } Object localValue = value; - if (localValue != null & !(localValue instanceof SetFuture)) { + if (localValue != null && !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } // we delay calling nanoTime until we know we will need to either park or spin @@ -439,7 +449,7 @@ public V get(long timeout, TimeUnit unit) // Otherwise re-read and check doneness. If we loop then it must have been a spurious // wakeup localValue = value; - if (localValue != null & !(localValue instanceof SetFuture)) { + if (localValue != null && !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } @@ -457,13 +467,14 @@ public V get(long timeout, TimeUnit unit) } // re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a // waiter. - return getDoneValue(value); + // requireNonNull is safe because value is always set before TOMBSTONE. + return getDoneValue(requireNonNull(value)); } // If we get here then we have remainingNanos < SPIN_THRESHOLD_NANOS and there is no node on the // waiters list while (remainingNanos > 0) { localValue = value; - if (localValue != null & !(localValue instanceof SetFuture)) { + if (localValue != null && !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } if (Thread.interrupted()) { @@ -521,7 +532,7 @@ public V get() throws InterruptedException, ExecutionException { throw new InterruptedException(); } Object localValue = value; - if (localValue != null & !(localValue instanceof SetFuture)) { + if (localValue != null && !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } Waiter oldHead = waiters; @@ -541,7 +552,7 @@ public V get() throws InterruptedException, ExecutionException { // Otherwise re-read and check doneness. If we loop then it must have been a spurious // wakeup localValue = value; - if (localValue != null & !(localValue instanceof SetFuture)) { + if (localValue != null && !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } } @@ -551,7 +562,8 @@ public V get() throws InterruptedException, ExecutionException { } // re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a // waiter. - return getDoneValue(value); + // requireNonNull is safe because value is always set before TOMBSTONE. + return getDoneValue(requireNonNull(value)); } /** Unboxes {@code obj}. Assumes that obj is not {@code null} or a {@link SetFuture}. */ @@ -563,7 +575,11 @@ private V getDoneValue(Object obj) throws ExecutionException { } else if (obj instanceof Failure) { throw new ExecutionException(((Failure) obj).exception); } else if (obj == NULL) { - return null; + /* + * It's safe to return null because we would only have stored it in the first place if it were + * a valid value for V. + */ + return unsafeNullV(); } else { @SuppressWarnings("unchecked") // this is the only other option V asV = (V) obj; @@ -571,10 +587,15 @@ private V getDoneValue(Object obj) throws ExecutionException { } } + @SuppressWarnings("nullness") + private static V unsafeNullV() { + return null; + } + @Override public boolean isDone() { final Object localValue = value; - return localValue != null & !(localValue instanceof SetFuture); + return localValue != null && !(localValue instanceof SetFuture); } @Override @@ -601,7 +622,7 @@ public boolean isCancelled() { public boolean cancel(boolean mayInterruptIfRunning) { Object localValue = value; boolean rValue = false; - if (localValue == null | localValue instanceof SetFuture) { + if (localValue == null || localValue instanceof SetFuture) { // Try to delay allocating the exception. At this point we may still lose the CAS, but it is // certainly less likely. Object valueToSet = @@ -624,7 +645,8 @@ mayInterruptIfRunning, new CancellationException("Future.cancel() was called.")) if (localValue instanceof SetFuture) { // propagate cancellation to the future set in setfuture, this is racy, and we don't // care if we are successful or not. - ListenableFuture futureToPropagateTo = ((SetFuture) localValue).future; + ListenableFuture futureToPropagateTo = + ((SetFuture) localValue).future; if (futureToPropagateTo instanceof Trusted) { // If the future is a TrustedFuture then we specifically avoid calling cancel() // this has 2 benefits @@ -633,9 +655,10 @@ mayInterruptIfRunning, new CancellationException("Future.cancel() was called.")) // chain // We can only do this for TrustedFuture, because TrustedFuture.cancel is final and // does nothing but delegate to this method. - AbstractFuture trusted = (AbstractFuture) futureToPropagateTo; + AbstractFuture trusted = + (AbstractFuture) futureToPropagateTo; localValue = trusted.value; - if (localValue == null | localValue instanceof SetFuture) { + if (localValue == null || localValue instanceof SetFuture) { abstractFuture = trusted; continue; // loop back up and try to complete the new future } @@ -732,7 +755,7 @@ public void addListener(Runnable listener, Executor executor) { * @return true if the attempt was accepted, completing the {@code Future} */ @CanIgnoreReturnValue - protected boolean set(@Nullable V value) { + protected boolean set(V value) { Object valueToSet = value == null ? NULL : value; if (ATOMIC_HELPER.casValue(this, null, valueToSet)) { complete(this); @@ -859,7 +882,8 @@ private static Object getFutureValue(ListenableFuture future) { : Cancellation.CAUSELESS_CANCELLED; } } - return v; + // requireNonNull is safe as long as we call this method only on completed futures. + return requireNonNull(v); } if (future instanceof InternalFutureFailureAccess) { Throwable throwable = @@ -870,7 +894,7 @@ private static Object getFutureValue(ListenableFuture future) { } boolean wasCancelled = future.isCancelled(); // Don't allocate a CancellationException if it's not necessary - if (!GENERATE_CANCELLATION_CAUSES & wasCancelled) { + if (!GENERATE_CANCELLATION_CAUSES && wasCancelled) { return Cancellation.CAUSELESS_CANCELLED; } // Otherwise calculate the value by calling .get() @@ -895,7 +919,14 @@ private static Object getFutureValue(ListenableFuture future) { + future, exception)); } - return new Failure(exception.getCause()); + /* + * requireNonNull should be safe because an ExecutionException from a Future should have a + * cause. TODO(cpovirk): But if it doesn't, consider creating a Failure with a + * NullPointerException (or IllegalArgumentException) as a cause, similar to how we create a + * CancellationException with an IllegalArgumentException as a cause above. See also + * AbstractTransformFuture. + */ + return new Failure(requireNonNull(exception.getCause())); } catch (CancellationException cancellation) { if (!wasCancelled) { return new Failure( @@ -914,7 +945,8 @@ private static Object getFutureValue(ListenableFuture future) { * An inlined private copy of {@link Uninterruptibles#getUninterruptibly} used to break an * internal dependency on other /util/concurrent classes. */ - private static V getUninterruptibly(Future future) throws ExecutionException { + private static V getUninterruptibly(Future future) + throws ExecutionException { boolean interrupted = false; try { while (true) { @@ -932,7 +964,10 @@ private static V getUninterruptibly(Future future) throws ExecutionExcept } /** Unblocks all threads and runs all listeners. */ - private static void complete(AbstractFuture future) { + private static void complete(AbstractFuture param) { + // Declare a "true" local variable so that the Checker Framework will infer nullness. + AbstractFuture future = param; + Listener next = null; outer: while (true) { @@ -951,7 +986,8 @@ private static void complete(AbstractFuture future) { next = next.next; Runnable task = curr.task; if (task instanceof SetFuture) { - SetFuture setFuture = (SetFuture) task; + SetFuture setFuture = + (SetFuture) task; // We unwind setFuture specifically to avoid StackOverflowErrors in the case of long // chains of SetFutures // Handling this special case is important because there is no way to pass an executor to @@ -1010,6 +1046,12 @@ protected void afterDone() {} * @since 27.0 */ @Override + /* + * We should annotate the superclass, InternalFutureFailureAccess, to say that its copy of this + * method returns @Nullable, too. However, we're not sure if we want to make any changes to that + * class, since it's in a separate artifact that we planned to release only a single version of. + */ + @SuppressWarnings("nullness") protected final @Nullable Throwable tryInternalFastPathGetFailure() { if (this instanceof Trusted) { Object obj = value; @@ -1025,7 +1067,7 @@ protected void afterDone() {} * the given future (if available). */ final void maybePropagateCancellationTo(@Nullable Future related) { - if (related != null & isCancelled()) { + if (related != null && isCancelled()) { related.cancel(wasInterrupted()); } } @@ -1045,7 +1087,7 @@ private void releaseWaiters() { * Clears the {@link #listeners} list and prepends its contents to {@code onto}, least recently * added first. */ - private Listener clearListeners(Listener onto) { + private @Nullable Listener clearListeners(@Nullable Listener onto) { // We need to // 1. atomically swap the listeners with TOMBSTONE, this is because addListener uses that to // to synchronize with us @@ -1147,7 +1189,7 @@ private void addDoneString(StringBuilder builder) { } /** Helper for printing user supplied objects into our toString method. */ - private void appendUserObject(StringBuilder builder, Object o) { + private void appendUserObject(StringBuilder builder, @Nullable Object o) { // This is some basic recursion detection for when people create cycles via set/setFuture or // when deep chains of futures exist resulting in a StackOverflowException. We could detect // arbitrary cycles using a thread local but this should be a good enough solution (it is also @@ -1188,16 +1230,23 @@ private abstract static class AtomicHelper { abstract void putThread(Waiter waiter, Thread newValue); /** Non volatile write of the waiter to the {@link Waiter#next} field. */ - abstract void putNext(Waiter waiter, Waiter newValue); + abstract void putNext(Waiter waiter, @Nullable Waiter newValue); /** Performs a CAS operation on the {@link #waiters} field. */ - abstract boolean casWaiters(AbstractFuture future, Waiter expect, Waiter update); + abstract boolean casWaiters( + AbstractFuture future, + @Nullable Waiter expect, + @Nullable Waiter update); /** Performs a CAS operation on the {@link #listeners} field. */ - abstract boolean casListeners(AbstractFuture future, Listener expect, Listener update); + abstract boolean casListeners( + AbstractFuture future, + @Nullable Listener expect, + Listener update); /** Performs a CAS operation on the {@link #value} field. */ - abstract boolean casValue(AbstractFuture future, Object expect, Object update); + abstract boolean casValue( + AbstractFuture future, @Nullable Object expect, Object update); } /** @@ -1206,6 +1255,12 @@ private abstract static class AtomicHelper { *

    Static initialization of this class will fail if the {@link sun.misc.Unsafe} object cannot * be accessed. */ + /* + * No nullness checker is going to understand this level of reflective hackery. The good news is + * that SynchronizedHelper implements the same logic in a way that nullness checkers *can* + * understand. + */ + @SuppressWarnings("nullness") private static final class UnsafeAtomicHelper extends AtomicHelper { static final sun.misc.Unsafe UNSAFE; static final long LISTENERS_OFFSET; @@ -1260,30 +1315,38 @@ void putThread(Waiter waiter, Thread newValue) { } @Override - void putNext(Waiter waiter, Waiter newValue) { + void putNext(Waiter waiter, @Nullable Waiter newValue) { UNSAFE.putObject(waiter, WAITER_NEXT_OFFSET, newValue); } /** Performs a CAS operation on the {@link #waiters} field. */ @Override - boolean casWaiters(AbstractFuture future, Waiter expect, Waiter update) { + boolean casWaiters( + AbstractFuture future, + @Nullable Waiter expect, + @Nullable Waiter update) { return UNSAFE.compareAndSwapObject(future, WAITERS_OFFSET, expect, update); } /** Performs a CAS operation on the {@link #listeners} field. */ @Override - boolean casListeners(AbstractFuture future, Listener expect, Listener update) { + boolean casListeners( + AbstractFuture future, + @Nullable Listener expect, + Listener update) { return UNSAFE.compareAndSwapObject(future, LISTENERS_OFFSET, expect, update); } /** Performs a CAS operation on the {@link #value} field. */ @Override - boolean casValue(AbstractFuture future, Object expect, Object update) { + boolean casValue( + AbstractFuture future, @Nullable Object expect, Object update) { return UNSAFE.compareAndSwapObject(future, VALUE_OFFSET, expect, update); } } /** {@link AtomicHelper} based on {@link AtomicReferenceFieldUpdater}. */ + @SuppressWarnings("nullness") // see UnsafeAtomicHelper private static final class SafeAtomicHelper extends AtomicHelper { final AtomicReferenceFieldUpdater waiterThreadUpdater; final AtomicReferenceFieldUpdater waiterNextUpdater; @@ -1310,22 +1373,29 @@ void putThread(Waiter waiter, Thread newValue) { } @Override - void putNext(Waiter waiter, Waiter newValue) { + void putNext(Waiter waiter, @Nullable Waiter newValue) { waiterNextUpdater.lazySet(waiter, newValue); } @Override - boolean casWaiters(AbstractFuture future, Waiter expect, Waiter update) { + boolean casWaiters( + AbstractFuture future, + @Nullable Waiter expect, + @Nullable Waiter update) { return waitersUpdater.compareAndSet(future, expect, update); } @Override - boolean casListeners(AbstractFuture future, Listener expect, Listener update) { + boolean casListeners( + AbstractFuture future, + @Nullable Listener expect, + Listener update) { return listenersUpdater.compareAndSet(future, expect, update); } @Override - boolean casValue(AbstractFuture future, Object expect, Object update) { + boolean casValue( + AbstractFuture future, @Nullable Object expect, Object update) { return valueUpdater.compareAndSet(future, expect, update); } } @@ -1343,12 +1413,15 @@ void putThread(Waiter waiter, Thread newValue) { } @Override - void putNext(Waiter waiter, Waiter newValue) { + void putNext(Waiter waiter, @Nullable Waiter newValue) { waiter.next = newValue; } @Override - boolean casWaiters(AbstractFuture future, Waiter expect, Waiter update) { + boolean casWaiters( + AbstractFuture future, + @Nullable Waiter expect, + @Nullable Waiter update) { synchronized (future) { if (future.waiters == expect) { future.waiters = update; @@ -1359,7 +1432,10 @@ boolean casWaiters(AbstractFuture future, Waiter expect, Waiter update) { } @Override - boolean casListeners(AbstractFuture future, Listener expect, Listener update) { + boolean casListeners( + AbstractFuture future, + @Nullable Listener expect, + Listener update) { synchronized (future) { if (future.listeners == expect) { future.listeners = update; @@ -1370,7 +1446,8 @@ boolean casListeners(AbstractFuture future, Listener expect, Listener update) } @Override - boolean casValue(AbstractFuture future, Object expect, Object update) { + boolean casValue( + AbstractFuture future, @Nullable Object expect, Object update) { synchronized (future) { if (future.value == expect) { future.value = update; @@ -1382,7 +1459,7 @@ boolean casValue(AbstractFuture future, Object expect, Object update) { } private static CancellationException cancellationExceptionWithCause( - @Nullable String message, @Nullable Throwable cause) { + String message, @Nullable Throwable cause) { CancellationException exception = new CancellationException(message); exception.initCause(cause); return exception; diff --git a/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java index 960f40e8ffab..a2aaaff4010d 100644 --- a/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java @@ -41,7 +41,8 @@ public abstract class AbstractListeningExecutorService extends AbstractExecutorS /** @since 19.0 (present with return type {@code ListenableFutureTask} since 14.0) */ @Override - protected final RunnableFuture newTaskFor(Runnable runnable, T value) { + protected final RunnableFuture newTaskFor( + Runnable runnable, T value) { return TrustedListenableFutureTask.create(runnable, value); } @@ -57,7 +58,7 @@ public ListenableFuture submit(Runnable task) { } @Override - public ListenableFuture submit(Runnable task, @Nullable T result) { + public ListenableFuture submit(Runnable task, T result) { return (ListenableFuture) super.submit(task, result); } diff --git a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java index a7a342ad5f6c..7a3f6389bb1b 100644 --- a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java +++ b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Internal.toNanosSaturated; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Supplier; @@ -213,6 +214,11 @@ class Task implements Runnable { @Override public void run() { lock.lock(); + /* + * requireNonNull is safe because Task isn't run (or at least it doesn't succeed in taking + * the lock) until after it's scheduled and the runningTask field is set. + */ + requireNonNull(runningTask); try { if (runningTask.isCancelled()) { // task may have been cancelled while blocked on the lock. @@ -273,6 +279,9 @@ public void run() { @Override protected final void doStop() { + // Both requireNonNull calls are safe because doStop can run only after a successful doStart. + requireNonNull(runningTask); + requireNonNull(executorService); runningTask.cancel(false); executorService.execute( new Runnable() { @@ -482,7 +491,8 @@ public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutExc public abstract static class CustomScheduler extends Scheduler { /** A callable class that can reschedule itself using a {@link CustomScheduler}. */ - private class ReschedulableCallable extends ForwardingFuture implements Callable { + private class ReschedulableCallable extends ForwardingFuture<@Nullable Void> + implements Callable<@Nullable Void> { /** The underlying task. */ private final Runnable wrappedRunnable; @@ -505,7 +515,7 @@ private class ReschedulableCallable extends ForwardingFuture implements Ca /** The future that represents the next execution of this task. */ @GuardedBy("lock") - private @Nullable Future currentFuture; + private @Nullable Future<@Nullable Void> currentFuture; ReschedulableCallable( AbstractService service, ScheduledExecutorService executor, Runnable runnable) { @@ -515,7 +525,7 @@ private class ReschedulableCallable extends ForwardingFuture implements Ca } @Override - public Void call() throws Exception { + public @Nullable Void call() throws Exception { wrappedRunnable.run(); reschedule(); return null; @@ -567,6 +577,40 @@ public boolean cancel(boolean mayInterruptIfRunning) { // Ensure that a task cannot be rescheduled while a cancel is ongoing. lock.lock(); try { + /* + * requireNonNull is mostly safe because: + * + * As soon as we create a ReschedulableCallable, we call reschedule() before returning it + * to any code that might call other methods on it. In the normal case, reschedule() + * assigns a non-null value to currentFuture and returns. + * + * - Less common case #1: If reschedule() encounters an error when calling + * getNextSchedule(), then we will still won't run any code that would dereference + * runningTask: + * + * 1. schedule() will never be called, so Task.run() will never run, so it will never + * dereference runningTask. + * + * 2. doStart checks runningTask for null before dereferencing it. + * + * 3. doStop will never be called because its contract requires it to wait for the service + * to start successfully. Thus, it will never dereference runningTask. + * + * - Less common case #2: The executor itself receives a reference to this object. In + * particular, it's passed as the Callable argument to + * ScheduledThreadPoolExecutor.decorateTask. An implementation of that method could in + * theory cast to Future and call this method, producing NullPointerException. + * + * TODO(cpovirk): Fix that less common case, probably by returning false to indicate that + * the task is already done. + * + * TODO(cpovirk): That said, if we care about that, we probably should care about the fact + * that this isn't a full Future implementation at all. After all, decorateTask could just + * as well call isDone or another Future method. Maybe we should really implement them + * all? But that's a lot of work for a case that's almost certainly never going to come + * up. + */ + requireNonNull(currentFuture); return currentFuture.cancel(mayInterruptIfRunning); } finally { lock.unlock(); @@ -577,6 +621,8 @@ public boolean cancel(boolean mayInterruptIfRunning) { public boolean isCancelled() { lock.lock(); try { + // requireNonNull is mostly safe. See the comment in cancel() above. + requireNonNull(currentFuture); return currentFuture.isCancelled(); } finally { lock.unlock(); @@ -584,7 +630,7 @@ public boolean isCancelled() { } @Override - protected Future delegate() { + protected Future<@Nullable Void> delegate() { throw new UnsupportedOperationException( "Only cancel and isCancelled is supported by this future"); } diff --git a/guava/src/com/google/common/util/concurrent/AbstractService.java b/guava/src/com/google/common/util/concurrent/AbstractService.java index f5d38edbb616..814e22915177 100644 --- a/guava/src/com/google/common/util/concurrent/AbstractService.java +++ b/guava/src/com/google/common/util/concurrent/AbstractService.java @@ -23,6 +23,7 @@ import static com.google.common.util.concurrent.Service.State.STARTING; import static com.google.common.util.concurrent.Service.State.STOPPING; import static com.google.common.util.concurrent.Service.State.TERMINATED; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -626,7 +627,8 @@ Throwable failureCause() { state == FAILED, "failureCause() is only valid if the service has failed, service is %s", state); - return failure; + // requireNonNull should be safe because we always provide a non-null cause with FAILED. + return requireNonNull(failure); } } } diff --git a/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java b/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java index e254dc692154..c0f7929b1cc5 100644 --- a/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java +++ b/guava/src/com/google/common/util/concurrent/AbstractTransformFuture.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Futures.getDone; import static com.google.common.util.concurrent.MoreExecutors.rejectionPropagatingExecutor; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Function; @@ -24,12 +25,17 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** Implementations of {@code Futures.transform*}. */ @GwtCompatible -abstract class AbstractTransformFuture extends FluentFuture.TrustedFuture - implements Runnable { +abstract class AbstractTransformFuture< + I, + O, + F extends @NonNull Object, + T> + extends FluentFuture.TrustedFuture implements Runnable { static ListenableFuture create( ListenableFuture input, AsyncFunction function, @@ -64,7 +70,7 @@ static ListenableFuture create( public final void run() { ListenableFuture localInputFuture = inputFuture; F localFunction = function; - if (isCancelled() | localInputFuture == null | localFunction == null) { + if (isCancelled() || localInputFuture == null || localFunction == null) { return; } inputFuture = null; @@ -88,7 +94,8 @@ public final void run() { try { sourceResult = getDone(localInputFuture); } catch (CancellationException e) { - // TODO(user): verify future behavior - unify logic with getFutureValue in AbstractFuture. This + // TODO(user): verify future behavior - unify logic with getFutureValue in AbstractFuture. + // This // code should be unreachable with correctly implemented Futures. // Cancel this future and return. // At this point, inputFuture is cancelled and outputFuture doesn't exist, so the value of @@ -96,8 +103,8 @@ public final void run() { cancel(false); return; } catch (ExecutionException e) { - // Set the cause of the exception as this future's exception. - setException(e.getCause()); + // requireNonNull should be safe: See AbstractFuture.getFutureValue. + setException(requireNonNull(e.getCause())); return; } catch (RuntimeException e) { // Bug in inputFuture.get(). Propagate to the output Future so that its consumers don't hang. @@ -165,11 +172,11 @@ public final void run() { /** Template method for subtypes to actually run the transform. */ @ForOverride - abstract @Nullable T doTransform(F function, @Nullable I result) throws Exception; + abstract T doTransform(F function, I result) throws Exception; /** Template method for subtypes to actually set the result. */ @ForOverride - abstract void setResult(@Nullable T result); + abstract void setResult(T result); @Override protected final void afterDone() { @@ -179,7 +186,7 @@ protected final void afterDone() { } @Override - protected String pendingToString() { + protected @Nullable String pendingToString() { ListenableFuture localInputFuture = inputFuture; F localFunction = function; String superString = super.pendingToString(); @@ -199,7 +206,8 @@ protected String pendingToString() { * An {@link AbstractTransformFuture} that delegates to an {@link AsyncFunction} and {@link * #setFuture(ListenableFuture)}. */ - private static final class AsyncTransformFuture + private static final class AsyncTransformFuture< + I, O> extends AbstractTransformFuture< I, O, AsyncFunction, ListenableFuture> { AsyncTransformFuture( @@ -209,7 +217,7 @@ private static final class AsyncTransformFuture @Override ListenableFuture doTransform( - AsyncFunction function, @Nullable I input) throws Exception { + AsyncFunction function, I input) throws Exception { ListenableFuture outputFuture = function.apply(input); checkNotNull( outputFuture, @@ -237,13 +245,12 @@ private static final class TransformFuture } @Override - @Nullable - O doTransform(Function function, @Nullable I input) { + O doTransform(Function function, I input) { return function.apply(input); } @Override - void setResult(@Nullable O result) { + void setResult(O result) { set(result); } } diff --git a/guava/src/com/google/common/util/concurrent/AggregateFuture.java b/guava/src/com/google/common/util/concurrent/AggregateFuture.java index 596a5ae353f2..f64fb1ca2f52 100644 --- a/guava/src/com/google/common/util/concurrent/AggregateFuture.java +++ b/guava/src/com/google/common/util/concurrent/AggregateFuture.java @@ -20,6 +20,7 @@ import static com.google.common.util.concurrent.AggregateFuture.ReleaseResourcesReason.OUTPUT_FUTURE_DONE; import static com.google.common.util.concurrent.Futures.getDone; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static java.util.Objects.requireNonNull; import static java.util.logging.Level.SEVERE; import com.google.common.annotations.GwtCompatible; @@ -39,7 +40,8 @@ * @param the type of the output (i.e. this) future */ @GwtCompatible -abstract class AggregateFuture extends AggregateFutureState { +abstract class AggregateFuture + extends AggregateFutureState { private static final Logger logger = Logger.getLogger(AggregateFuture.class.getName()); /** @@ -87,7 +89,7 @@ protected final void afterDone() { } @Override - protected final String pendingToString() { + protected final @Nullable String pendingToString() { ImmutableCollection> localFutures = futures; if (localFutures != null) { return "futures=" + localFutures; @@ -103,6 +105,9 @@ protected final String pendingToString() { * we're guaranteed to have properly initialized the subclass. */ final void init() { + // requireNonNull is safe because this is called from the constructor after `futures` is set. + requireNonNull(futures); + // Corner case: List is empty. if (futures.isEmpty()) { handleAllCompleted(); @@ -234,8 +239,14 @@ private static void log(Throwable throwable) { final void addInitialException(Set seen) { checkNotNull(seen); if (!isCancelled()) { - // TODO(cpovirk): Think about whether we could/should use Verify to check this. - boolean unused = addCausalChain(seen, tryInternalFastPathGetFailure()); + /* + * requireNonNull is safe because this is a TrustedFuture, and we're calling this method only + * if it has failed. + * + * TODO(cpovirk): Think about whether we could/should use Verify to check the return value of + * addCausalChain. + */ + boolean unused = addCausalChain(seen, requireNonNull(tryInternalFastPathGetFailure())); } } @@ -248,7 +259,12 @@ private void collectValueFromNonCancelledFuture(int index, Future seen, Throwable t) { + private static boolean addCausalChain(Set seen, Throwable param) { + // Declare a "true" local variable so that the Checker Framework will infer nullness. + Throwable t = param; + for (; t != null; t = t.getCause()) { boolean firstTimeSeen = seen.add(t); if (!firstTimeSeen) { diff --git a/guava/src/com/google/common/util/concurrent/AggregateFutureState.java b/guava/src/com/google/common/util/concurrent/AggregateFutureState.java index f8398d817eb2..e4c7bd25b18b 100644 --- a/guava/src/com/google/common/util/concurrent/AggregateFutureState.java +++ b/guava/src/com/google/common/util/concurrent/AggregateFutureState.java @@ -15,6 +15,7 @@ package com.google.common.util.concurrent; import static com.google.common.collect.Sets.newConcurrentHashSet; +import static java.util.Objects.requireNonNull; import static java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater; import static java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater; @@ -25,6 +26,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.logging.Level; import java.util.logging.Logger; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A helper which does some thread-safe operations for aggregate futures, which must be implemented @@ -37,10 +39,11 @@ */ @GwtCompatible(emulated = true) @ReflectionSupport(value = ReflectionSupport.Level.FULL) -abstract class AggregateFutureState extends AbstractFuture.TrustedFuture { +abstract class AggregateFutureState + extends AbstractFuture.TrustedFuture { // Lazily initialized the first time we see an exception; not released until all the input futures // have completed and we have processed them all. - private volatile Set seenExceptions = null; + private volatile @Nullable Set seenExceptions = null; private volatile int remaining; @@ -124,8 +127,11 @@ final Set getOrInitSeenExceptions() { * other callers have added to it. * * This read is guaranteed to get us the right value because we only set this once (here). + * + * requireNonNull is safe because either our compareAndSet succeeded or it failed because + * another thread did it for us. */ - seenExceptionsLocal = seenExceptions; + seenExceptionsLocal = requireNonNull(seenExceptions); } return seenExceptionsLocal; } @@ -144,7 +150,7 @@ final void clearSeenExceptions() { private abstract static class AtomicHelper { /** Atomic compare-and-set of the {@link AggregateFutureState#seenExceptions} field. */ abstract void compareAndSetSeenExceptions( - AggregateFutureState state, Set expect, Set update); + AggregateFutureState state, @Nullable Set expect, Set update); /** Atomic decrement-and-get of the {@link AggregateFutureState#remaining} field. */ abstract int decrementAndGetRemainingCount(AggregateFutureState state); @@ -163,8 +169,10 @@ private static final class SafeAtomicHelper extends AtomicHelper { } @Override + // Suppress warnings from reflection. See similar comments in AbstractFuture.UnsafeAtomicHelper. + @SuppressWarnings("nullness") void compareAndSetSeenExceptions( - AggregateFutureState state, Set expect, Set update) { + AggregateFutureState state, @Nullable Set expect, Set update) { seenExceptionsUpdater.compareAndSet(state, expect, update); } @@ -177,7 +185,7 @@ int decrementAndGetRemainingCount(AggregateFutureState state) { private static final class SynchronizedAtomicHelper extends AtomicHelper { @Override void compareAndSetSeenExceptions( - AggregateFutureState state, Set expect, Set update) { + AggregateFutureState state, @Nullable Set expect, Set update) { synchronized (state) { if (state.seenExceptions == expect) { state.seenExceptions = update; diff --git a/guava/src/com/google/common/util/concurrent/AsyncCallable.java b/guava/src/com/google/common/util/concurrent/AsyncCallable.java index f39a88260d57..f89bca040c38 100644 --- a/guava/src/com/google/common/util/concurrent/AsyncCallable.java +++ b/guava/src/com/google/common/util/concurrent/AsyncCallable.java @@ -17,6 +17,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import java.util.concurrent.Future; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Computes a value, possibly asynchronously. For an example usage and more information, see {@link diff --git a/guava/src/com/google/common/util/concurrent/AsyncFunction.java b/guava/src/com/google/common/util/concurrent/AsyncFunction.java index bae9bce3a021..d447a19efd2a 100644 --- a/guava/src/com/google/common/util/concurrent/AsyncFunction.java +++ b/guava/src/com/google/common/util/concurrent/AsyncFunction.java @@ -35,5 +35,5 @@ public interface AsyncFunction { * *

    Throwing an exception from this method is equivalent to returning a failing {@code Future}. */ - ListenableFuture apply(@Nullable I input) throws Exception; + ListenableFuture apply(I input) throws Exception; } diff --git a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java index b80ef2eba445..9052441a2f90 100644 --- a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java +++ b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.LongBinaryOperator; import java.util.function.LongUnaryOperator; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -55,7 +56,7 @@ * @since 11.0 */ @GwtCompatible -public final class AtomicLongMap implements Serializable { +public final class AtomicLongMap implements Serializable { private final ConcurrentHashMap map; private AtomicLongMap(ConcurrentHashMap map) { @@ -63,12 +64,13 @@ private AtomicLongMap(ConcurrentHashMap map) { } /** Creates an {@code AtomicLongMap}. */ - public static AtomicLongMap create() { + public static AtomicLongMap create() { return new AtomicLongMap(new ConcurrentHashMap<>()); } /** Creates an {@code AtomicLongMap} with the same mappings as the specified {@code Map}. */ - public static AtomicLongMap create(Map m) { + public static AtomicLongMap create( + Map m) { AtomicLongMap result = create(); result.putAll(m); return result; diff --git a/guava/src/com/google/common/util/concurrent/Atomics.java b/guava/src/com/google/common/util/concurrent/Atomics.java index 191da95bd397..2e91b9f74b83 100644 --- a/guava/src/com/google/common/util/concurrent/Atomics.java +++ b/guava/src/com/google/common/util/concurrent/Atomics.java @@ -17,6 +17,7 @@ import com.google.common.annotations.GwtIncompatible; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReferenceArray; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -34,8 +35,8 @@ private Atomics() {} * * @return a new {@code AtomicReference} with no initial value */ - public static AtomicReference newReference() { - return new AtomicReference(); + public static AtomicReference<@Nullable V> newReference() { + return new AtomicReference<>(); } /** @@ -44,8 +45,8 @@ public static AtomicReference newReference() { * @param initialValue the initial value * @return a new {@code AtomicReference} with the given initial value */ - public static AtomicReference newReference(@Nullable V initialValue) { - return new AtomicReference(initialValue); + public static AtomicReference newReference(V initialValue) { + return new AtomicReference<>(initialValue); } /** @@ -54,8 +55,8 @@ public static AtomicReference newReference(@Nullable V initialValue) { * @param length the length of the array * @return a new {@code AtomicReferenceArray} with the given length */ - public static AtomicReferenceArray newReferenceArray(int length) { - return new AtomicReferenceArray(length); + public static AtomicReferenceArray<@Nullable E> newReferenceArray(int length) { + return new AtomicReferenceArray<>(length); } /** @@ -65,7 +66,7 @@ public static AtomicReferenceArray newReferenceArray(int length) { * @param array the array to copy elements from * @return a new {@code AtomicReferenceArray} copied from the given array */ - public static AtomicReferenceArray newReferenceArray(E[] array) { - return new AtomicReferenceArray(array); + public static AtomicReferenceArray newReferenceArray(E[] array) { + return new AtomicReferenceArray<>(array); } } diff --git a/guava/src/com/google/common/util/concurrent/Callables.java b/guava/src/com/google/common/util/concurrent/Callables.java index 747ffa758f96..168d881e5f7d 100644 --- a/guava/src/com/google/common/util/concurrent/Callables.java +++ b/guava/src/com/google/common/util/concurrent/Callables.java @@ -34,7 +34,7 @@ public final class Callables { private Callables() {} /** Creates a {@code Callable} which immediately returns a preset value each time it is called. */ - public static Callable returning(final @Nullable T value) { + public static Callable returning(final T value) { return new Callable() { @Override public T call() { @@ -69,7 +69,6 @@ public ListenableFuture call() throws Exception { * Wraps the given callable such that for the duration of {@link Callable#call} the thread that is * running will have the given name. * - * * @param callable The callable to wrap * @param nameSupplier The supplier of thread names, {@link Supplier#get get} will be called once * for each invocation of the wrapped callable. @@ -100,7 +99,6 @@ public T call() throws Exception { * Wraps the given runnable such that for the duration of {@link Runnable#run} the thread that is * running with have the given name. * - * * @param task The Runnable to wrap * @param nameSupplier The supplier of thread names, {@link Supplier#get get} will be called once * for each invocation of the wrapped callable. diff --git a/guava/src/com/google/common/util/concurrent/CollectionFuture.java b/guava/src/com/google/common/util/concurrent/CollectionFuture.java index 9f0aa64cedce..a002d123234f 100644 --- a/guava/src/com/google/common/util/concurrent/CollectionFuture.java +++ b/guava/src/com/google/common/util/concurrent/CollectionFuture.java @@ -19,10 +19,9 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.collect.ImmutableCollection; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import java.util.Collections; import java.util.List; -import java.util.concurrent.Future; import org.checkerframework.checker.nullness.qual.Nullable; /** Aggregate future that collects (stores) results of each future. */ @@ -34,17 +33,17 @@ abstract class CollectionFuture extends AggregateFuture { * there: cancel() never reads this field, only writes to it. That makes the race here completely * harmless, rather than just 99.99% harmless. */ - private List> values; + private @Nullable List<@Nullable Present> values; CollectionFuture( ImmutableCollection> futures, boolean allMustSucceed) { super(futures, allMustSucceed, true); - List> values = + List<@Nullable Present> values = futures.isEmpty() - ? ImmutableList.>of() - : Lists.>newArrayListWithCapacity(futures.size()); + ? Collections.<@Nullable Present>emptyList() + : Lists.<@Nullable Present>newArrayListWithCapacity(futures.size()); // Populate the results list with null initially. for (int i = 0; i < futures.size(); ++i) { @@ -55,8 +54,8 @@ abstract class CollectionFuture extends AggregateFuture { } @Override - final void collectOneValue(int index, @Nullable V returnValue) { - List> localValues = values; + final void collectOneValue(int index, V returnValue) { + List<@Nullable Present> localValues = values; if (localValues != null) { localValues.set(index, new Present<>(returnValue)); } @@ -64,7 +63,7 @@ final void collectOneValue(int index, @Nullable V returnValue) { @Override final void handleAllCompleted() { - List> localValues = values; + List<@Nullable Present> localValues = values; if (localValues != null) { set(combine(localValues)); } @@ -76,10 +75,11 @@ void releaseResources(ReleaseResourcesReason reason) { this.values = null; } - abstract C combine(List> values); + abstract C combine(List<@Nullable Present> values); /** Used for {@link Futures#allAsList} and {@link Futures#successfulAsList}. */ - static final class ListFuture extends CollectionFuture> { + static final class ListFuture + extends CollectionFuture> { ListFuture( ImmutableCollection> futures, boolean allMustSucceed) { @@ -88,8 +88,8 @@ static final class ListFuture extends CollectionFuture> { } @Override - public List combine(List> values) { - List result = newArrayListWithCapacity(values.size()); + public List<@Nullable V> combine(List<@Nullable Present> values) { + List<@Nullable V> result = newArrayListWithCapacity(values.size()); for (Present element : values) { result.add(element != null ? element.value : null); } diff --git a/guava/src/com/google/common/util/concurrent/CombinedFuture.java b/guava/src/com/google/common/util/concurrent/CombinedFuture.java index 51b80be23263..1d242f4ab396 100644 --- a/guava/src/com/google/common/util/concurrent/CombinedFuture.java +++ b/guava/src/com/google/common/util/concurrent/CombinedFuture.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.AggregateFuture.ReleaseResourcesReason.OUTPUT_FUTURE_DONE; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtCompatible; import com.google.common.collect.ImmutableCollection; @@ -29,8 +30,9 @@ /** Aggregate future that computes its value by calling a callable. */ @GwtCompatible -final class CombinedFuture extends AggregateFuture { - private CombinedFutureInterruptibleTask task; +final class CombinedFuture + extends AggregateFuture<@Nullable Object, V> { + private @Nullable CombinedFutureInterruptibleTask task; CombinedFuture( ImmutableCollection> futures, @@ -87,7 +89,8 @@ protected void interruptTask() { } @WeakOuter - private abstract class CombinedFutureInterruptibleTask extends InterruptibleTask { + private abstract class CombinedFutureInterruptibleTask + extends InterruptibleTask { private final Executor listenerExecutor; boolean thrownByExecute = true; @@ -111,7 +114,7 @@ final void execute() { } @Override - final void afterRanInterruptibly(T result, Throwable error) { + final void afterRanInterruptiblySuccess(T result) { /* * The future no longer needs to interrupt this task, so it no longer needs a reference to it. * @@ -125,16 +128,21 @@ final void afterRanInterruptibly(T result, Throwable error) { */ CombinedFuture.this.task = null; - if (error != null) { - if (error instanceof ExecutionException) { - CombinedFuture.this.setException(error.getCause()); - } else if (error instanceof CancellationException) { - cancel(false); - } else { - CombinedFuture.this.setException(error); - } + setValue(result); + } + + @Override + final void afterRanInterruptiblyFailure(Throwable error) { + // See afterRanInterruptiblySuccess. + CombinedFuture.this.task = null; + + if (error instanceof ExecutionException) { + // requireNonNull should be safe: See AbstractFuture.getFutureValue. + CombinedFuture.this.setException(requireNonNull(error.getCause())); + } else if (error instanceof CancellationException) { + cancel(false); } else { - setValue(result); + CombinedFuture.this.setException(error); } } diff --git a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java index 67d247867166..25bee89dbc64 100644 --- a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java +++ b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java @@ -15,6 +15,7 @@ package com.google.common.util.concurrent; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -32,6 +33,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -302,8 +304,8 @@ private static Map getOrCreateNodes(Class> Map createNodes(Class clazz) { EnumMap map = Maps.newEnumMap(clazz); - E[] keys = clazz.getEnumConstants(); - final int numKeys = keys.length; + EnumSet keys = EnumSet.allOf(clazz); + final int numKeys = keys.size(); ArrayList nodes = Lists.newArrayListWithCapacity(numKeys); // Create a LockGraphNode for each enum value. for (E key : keys) { @@ -417,7 +419,9 @@ public ReentrantLock newReentrantLock(E rank) { public ReentrantLock newReentrantLock(E rank, boolean fair) { return policy == Policies.DISABLED ? new ReentrantLock(fair) - : new CycleDetectingReentrantLock(lockGraphNodes.get(rank), fair); + // requireNonNull is safe because createNodes inserts an entry for every E. + // (If the caller passes `null` for the `rank` parameter, this will throw, but that's OK.) + : new CycleDetectingReentrantLock(requireNonNull(lockGraphNodes.get(rank)), fair); } /** Equivalent to {@code newReentrantReadWriteLock(rank, false)}. */ @@ -436,7 +440,10 @@ public ReentrantReadWriteLock newReentrantReadWriteLock(E rank) { public ReentrantReadWriteLock newReentrantReadWriteLock(E rank, boolean fair) { return policy == Policies.DISABLED ? new ReentrantReadWriteLock(fair) - : new CycleDetectingReentrantReadWriteLock(lockGraphNodes.get(rank), fair); + // requireNonNull is safe because createNodes inserts an entry for every E. + // (If the caller passes `null` for the `rank` parameter, this will throw, but that's OK.) + : new CycleDetectingReentrantReadWriteLock( + requireNonNull(lockGraphNodes.get(rank)), fair); } } @@ -487,6 +494,7 @@ private static class ExampleStackTrace extends IllegalStateException { ExampleStackTrace.class.getName(), LockGraphNode.class.getName()); + @SuppressWarnings("argument.type.incompatible") // arrays ExampleStackTrace(LockGraphNode node1, LockGraphNode node2) { super(node1.getLockName() + " -> " + node2.getLockName()); StackTraceElement[] origStackTrace = getStackTrace(); @@ -546,7 +554,8 @@ public ExampleStackTrace getConflictingStackTrace() { */ @Override public String getMessage() { - StringBuilder message = new StringBuilder(super.getMessage()); + // requireNonNull is safe because ExampleStackTrace sets a non-null message. + StringBuilder message = new StringBuilder(requireNonNull(super.getMessage())); for (Throwable t = conflictingStackTrace; t != null; t = t.getCause()) { message.append(", ").append(t.getMessage()); } @@ -705,7 +714,11 @@ void checkAcquiredLock(Policy policy, LockGraphNode acquiredLock) { */ private void aboutToAcquire(CycleDetectingLock lock) { if (!lock.isAcquiredByCurrentThread()) { - ArrayList acquiredLockList = acquiredLocks.get(); + /* + * requireNonNull is safe because acquiredLocks has a non-null initialValue and is never set + * to a null value. + */ + ArrayList acquiredLockList = requireNonNull(acquiredLocks.get()); LockGraphNode node = lock.getLockGraphNode(); node.checkAcquiredLocks(policy, acquiredLockList); acquiredLockList.add(node); @@ -719,7 +732,11 @@ private void aboutToAcquire(CycleDetectingLock lock) { */ private static void lockStateChanged(CycleDetectingLock lock) { if (!lock.isAcquiredByCurrentThread()) { - ArrayList acquiredLockList = acquiredLocks.get(); + /* + * requireNonNull is safe because acquiredLocks has a non-null initialValue and is never set + * to a null value. + */ + ArrayList acquiredLockList = requireNonNull(acquiredLocks.get()); LockGraphNode node = lock.getLockGraphNode(); // Iterate in reverse because locks are usually locked/unlocked in a // LIFO order. @@ -817,6 +834,8 @@ final class CycleDetectingReentrantReadWriteLock extends ReentrantReadWriteLock private final LockGraphNode lockGraphNode; + // Suppressions for initialization checker + @SuppressWarnings({"argument.type.incompatible", "assignment.type.incompatible"}) private CycleDetectingReentrantReadWriteLock(LockGraphNode lockGraphNode, boolean fair) { super(fair); this.readLock = new CycleDetectingReentrantReadLock(this); diff --git a/guava/src/com/google/common/util/concurrent/ExecutionList.java b/guava/src/com/google/common/util/concurrent/ExecutionList.java index 1ff609b78c98..06d3cd343450 100644 --- a/guava/src/com/google/common/util/concurrent/ExecutionList.java +++ b/guava/src/com/google/common/util/concurrent/ExecutionList.java @@ -155,7 +155,8 @@ private static final class RunnableExecutorPair { final Executor executor; @Nullable RunnableExecutorPair next; - RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) { + RunnableExecutorPair( + Runnable runnable, Executor executor, @Nullable RunnableExecutorPair next) { this.runnable = runnable; this.executor = executor; this.next = next; diff --git a/guava/src/com/google/common/util/concurrent/ExecutionSequencer.java b/guava/src/com/google/common/util/concurrent/ExecutionSequencer.java index 88929b6cedbb..b35ebcce5f0f 100644 --- a/guava/src/com/google/common/util/concurrent/ExecutionSequencer.java +++ b/guava/src/com/google/common/util/concurrent/ExecutionSequencer.java @@ -21,11 +21,13 @@ import static com.google.common.util.concurrent.Futures.immediateCancelledFuture; import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Serializes execution of a set of operations. This class guarantees that a submitted callable will @@ -55,7 +57,7 @@ enum RunningState { } /** This reference acts as a pointer tracking the head of a linked list of ListenableFutures. */ - private final AtomicReference> ref = + private final AtomicReference> ref = new AtomicReference<>(immediateFuture(null)); /** @@ -65,7 +67,8 @@ enum RunningState { * execute, but if the output future is cancelled before {@link Callable#call()} is invoked, * {@link Callable#call()} will not be invoked. */ - public ListenableFuture submit(final Callable callable, Executor executor) { + public ListenableFuture submit( + final Callable callable, Executor executor) { checkNotNull(callable); return submitAsync( new AsyncCallable() { @@ -119,9 +122,14 @@ public String toString() { * have completed - namely after oldFuture is done, and taskFuture has either completed or been * cancelled before the callable started execution. */ - final SettableFuture newFuture = SettableFuture.create(); + final SettableFuture<@Nullable Object> newFuture = SettableFuture.create(); - final ListenableFuture oldFuture = ref.getAndSet(newFuture); + /* + * requireNonNull is safe because we initialize ref with a non-null value and always replace it + * with another non-null value. + */ + final ListenableFuture oldFuture = + requireNonNull(ref.getAndSet(newFuture)); // Invoke our task once the previous future completes. final ListenableFuture taskFuture = diff --git a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java index 9dad51be2c8b..ba67eee47c27 100644 --- a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java +++ b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java @@ -22,6 +22,8 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A TimeLimiter implementation which actually does not attempt to limit time at all. This may be @@ -38,7 +40,7 @@ @GwtIncompatible public final class FakeTimeLimiter implements TimeLimiter { @Override - public T newProxy( + public T newProxy( T target, Class interfaceType, long timeoutDuration, TimeUnit timeoutUnit) { checkNotNull(target); checkNotNull(interfaceType); @@ -47,8 +49,8 @@ public T newProxy( } @Override - public T callWithTimeout(Callable callable, long timeoutDuration, TimeUnit timeoutUnit) - throws ExecutionException { + public T callWithTimeout( + Callable callable, long timeoutDuration, TimeUnit timeoutUnit) throws ExecutionException { checkNotNull(callable); checkNotNull(timeoutUnit); try { diff --git a/guava/src/com/google/common/util/concurrent/FluentFuture.java b/guava/src/com/google/common/util/concurrent/FluentFuture.java index c286e6fe8ed6..ca04c6873e73 100644 --- a/guava/src/com/google/common/util/concurrent/FluentFuture.java +++ b/guava/src/com/google/common/util/concurrent/FluentFuture.java @@ -22,13 +22,13 @@ import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Function; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.time.Duration; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link ListenableFuture} that supports fluent chains of operations. For example: @@ -72,9 +72,9 @@ * @since 23.0 */ @Beta -@DoNotMock("Use FluentFuture.from(Futures.immediate*Future) or SettableFuture") @GwtCompatible(emulated = true) -public abstract class FluentFuture extends GwtFluentFutureCatchingSpecialization { +public abstract class FluentFuture + extends GwtFluentFutureCatchingSpecialization { /** * A less abstract subclass of AbstractFuture. This can be used to optimize setFuture by ensuring @@ -359,7 +359,8 @@ public final FluentFuture transformAsync( * @param executor Executor to run the function in. * @return A future that holds result of the transformation. */ - public final FluentFuture transform(Function function, Executor executor) { + public final FluentFuture transform( + Function function, Executor executor) { return (FluentFuture) Futures.transform(this, function, executor); } diff --git a/guava/src/com/google/common/util/concurrent/ForwardingBlockingDeque.java b/guava/src/com/google/common/util/concurrent/ForwardingBlockingDeque.java index 2485966948de..2c1215e7a647 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingBlockingDeque.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingBlockingDeque.java @@ -21,6 +21,8 @@ import java.util.Collection; import java.util.concurrent.BlockingDeque; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link BlockingDeque} which forwards all its method calls to another {@code BlockingDeque}. @@ -44,7 +46,7 @@ * @since 21.0 (since 14.0 as {@link com.google.common.collect.ForwardingBlockingDeque}) */ @GwtIncompatible -public abstract class ForwardingBlockingDeque extends ForwardingDeque +public abstract class ForwardingBlockingDeque extends ForwardingDeque implements BlockingDeque { /** Constructor for use by subclasses. */ @@ -89,12 +91,12 @@ public E takeLast() throws InterruptedException { } @Override - public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E pollFirst(long timeout, TimeUnit unit) throws InterruptedException { return delegate().pollFirst(timeout, unit); } @Override - public E pollLast(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E pollLast(long timeout, TimeUnit unit) throws InterruptedException { return delegate().pollLast(timeout, unit); } @@ -114,7 +116,7 @@ public E take() throws InterruptedException { } @Override - public E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { return delegate().poll(timeout, unit); } diff --git a/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java b/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java index f5575a15767c..1cc8510a4e68 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java @@ -20,6 +20,8 @@ import java.util.Collection; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link BlockingQueue} which forwards all its method calls to another {@link BlockingQueue}. @@ -37,7 +39,7 @@ */ @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict. @GwtIncompatible -public abstract class ForwardingBlockingQueue extends ForwardingQueue +public abstract class ForwardingBlockingQueue extends ForwardingQueue implements BlockingQueue { /** Constructor for use by subclasses. */ @@ -62,7 +64,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedExcepti } @Override - public E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { return delegate().poll(timeout, unit); } diff --git a/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java b/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java index f9da1d495631..3d9f59829e01 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java @@ -25,6 +25,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An executor service which forwards all its method calls to another executor service. Subclasses @@ -50,8 +51,8 @@ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedE } @Override - public List> invokeAll(Collection> tasks) - throws InterruptedException { + public List> invokeAll( + Collection> tasks) throws InterruptedException { return delegate().invokeAll(tasks); } @@ -69,7 +70,8 @@ public T invokeAny(Collection> tasks) } @Override - public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) + public T invokeAny( + Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return delegate().invokeAny(tasks, timeout, unit); } diff --git a/guava/src/com/google/common/util/concurrent/ForwardingFluentFuture.java b/guava/src/com/google/common/util/concurrent/ForwardingFluentFuture.java index 984fd680162d..cd80d4a313b8 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingFluentFuture.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingFluentFuture.java @@ -21,6 +21,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * {@link FluentFuture} that forwards all calls to a delegate. diff --git a/guava/src/com/google/common/util/concurrent/ForwardingFuture.java b/guava/src/com/google/common/util/concurrent/ForwardingFuture.java index 165793bef25c..85591854638f 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingFuture.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingFuture.java @@ -22,6 +22,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link Future} which forwards all its method calls to another future. Subclasses should @@ -35,7 +36,8 @@ */ @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict. @GwtCompatible -public abstract class ForwardingFuture extends ForwardingObject implements Future { +public abstract class ForwardingFuture extends ForwardingObject + implements Future { /** Constructor for use by subclasses. */ protected ForwardingFuture() {} @@ -75,7 +77,8 @@ public V get(long timeout, TimeUnit unit) * * @since 9.0 */ - public abstract static class SimpleForwardingFuture extends ForwardingFuture { + public abstract static class SimpleForwardingFuture + extends ForwardingFuture { private final Future delegate; protected SimpleForwardingFuture(Future delegate) { diff --git a/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java b/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java index d3ed3c28a89b..ee598d15b649 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java @@ -18,6 +18,7 @@ import com.google.common.base.Preconditions; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.concurrent.Executor; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link ListenableFuture} which forwards all its method calls to another future. Subclasses @@ -31,8 +32,8 @@ */ @CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict. @GwtCompatible -public abstract class ForwardingListenableFuture extends ForwardingFuture - implements ListenableFuture { +public abstract class ForwardingListenableFuture + extends ForwardingFuture implements ListenableFuture { /** Constructor for use by subclasses. */ protected ForwardingListenableFuture() {} diff --git a/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java index 48a49b89d83c..8c7e42390e53 100644 --- a/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java @@ -17,6 +17,7 @@ import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.concurrent.Callable; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A listening executor service which forwards all its method calls to another listening executor diff --git a/guava/src/com/google/common/util/concurrent/FutureCallback.java b/guava/src/com/google/common/util/concurrent/FutureCallback.java index b18047751469..4c5c2351694a 100644 --- a/guava/src/com/google/common/util/concurrent/FutureCallback.java +++ b/guava/src/com/google/common/util/concurrent/FutureCallback.java @@ -31,7 +31,7 @@ @GwtCompatible public interface FutureCallback { /** Invoked with the result of the {@code Future} computation when it is successful. */ - void onSuccess(@Nullable V result); + void onSuccess(V result); /** * Invoked when a {@code Future} computation fails or is canceled. diff --git a/guava/src/com/google/common/util/concurrent/Futures.java b/guava/src/com/google/common/util/concurrent/Futures.java index c241cb848c31..61d52d3b4c92 100644 --- a/guava/src/com/google/common/util/concurrent/Futures.java +++ b/guava/src/com/google/common/util/concurrent/Futures.java @@ -19,6 +19,7 @@ import static com.google.common.util.concurrent.Internal.toNanosSaturated; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -127,7 +128,7 @@ private Futures() {} * getters just return the value. This {@code Future} can't be canceled or timed out and its * {@code isDone()} method always returns {@code true}. */ - public static ListenableFuture immediateFuture(@Nullable V value) { + public static ListenableFuture immediateFuture(V value) { if (value == null) { // This cast is safe because null is assignable to V for all V (i.e. it is bivariant) @SuppressWarnings("unchecked") @@ -155,7 +156,8 @@ public static ListenableFuture immediateVoidFuture() { * returns {@code true}. Calling {@code get()} will immediately throw the provided {@code * Throwable} wrapped in an {@code ExecutionException}. */ - public static ListenableFuture immediateFailedFuture(Throwable throwable) { + public static ListenableFuture immediateFailedFuture( + Throwable throwable) { checkNotNull(throwable); return new ImmediateFailedFuture(throwable); } @@ -191,8 +193,9 @@ public static ListenableFuture submit(Callable callable, Executor exec * @since 28.2 */ @Beta - public static ListenableFuture submit(Runnable runnable, Executor executor) { - TrustedListenableFutureTask task = TrustedListenableFutureTask.create(runnable, null); + public static ListenableFuture<@Nullable Void> submit(Runnable runnable, Executor executor) { + TrustedListenableFutureTask<@Nullable Void> task = + TrustedListenableFutureTask.create(runnable, null); executor.execute(task); return task; } @@ -204,7 +207,8 @@ public static ListenableFuture submit(Runnable runnable, Executor executor * @since 23.0 */ @Beta - public static ListenableFuture submitAsync(AsyncCallable callable, Executor executor) { + public static ListenableFuture submitAsync( + AsyncCallable callable, Executor executor) { TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); executor.execute(task); return task; @@ -238,7 +242,8 @@ public static ListenableFuture scheduleAsync( TimeUnit timeUnit, ScheduledExecutorService executorService) { TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); - final Future scheduled = executorService.schedule(task, delay, timeUnit); + final Future scheduled = + executorService.schedule(task, delay, timeUnit); task.addListener( new Runnable() { @Override @@ -449,10 +454,11 @@ public static ListenableFuture withTimeout( * @since 19.0 (in 11.0 as {@code transform}) */ @Beta - public static ListenableFuture transformAsync( - ListenableFuture input, - AsyncFunction function, - Executor executor) { + public static + ListenableFuture transformAsync( + ListenableFuture input, + AsyncFunction function, + Executor executor) { return AbstractTransformFuture.create(input, function, executor); } @@ -488,8 +494,9 @@ public static ListenableFuture transformAsync( * @since 9.0 (in 2.0 as {@code compose}) */ @Beta - public static ListenableFuture transform( - ListenableFuture input, Function function, Executor executor) { + public static + ListenableFuture transform( + ListenableFuture input, Function function, Executor executor) { return AbstractTransformFuture.create(input, function, executor); } @@ -575,8 +582,14 @@ private O applyTransformation(I input) throws ExecutionException { */ @Beta @SafeVarargs - public static ListenableFuture> allAsList(ListenableFuture... futures) { - return new ListFuture(ImmutableList.copyOf(futures), true); + public static ListenableFuture> allAsList( + ListenableFuture... futures) { + ListenableFuture> nullable = + new ListFuture(ImmutableList.copyOf(futures), true); + // allAsList ensures that it fills the output list with V instances. + @SuppressWarnings("nullness") + ListenableFuture> nonNull = nullable; + return nonNull; } /** @@ -598,7 +611,12 @@ public static ListenableFuture> allAsList(ListenableFuture ListenableFuture> allAsList( Iterable> futures) { - return new ListFuture(ImmutableList.copyOf(futures), true); + ListenableFuture> nullable = + new ListFuture(ImmutableList.copyOf(futures), true); + // allAsList ensures that it fills the output list with V instances. + @SuppressWarnings("nullness") + ListenableFuture> nonNull = nullable; + return nonNull; } /** @@ -611,7 +629,8 @@ public static ListenableFuture> allAsList( */ @Beta @SafeVarargs - public static FutureCombiner whenAllComplete(ListenableFuture... futures) { + public static FutureCombiner whenAllComplete( + ListenableFuture... futures) { return new FutureCombiner(false, ImmutableList.copyOf(futures)); } @@ -638,7 +657,8 @@ public static FutureCombiner whenAllComplete( */ @Beta @SafeVarargs - public static FutureCombiner whenAllSucceed(ListenableFuture... futures) { + public static FutureCombiner whenAllSucceed( + ListenableFuture... futures) { return new FutureCombiner(true, ImmutableList.copyOf(futures)); } @@ -708,7 +728,8 @@ private FutureCombiner( * *

    Canceling this future will attempt to cancel all the component futures. */ - public ListenableFuture callAsync(AsyncCallable combiner, Executor executor) { + public ListenableFuture callAsync( + AsyncCallable combiner, Executor executor) { return new CombinedFuture(futures, allMustSucceed, executor, combiner); } @@ -727,7 +748,8 @@ public ListenableFuture callAsync(AsyncCallable combiner, Executor exe *

    Canceling this future will attempt to cancel all the component futures. */ @CanIgnoreReturnValue // TODO(cpovirk): Remove this - public ListenableFuture call(Callable combiner, Executor executor) { + public ListenableFuture call( + Callable combiner, Executor executor) { return new CombinedFuture(futures, allMustSucceed, executor, combiner); } @@ -742,11 +764,12 @@ public ListenableFuture call(Callable combiner, Executor executor) { * * @since 23.6 */ - public ListenableFuture run(final Runnable combiner, Executor executor) { + public ListenableFuture run( + final Runnable combiner, Executor executor) { return call( - new Callable() { + new Callable<@Nullable Void>() { @Override - public Void call() throws Exception { + public @Nullable Void call() throws Exception { combiner.run(); return null; } @@ -763,7 +786,8 @@ public Void call() throws Exception { * @since 15.0 */ @Beta - public static ListenableFuture nonCancellationPropagating(ListenableFuture future) { + public static ListenableFuture nonCancellationPropagating( + ListenableFuture future) { if (future.isDone()) { return future; } @@ -775,7 +799,7 @@ public static ListenableFuture nonCancellationPropagating(ListenableFutur /** A wrapped future that does not propagate cancellation to its delegate. */ private static final class NonCancellationPropagatingFuture extends AbstractFuture.TrustedFuture implements Runnable { - private ListenableFuture delegate; + private @Nullable ListenableFuture delegate; NonCancellationPropagatingFuture(final ListenableFuture delegate) { this.delegate = delegate; @@ -792,7 +816,7 @@ public void run() { } @Override - protected String pendingToString() { + protected @Nullable String pendingToString() { ListenableFuture localDelegate = delegate; if (localDelegate != null) { return "delegate=[" + localDelegate + "]"; @@ -824,9 +848,21 @@ protected void afterDone() { * @return a future that provides a list of the results of the component futures * @since 10.0 */ + /* + * Another way to express this signature would be to bound by @NonNull and accept LF. That might be better: There's currently no difference between the outputs users + * get when calling this with and calling it with <@Nullable Foo>. The only difference is + * that calling it with won't work when an input Future has a @Nullable type. So why even + * make that error possible by giving callers the choice? + * + * On the other hand, the current signature is consistent with the similar allAsList method. And + * eventually this method may go away entirely in favor of an API like + * whenAllComplete().collectSuccesses(). That API would have a signature more like the current + * one. + */ @Beta @SafeVarargs - public static ListenableFuture> successfulAsList( + public static ListenableFuture> successfulAsList( ListenableFuture... futures) { return new ListFuture(ImmutableList.copyOf(futures), false); } @@ -850,7 +886,7 @@ public static ListenableFuture> successfulAsList( * @since 10.0 */ @Beta - public static ListenableFuture> successfulAsList( + public static ListenableFuture> successfulAsList( Iterable> futures) { return new ListFuture(ImmutableList.copyOf(futures), false); } @@ -917,8 +953,9 @@ public void run() { // This can't be a TrustedFuture, because TrustedFuture has clever optimizations that // mean cancel won't be called if this Future is passed into setFuture, and then // cancelled. - private static final class InCompletionOrderFuture extends AbstractFuture { - private InCompletionOrderState state; + private static final class InCompletionOrderFuture + extends AbstractFuture { + private @Nullable InCompletionOrderState state; private InCompletionOrderFuture(InCompletionOrderState state) { this.state = state; @@ -928,7 +965,15 @@ private InCompletionOrderFuture(InCompletionOrderState state) { public boolean cancel(boolean interruptIfRunning) { InCompletionOrderState localState = state; if (super.cancel(interruptIfRunning)) { - localState.recordOutputCancellation(interruptIfRunning); + /* + * requireNonNull is generally safe: If cancel succeeded, then this Future was still + * pending, so its `state` field hasn't been nulled out yet. + * + * OK, it's technically possible for this to fail in the presence of unsafe publishing, as + * discussed in the comments in TimeoutFuture. TODO(cpovirk): Maybe check for null before + * calling recordOutputCancellation? + */ + requireNonNull(localState).recordOutputCancellation(interruptIfRunning); return true; } return false; @@ -940,7 +985,7 @@ protected void afterDone() { } @Override - protected String pendingToString() { + protected @Nullable String pendingToString() { InCompletionOrderState localState = state; if (localState != null) { // Don't print the actual array! We don't want inCompletionOrder(list).toString() to have @@ -962,10 +1007,10 @@ private static final class InCompletionOrderState { private boolean wasCancelled = false; private boolean shouldInterrupt = true; private final AtomicInteger incompleteOutputCount; - private final ListenableFuture[] inputFutures; + private final @Nullable ListenableFuture[] inputFutures; private volatile int delegateIndex = 0; - private InCompletionOrderState(ListenableFuture[] inputFutures) { + private InCompletionOrderState(@Nullable ListenableFuture[] inputFutures) { this.inputFutures = inputFutures; incompleteOutputCount = new AtomicInteger(inputFutures.length); } @@ -982,7 +1027,11 @@ private void recordOutputCancellation(boolean interruptIfRunning) { private void recordInputCompletion( ImmutableList> delegates, int inputFutureIndex) { - ListenableFuture inputFuture = inputFutures[inputFutureIndex]; + /* + * requireNonNull is safe because we accepted an Iterable of non-null Future instances, and we + * don't overwrite an element in the array until after reading it. + */ + ListenableFuture inputFuture = requireNonNull(inputFutures[inputFutureIndex]); // Null out our reference to this future, so it can be GCed inputFutures[inputFutureIndex] = null; for (int i = delegateIndex; i < delegates.size(); i++) { @@ -1001,7 +1050,7 @@ private void recordInputCompletion( private void recordCompletion() { if (incompleteOutputCount.decrementAndGet() == 0 && wasCancelled) { - for (ListenableFuture toCancel : inputFutures) { + for (ListenableFuture toCancel : inputFutures) { if (toCancel != null) { toCancel.cancel(shouldInterrupt); } @@ -1080,7 +1129,11 @@ public void run() { try { value = getDone(future); } catch (ExecutionException e) { - callback.onFailure(e.getCause()); + /* + * requireNonNull should be safe because an ExecutionException from a Future should have a + * cause. But see AbstractFuture.getFutureValue. + */ + callback.onFailure(requireNonNull(e.getCause())); return; } catch (RuntimeException | Error e) { callback.onFailure(e); @@ -1177,8 +1230,8 @@ public static V getDone(Future future) throws ExecutionException { @Beta @CanIgnoreReturnValue @GwtIncompatible // reflection - public static V getChecked(Future future, Class exceptionClass) - throws X { + public static V getChecked( + Future future, Class exceptionClass) throws X { return FuturesGetChecked.getChecked(future, exceptionClass); } @@ -1325,7 +1378,14 @@ public static V getUnchecked(Future future) { try { return getUninterruptibly(future); } catch (ExecutionException e) { - wrapAndThrowUnchecked(e.getCause()); + /* + * requireNonNull should be safe because an ExecutionException from a Future should have a + * cause. In some similar cases, we may want to handle null more gracefully, as discussed in + * AbstractFuture.getFutureValue. However, in this particular case, all we're doing is + * throwing an exception, so there's not much we could do differently. That's fine: Unlike in + * some of the similar cases, we're not responsible for notifying listeners. + */ + wrapAndThrowUnchecked(requireNonNull(e.getCause())); throw new AssertionError(); } } diff --git a/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java b/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java index 23650408370c..7ff8e46867c6 100644 --- a/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java +++ b/guava/src/com/google/common/util/concurrent/FuturesGetChecked.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.lang.Thread.currentThread; import static java.util.Arrays.asList; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.VisibleForTesting; @@ -35,13 +36,15 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** Static methods used to implement {@link Futures#getChecked(Future, Class)}. */ @GwtIncompatible final class FuturesGetChecked { @CanIgnoreReturnValue - static V getChecked(Future future, Class exceptionClass) throws X { + static V getChecked( + Future future, Class exceptionClass) throws X { return getChecked(bestGetCheckedTypeValidator(), future, exceptionClass); } @@ -57,7 +60,8 @@ static V getChecked( currentThread().interrupt(); throw newWithCause(exceptionClass, e); } catch (ExecutionException e) { - wrapAndThrowExceptionOrError(e.getCause(), exceptionClass); + // requireNonNull should be safe: See AbstractFuture.getFutureValue. + wrapAndThrowExceptionOrError(requireNonNull(e.getCause()), exceptionClass); throw new AssertionError(); } } @@ -76,7 +80,8 @@ static V getChecked( } catch (TimeoutException e) { throw newWithCause(exceptionClass, e); } catch (ExecutionException e) { - wrapAndThrowExceptionOrError(e.getCause(), exceptionClass); + // requireNonNull should be safe: See AbstractFuture.getFutureValue. + wrapAndThrowExceptionOrError(requireNonNull(e.getCause()), exceptionClass); throw new AssertionError(); } } @@ -186,7 +191,8 @@ public void validateClass(Class exceptionClass) { static GetCheckedTypeValidator getBestValidator() { try { Class theClass = Class.forName(CLASS_VALUE_VALIDATOR_NAME); - return (GetCheckedTypeValidator) theClass.getEnumConstants()[0]; + // requireNonNull is safe because the class is an enum. + return (GetCheckedTypeValidator) requireNonNull(theClass.getEnumConstants())[0]; } catch (Throwable t) { // ensure we really catch *everything* return weakSetValidator(); } @@ -256,7 +262,8 @@ public Boolean apply(Constructor input) { }) .reverse(); - private static @Nullable X newFromConstructor(Constructor constructor, Throwable cause) { + private static @Nullable X newFromConstructor( + Constructor constructor, Throwable cause) { Class[] paramTypes = constructor.getParameterTypes(); Object[] params = new Object[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) { diff --git a/guava/src/com/google/common/util/concurrent/GwtFluentFutureCatchingSpecialization.java b/guava/src/com/google/common/util/concurrent/GwtFluentFutureCatchingSpecialization.java index e8acf625af72..6e7c5c70ede6 100644 --- a/guava/src/com/google/common/util/concurrent/GwtFluentFutureCatchingSpecialization.java +++ b/guava/src/com/google/common/util/concurrent/GwtFluentFutureCatchingSpecialization.java @@ -15,6 +15,7 @@ package com.google.common.util.concurrent; import com.google.common.annotations.GwtCompatible; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Hidden superclass of {@link FluentFuture} that provides us a place to declare special GWT @@ -22,7 +23,8 @@ * FluentFuture.catching} family of methods. Those versions have slightly different signatures. */ @GwtCompatible(emulated = true) -abstract class GwtFluentFutureCatchingSpecialization extends AbstractFuture { +abstract class GwtFluentFutureCatchingSpecialization + extends AbstractFuture { /* * This server copy of the class is empty. The corresponding GWT copy contains alternative * versions of catching() and catchingAsync() with slightly different signatures from the ones diff --git a/guava/src/com/google/common/util/concurrent/ImmediateFuture.java b/guava/src/com/google/common/util/concurrent/ImmediateFuture.java index 7bee37d58d69..8e50c9e617e6 100644 --- a/guava/src/com/google/common/util/concurrent/ImmediateFuture.java +++ b/guava/src/com/google/common/util/concurrent/ImmediateFuture.java @@ -29,13 +29,14 @@ @GwtCompatible // TODO(cpovirk): Make this final (but that may break Mockito spy calls). class ImmediateFuture implements ListenableFuture { - static final ListenableFuture NULL = new ImmediateFuture<>(null); + static final ListenableFuture NULL = + new ImmediateFuture<@Nullable Object>(null); private static final Logger log = Logger.getLogger(ImmediateFuture.class.getName()); - private final @Nullable V value; + private final V value; - ImmediateFuture(@Nullable V value) { + ImmediateFuture(V value) { this.value = value; } diff --git a/guava/src/com/google/common/util/concurrent/InterruptibleTask.java b/guava/src/com/google/common/util/concurrent/InterruptibleTask.java index 76537764cd33..645d3b9ae286 100644 --- a/guava/src/com/google/common/util/concurrent/InterruptibleTask.java +++ b/guava/src/com/google/common/util/concurrent/InterruptibleTask.java @@ -27,7 +27,8 @@ // Since this class only needs CAS on one field, we can avoid this bug by extending AtomicReference // instead of using an AtomicReferenceFieldUpdater. This reference stores Thread instances // and DONE/INTERRUPTED - they have a common ancestor of Runnable. -abstract class InterruptibleTask extends AtomicReference implements Runnable { +abstract class InterruptibleTask extends AtomicReference<@Nullable Runnable> + implements Runnable { static { // Prevent rare disastrous classloading in first call to LockSupport.park. // See: https://bugs.openjdk.java.net/browse/JDK-8074773 @@ -130,7 +131,12 @@ public final void run() { */ } if (run) { - afterRanInterruptibly(result, error); + if (error == null) { + // The cast is safe because of the `run` and `error` checks. + afterRanInterruptiblySuccess(uncheckedCastNullableTToT(result)); + } else { + afterRanInterruptiblyFailure(error); + } } } } @@ -151,7 +157,13 @@ public final void run() { * Any interruption that happens as a result of calling interruptTask will arrive before this * method is called. Complete Futures here. */ - abstract void afterRanInterruptibly(@Nullable T result, @Nullable Throwable error); + abstract void afterRanInterruptiblySuccess(T result); + + /** + * Any interruption that happens as a result of calling interruptTask will arrive before this + * method is called. Complete Futures here. + */ + abstract void afterRanInterruptiblyFailure(Throwable error); /** * Interrupts the running task. Because this internally calls {@link Thread#interrupt()} which can @@ -196,4 +208,15 @@ public final String toString() { } abstract String toPendingString(); + + @SuppressWarnings("nullness") + private static T uncheckedCastNullableTToT(@Nullable T result) { + /* + * We can't use requireNonNull because `result` might be null. Specifically, it can be null + * because the future might have generated the value `null` to be returned to the user. This + * is in contrast to the other way for `result` to be null, which is for the future to have + * failed, leaving the variable with its initial null value. + */ + return result; + } } diff --git a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java index 1b84302e638d..41bfa7e2ac55 100644 --- a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java +++ b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java @@ -24,6 +24,7 @@ import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Utilities necessary for working with libraries that supply plain {@link Future} instances. Note @@ -49,7 +50,8 @@ public final class JdkFutureAdapters { * ListenableFutureTask}, {@link AbstractFuture}, and other utilities over creating plain {@code * Future} instances to be upgraded to {@code ListenableFuture} after the fact. */ - public static ListenableFuture listenInPoolThread(Future future) { + public static ListenableFuture listenInPoolThread( + Future future) { if (future instanceof ListenableFuture) { return (ListenableFuture) future; } @@ -76,7 +78,8 @@ public static ListenableFuture listenInPoolThread(Future future) { * * @since 12.0 */ - public static ListenableFuture listenInPoolThread(Future future, Executor executor) { + public static ListenableFuture listenInPoolThread( + Future future, Executor executor) { checkNotNull(executor); if (future instanceof ListenableFuture) { return (ListenableFuture) future; @@ -93,8 +96,8 @@ public static ListenableFuture listenInPoolThread(Future future, Execu *

    If the delegate future is interrupted or throws an unexpected unchecked exception, the * listeners will not be invoked. */ - private static class ListenableFutureAdapter extends ForwardingFuture - implements ListenableFuture { + private static class ListenableFutureAdapter + extends ForwardingFuture implements ListenableFuture { private static final ThreadFactory threadFactory = new ThreadFactoryBuilder() diff --git a/guava/src/com/google/common/util/concurrent/ListenableFuture.java b/guava/src/com/google/common/util/concurrent/ListenableFuture.java index 5a636d1acadd..1f3fa0d423b0 100644 --- a/guava/src/com/google/common/util/concurrent/ListenableFuture.java +++ b/guava/src/com/google/common/util/concurrent/ListenableFuture.java @@ -14,10 +14,10 @@ package com.google.common.util.concurrent; -import com.google.errorprone.annotations.DoNotMock; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link Future} that accepts completion listeners. Each listener has an associated executor, and @@ -99,7 +99,12 @@ * @author Nishant Thakkar * @since 1.0 */ -@DoNotMock("Use the methods in Futures (like immediateFuture) or SettableFuture") +/* + * TODO(cpovirk): DO NOT SUBMIT REVERT: We've promised not to change ListenableFuture, at least + * externally. But maybe we could get away with such a small change, or maybe we could make the + * change internally only? Alternatively, maybe we should just create a stub file? That might be + * harder for external users, though. + */ public interface ListenableFuture extends Future { /** * Registers a listener to be {@linkplain Executor#execute(Runnable) run} on the given executor. diff --git a/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java b/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java index ee7e861d49ad..2b006c6b84e8 100644 --- a/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java +++ b/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java @@ -34,7 +34,8 @@ * @since 1.0 */ @GwtIncompatible -public class ListenableFutureTask extends FutureTask implements ListenableFuture { +public class ListenableFutureTask extends FutureTask + implements ListenableFuture { // TODO(cpovirk): explore ways of making ListenableFutureTask final. There are some valid reasons // such as BoundedQueueExecutorService to allow extends but it would be nice to make it final to // avoid unintended usage. @@ -63,7 +64,8 @@ public static ListenableFutureTask create(Callable callable) { * ListenableFutureTask.create(runnable, null)} * @since 10.0 */ - public static ListenableFutureTask create(Runnable runnable, @Nullable V result) { + public static ListenableFutureTask create( + Runnable runnable, V result) { return new ListenableFutureTask(runnable, result); } @@ -71,7 +73,7 @@ public static ListenableFutureTask create(Runnable runnable, @Nullable V super(callable); } - ListenableFutureTask(Runnable runnable, @Nullable V result) { + ListenableFutureTask(Runnable runnable, V result) { super(runnable, result); } diff --git a/guava/src/com/google/common/util/concurrent/ListenableScheduledFuture.java b/guava/src/com/google/common/util/concurrent/ListenableScheduledFuture.java index 77fa5f7fc69b..a091ea34de9b 100644 --- a/guava/src/com/google/common/util/concurrent/ListenableScheduledFuture.java +++ b/guava/src/com/google/common/util/concurrent/ListenableScheduledFuture.java @@ -17,6 +17,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import java.util.concurrent.ScheduledFuture; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Helper interface to implement both {@link ListenableFuture} and {@link ScheduledFuture}. @@ -26,4 +27,5 @@ */ @Beta @GwtCompatible -public interface ListenableScheduledFuture extends ScheduledFuture, ListenableFuture {} +public interface ListenableScheduledFuture + extends ScheduledFuture, ListenableFuture {} diff --git a/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java b/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java index ee6b5b94c964..c44151075106 100644 --- a/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java +++ b/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java @@ -27,6 +27,7 @@ import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A list of listeners for implementing a concurrency friendly observable object. @@ -53,7 +54,7 @@ * #dispatch} is expected to be called concurrently, it is idempotent. */ @GwtIncompatible -final class ListenerCallQueue { +final class ListenerCallQueue { // TODO(cpovirk): consider using the logger associated with listener.getClass(). private static final Logger logger = Logger.getLogger(ListenerCallQueue.class.getName()); @@ -128,7 +129,7 @@ public void dispatch() { *

    This class is very similar to {@link SequentialExecutor} with the exception that events can * be added without necessarily executing immediately. */ - private static final class PerListenerQueue implements Runnable { + private static final class PerListenerQueue implements Runnable { final L listener; final Executor executor; diff --git a/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java index 469eb6757a09..515a317acf59 100644 --- a/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java @@ -15,7 +15,6 @@ package com.google.common.util.concurrent; import com.google.common.annotations.GwtIncompatible; -import com.google.errorprone.annotations.DoNotMock; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; @@ -23,6 +22,7 @@ import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An {@link ExecutorService} that returns {@link ListenableFuture} instances. To create an instance @@ -32,9 +32,6 @@ * @author Chris Povirk * @since 10.0 */ -@DoNotMock( - "Use TestingExecutors.sameThreadScheduledExecutor, or wrap a real Executor from " - + "java.util.concurrent.Executors with MoreExecutors.listeningDecorator") @GwtIncompatible public interface ListeningExecutorService extends ExecutorService { /** diff --git a/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java b/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java index 6410e83f8482..ee185fdb4b5b 100644 --- a/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java @@ -21,6 +21,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A {@link ScheduledExecutorService} that returns {@link ListenableFuture} instances from its @@ -37,7 +38,8 @@ public interface ListeningScheduledExecutorService /** @since 15.0 (previously returned ScheduledFuture) */ @Override - ListenableScheduledFuture schedule(Runnable command, long delay, TimeUnit unit); + ListenableScheduledFuture schedule( + Runnable command, long delay, TimeUnit unit); /** * Duration-based overload of {@link #schedule(Runnable, long, TimeUnit)}. @@ -50,7 +52,8 @@ default ListenableScheduledFuture schedule(Runnable command, Duration delay) /** @since 15.0 (previously returned ScheduledFuture) */ @Override - ListenableScheduledFuture schedule(Callable callable, long delay, TimeUnit unit); + ListenableScheduledFuture schedule( + Callable callable, long delay, TimeUnit unit); /** * Duration-based overload of {@link #schedule(Callable, long, TimeUnit)}. diff --git a/guava/src/com/google/common/util/concurrent/Monitor.java b/guava/src/com/google/common/util/concurrent/Monitor.java index dcdd7b66a13a..9053c50b9f6b 100644 --- a/guava/src/com/google/common/util/concurrent/Monitor.java +++ b/guava/src/com/google/common/util/concurrent/Monitor.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Internal.toNanosSaturated; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; @@ -341,7 +342,7 @@ protected Guard(Monitor monitor) { * A linked list threaded through the Guard.next field. */ @GuardedBy("lock") - private Guard activeGuards = null; + private @Nullable Guard activeGuards = null; /** * Creates a monitor with a non-fair (but fast) ordering policy. Equivalent to {@code @@ -513,7 +514,10 @@ public boolean enterWhen(Guard guard, Duration time) throws InterruptedException * @return whether the monitor was entered, which guarantees that the guard is now satisfied * @throws InterruptedException if interrupted while waiting */ - @SuppressWarnings("GoodTime") // should accept a java.time.Duration + @SuppressWarnings({ + "GoodTime", // should accept a java.time.Duration + "nullness", // https://github.com/typetools/checker-framework/issues/3015 + }) public boolean enterWhen(Guard guard, long time, TimeUnit unit) throws InterruptedException { final long timeoutNanos = toSafeNanos(time, unit); if (guard.monitor != this) { @@ -1153,7 +1157,17 @@ private void endWaitingFor(Guard guard) { int waiters = --guard.waiterCount; if (waiters == 0) { // unlink guard from activeGuards - for (Guard p = activeGuards, pred = null; ; pred = p, p = p.next) { + /* + * Both requireNonNull calls are safe: + * + * - the first because there is at least one active guard (namely, the parameter) + * + * - the second because we won't reach the end without finding the given guard (because we're + * careful not to call this method unless except with an active guard) + */ + for (Guard p = requireNonNull(activeGuards), pred = null; + ; + pred = p, p = requireNonNull(p).next) { if (p == guard) { if (pred == null) { activeGuards = p.next; diff --git a/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/guava/src/com/google/common/util/concurrent/MoreExecutors.java index a897aaa7e3aa..7b8fc35edd96 100644 --- a/guava/src/com/google/common/util/concurrent/MoreExecutors.java +++ b/guava/src/com/google/common/util/concurrent/MoreExecutors.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Internal.toNanosSaturated; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; @@ -51,6 +52,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link ExecutorService}, @@ -446,7 +448,6 @@ public static ListeningExecutorService newDirectExecutorService() { *

    This should be preferred to {@link #newDirectExecutorService()} because implementing the * {@link ExecutorService} subinterface necessitates significant performance overhead. * - * * @since 18.0 */ public static Executor directExecutor() { @@ -599,10 +600,12 @@ private static final class ScheduledListeningDecorator extends ListeningDecorato } @Override - public ListenableScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { - TrustedListenableFutureTask task = TrustedListenableFutureTask.create(command, null); + public ListenableScheduledFuture schedule( + Runnable command, long delay, TimeUnit unit) { + TrustedListenableFutureTask<@Nullable Void> task = + TrustedListenableFutureTask.create(command, null); ScheduledFuture scheduled = delegate.schedule(task, delay, unit); - return new ListenableScheduledTask<>(task, scheduled); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); } @Override @@ -617,8 +620,9 @@ public ListenableScheduledFuture schedule( public ListenableScheduledFuture scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit) { NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); - ScheduledFuture scheduled = delegate.scheduleAtFixedRate(task, initialDelay, period, unit); - return new ListenableScheduledTask<>(task, scheduled); + ScheduledFuture scheduled = + delegate.scheduleAtFixedRate(task, initialDelay, period, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); } @Override @@ -627,7 +631,7 @@ public ListenableScheduledFuture scheduleWithFixedDelay( NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); ScheduledFuture scheduled = delegate.scheduleWithFixedDelay(task, initialDelay, delay, unit); - return new ListenableScheduledTask<>(task, scheduled); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); } private static final class ListenableScheduledTask @@ -636,7 +640,8 @@ private static final class ListenableScheduledTask private final ScheduledFuture scheduledDelegate; public ListenableScheduledTask( - ListenableFuture listenableDelegate, ScheduledFuture scheduledDelegate) { + ListenableFuture listenableDelegate, + ScheduledFuture scheduledDelegate) { super(listenableDelegate); this.scheduledDelegate = scheduledDelegate; } @@ -666,7 +671,7 @@ public int compareTo(Delayed other) { @GwtIncompatible // TODO private static final class NeverSuccessfulListenableFutureTask - extends AbstractFuture.TrustedFuture implements Runnable { + extends AbstractFuture.TrustedFuture<@Nullable Void> implements Runnable { private final Runnable delegate; public NeverSuccessfulListenableFutureTask(Runnable delegate) { @@ -700,7 +705,8 @@ public void run() { * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} * implementations. */ - @GwtIncompatible static T invokeAnyImpl( + @GwtIncompatible + static T invokeAnyImpl( ListeningExecutorService executorService, Collection> tasks, boolean timed, @@ -715,7 +721,8 @@ public void run() { * implementations. */ @SuppressWarnings("GoodTime") // should accept a java.time.Duration - @GwtIncompatible static T invokeAnyImpl( + @GwtIncompatible + static T invokeAnyImpl( ListeningExecutorService executorService, Collection> tasks, boolean timed, @@ -828,10 +835,19 @@ public static ThreadFactory platformThreadFactory() { return Executors.defaultThreadFactory(); } try { + /* + * requireNonNull is safe as long as App Engine is using the default implementation + * ApiProxy.Environment implementation (ApiProxyImpl.EnvironmentImpl). While App Engine + * technically provides way to swap in a different implementation, that shouldn't happen in + * practice in "real" code. + * + * unsafeNull is safe because we are invoking a static method. + */ return (ThreadFactory) - Class.forName("com.google.appengine.api.ThreadManager") - .getMethod("currentRequestThreadFactory") - .invoke(null); + requireNonNull( + Class.forName("com.google.appengine.api.ThreadManager") + .getMethod("currentRequestThreadFactory") + .invoke(unsafeNull())); /* * Do not merge the 3 catch blocks below. javac would infer a type of * ReflectiveOperationException, which Animal Sniffer would reject. (Old versions of Android @@ -844,10 +860,19 @@ public static ThreadFactory platformThreadFactory() { } catch (NoSuchMethodException e) { throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); } catch (InvocationTargetException e) { - throw Throwables.propagate(e.getCause()); + /* + * requireNonNull should be safe because an InvocationTargetException from reflection should + * always have a cause. + */ + throw Throwables.propagate(requireNonNull(e.getCause())); } } + @SuppressWarnings("nullness") + private static Object unsafeNull() { + return null; + } + @GwtIncompatible // TODO private static boolean isAppEngineWithApiClasses() { if (System.getProperty("com.google.appengine.runtime.environment") == null) { @@ -860,9 +885,10 @@ private static boolean isAppEngineWithApiClasses() { } try { // If the current environment is null, we're not inside AppEngine. + // (unsafeNull is safe because we are invoking a static method.) return Class.forName("com.google.apphosting.api.ApiProxy") .getMethod("getCurrentEnvironment") - .invoke(null) + .invoke(unsafeNull()) != null; } catch (ClassNotFoundException e) { // If ApiProxy doesn't exist, we're not on AppEngine at all. @@ -907,7 +933,6 @@ static Thread newThread(String name, Runnable runnable) { * right before each task is run. The renaming is best effort, if a {@link SecurityManager} * prevents the renaming then it will be skipped but the tasks will still execute. * - * * @param executor The executor to decorate * @param nameSupplier The source of names for each task */ @@ -931,7 +956,6 @@ public void execute(Runnable command) { * right before each task is run. The renaming is best effort, if a {@link SecurityManager} * prevents the renaming then it will be skipped but the tasks will still execute. * - * * @param service The executor to decorate * @param nameSupplier The source of names for each task */ @@ -961,7 +985,6 @@ protected Runnable wrapTask(Runnable command) { * right before each task is run. The renaming is best effort, if a {@link SecurityManager} * prevents the renaming then it will be skipped but the tasks will still execute. * - * * @param service The executor to decorate * @param nameSupplier The source of names for each task */ diff --git a/guava/src/com/google/common/util/concurrent/Service.java b/guava/src/com/google/common/util/concurrent/Service.java index 3c4c47628dec..97681b867dca 100644 --- a/guava/src/com/google/common/util/concurrent/Service.java +++ b/guava/src/com/google/common/util/concurrent/Service.java @@ -18,7 +18,6 @@ import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.time.Duration; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -54,7 +53,6 @@ * @author Luke Sandberg * @since 9.0 (in 1.0 as {@code com.google.common.base.Service}) */ -@DoNotMock("Create an AbstractIdleService") @GwtIncompatible public interface Service { /** diff --git a/guava/src/com/google/common/util/concurrent/SettableFuture.java b/guava/src/com/google/common/util/concurrent/SettableFuture.java index a0f47329027b..2924394803cc 100644 --- a/guava/src/com/google/common/util/concurrent/SettableFuture.java +++ b/guava/src/com/google/common/util/concurrent/SettableFuture.java @@ -33,7 +33,8 @@ * @since 9.0 (in 1.0 as {@code ValueFuture}) */ @GwtCompatible -public final class SettableFuture extends AbstractFuture.TrustedFuture { +public final class SettableFuture + extends AbstractFuture.TrustedFuture { /** * Creates a new {@code SettableFuture} that can be completed or cancelled by a later method call. */ @@ -43,7 +44,7 @@ public static SettableFuture create() { @CanIgnoreReturnValue @Override - public boolean set(@Nullable V value) { + public boolean set(V value) { return super.set(value); } diff --git a/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java b/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java index 9d0b81bce26a..ece27c693405 100644 --- a/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java +++ b/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java @@ -34,6 +34,8 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A TimeLimiter that runs method calls in the background using an {@link ExecutorService}. If the @@ -69,7 +71,7 @@ public static SimpleTimeLimiter create(ExecutorService executor) { } @Override - public T newProxy( + public T newProxy( final T target, Class interfaceType, final long timeoutDuration, @@ -85,12 +87,25 @@ public T newProxy( InvocationHandler handler = new InvocationHandler() { @Override - public Object invoke(Object obj, final Method method, final Object[] args) + public @Nullable Object invoke( + Object obj, final Method method, @Nullable Object @Nullable [] argsOrNull) throws Throwable { - Callable callable = - new Callable() { + /* + * Method.invoke can run succesfully when given a null args argument -- as long as the + * method is a no-arg method, which is, thankfully, the only case in which + * InvocationHandler.invoke is passed a null args argument. + * + * However, nullness checkers may well define Method.invoke to *forbid* a null args + * argument: That ensures that callers don't pass null by accident through, e.g., a + * default-initialized field. Callers who intend to pass no arguments can do so + * explicitly by passing an empty array. So we do that here to accommodate more nullness + * checkers. + */ + final @Nullable Object[] args = argsOrNull == null ? NO_ARGS : argsOrNull; + Callable<@Nullable Object> callable = + new Callable<@Nullable Object>() { @Override - public Object call() throws Exception { + public @Nullable Object call() throws Exception { try { return method.invoke(target, args); } catch (InvocationTargetException e) { @@ -105,8 +120,11 @@ public Object call() throws Exception { return newProxy(interfaceType, handler); } + private static final Object[] NO_ARGS = new Object[0]; + // TODO: replace with version in common.reflect if and when it's open-sourced - private static T newProxy(Class interfaceType, InvocationHandler handler) { + private static T newProxy( + Class interfaceType, InvocationHandler handler) { Object object = Proxy.newProxyInstance( interfaceType.getClassLoader(), new Class[] {interfaceType}, handler); @@ -143,7 +161,8 @@ private T callWithTimeout( @CanIgnoreReturnValue @Override - public T callWithTimeout(Callable callable, long timeoutDuration, TimeUnit timeoutUnit) + public T callWithTimeout( + Callable callable, long timeoutDuration, TimeUnit timeoutUnit) throws TimeoutException, InterruptedException, ExecutionException { checkNotNull(callable); checkNotNull(timeoutUnit); @@ -264,7 +283,9 @@ private static boolean declaresInterruptedEx(Method method) { return false; } - private void wrapAndThrowExecutionExceptionOrError(Throwable cause) throws ExecutionException { + // In a sane world, the parameter will never be null. But the code works OK even if it is. + private void wrapAndThrowExecutionExceptionOrError(@Nullable Throwable cause) + throws ExecutionException { if (cause instanceof Error) { throw new ExecutionError((Error) cause); } else if (cause instanceof RuntimeException) { @@ -274,7 +295,8 @@ private void wrapAndThrowExecutionExceptionOrError(Throwable cause) throws Execu } } - private void wrapAndThrowRuntimeExecutionExceptionOrError(Throwable cause) { + // In a sane world, the parameter will never be null. But the code works OK even if it is. + private void wrapAndThrowRuntimeExecutionExceptionOrError(@Nullable Throwable cause) { if (cause instanceof Error) { throw new ExecutionError((Error) cause); } else { diff --git a/guava/src/com/google/common/util/concurrent/Striped.java b/guava/src/com/google/common/util/concurrent/Striped.java index c9ba77235d5a..4a6cd87bf034 100644 --- a/guava/src/com/google/common/util/concurrent/Striped.java +++ b/guava/src/com/google/common/util/concurrent/Striped.java @@ -40,6 +40,8 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A striped {@code Lock/Semaphore/ReadWriteLock}. This offers the underlying lock striping similar @@ -82,7 +84,7 @@ */ @Beta @GwtIncompatible -public abstract class Striped { +public abstract class Striped { /** * If there are at least this many stripes, we assume the memory usage of a ConcurrentMap will be * smaller than a large array. (This assumes that in the lazy case, most stripes are unused. As @@ -136,7 +138,7 @@ private Striped() {} * @return the stripes corresponding to the objects (one per each object, derived by delegating to * {@link #get(Object)}; may contain duplicates), in an increasing index order. */ - public Iterable bulkGet(Iterable keys) { + public Iterable bulkGet(Iterable keys) { // Initially using the array to store the keys, then reusing it to store the respective L's final Object[] array = Iterables.toArray(keys, Object.class); if (array.length == 0) { @@ -191,7 +193,7 @@ public Iterable bulkGet(Iterable keys) { * @param supplier a {@code Supplier} object to obtain locks from * @return a new {@code Striped} */ - static Striped custom(int stripes, Supplier supplier) { + static Striped custom(int stripes, Supplier supplier) { return new CompactStriped<>(stripes, supplier); } @@ -231,7 +233,7 @@ public Lock get() { }); } - private static Striped lazy(int stripes, Supplier supplier) { + private static Striped lazy(int stripes, Supplier supplier) { return stripes < LARGE_LAZY_CUTOFF ? new SmallLazyStriped(stripes, supplier) : new LargeLazyStriped(stripes, supplier); @@ -377,7 +379,7 @@ Condition delegate() { } } - private abstract static class PowerOfTwoStriped extends Striped { + private abstract static class PowerOfTwoStriped extends Striped { /** Capacity (power of two) minus one, for fast mod evaluation */ final int mask; @@ -402,7 +404,7 @@ public final L get(Object key) { * Implementation of Striped where 2^k stripes are represented as an array of the same length, * eagerly initialized. */ - private static class CompactStriped extends PowerOfTwoStriped { + private static class CompactStriped extends PowerOfTwoStriped { /** Size is a power of two. */ private final Object[] array; @@ -434,8 +436,8 @@ public int size() { * user key's (smeared) hashCode(). The stripes are lazily initialized and are weakly referenced. */ @VisibleForTesting - static class SmallLazyStriped extends PowerOfTwoStriped { - final AtomicReferenceArray> locks; + static class SmallLazyStriped extends PowerOfTwoStriped { + final AtomicReferenceArray<@Nullable ArrayReference> locks; final Supplier supplier; final int size; final ReferenceQueue queue = new ReferenceQueue(); @@ -490,7 +492,7 @@ public int size() { return size; } - private static final class ArrayReference extends WeakReference { + private static final class ArrayReference extends WeakReference { final int index; ArrayReference(L referent, int index, ReferenceQueue queue) { @@ -506,7 +508,7 @@ private static final class ArrayReference extends WeakReference { * user key's (smeared) hashCode(). The stripes are lazily initialized and are weakly referenced. */ @VisibleForTesting - static class LargeLazyStriped extends PowerOfTwoStriped { + static class LargeLazyStriped extends PowerOfTwoStriped { final ConcurrentMap locks; final Supplier supplier; final int size; diff --git a/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java b/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java index f09ed4e71721..ffabc1d34c5d 100644 --- a/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java +++ b/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.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.errorprone.annotations.CanIgnoreReturnValue; @@ -25,6 +26,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A ThreadFactory builder, providing any combination of these features: @@ -46,11 +48,11 @@ @CanIgnoreReturnValue @GwtIncompatible public final class ThreadFactoryBuilder { - private String nameFormat = null; - private Boolean daemon = null; - private Integer priority = null; - private UncaughtExceptionHandler uncaughtExceptionHandler = null; - private ThreadFactory backingThreadFactory = null; + private @Nullable String nameFormat = null; + private @Nullable Boolean daemon = null; + private @Nullable Integer priority = null; + private @Nullable UncaughtExceptionHandler uncaughtExceptionHandler = null; + private @Nullable ThreadFactory backingThreadFactory = null; /** Creates a new {@link ThreadFactory} builder. */ public ThreadFactoryBuilder() {} @@ -162,7 +164,8 @@ private static ThreadFactory doBuild(ThreadFactoryBuilder builder) { public Thread newThread(Runnable runnable) { Thread thread = backingThreadFactory.newThread(runnable); if (nameFormat != null) { - thread.setName(format(nameFormat, count.getAndIncrement())); + // requireNonNull is safe because we create it if (and only if) we have a nameFormat. + thread.setName(format(nameFormat, requireNonNull(count).getAndIncrement())); } if (daemon != null) { thread.setDaemon(daemon); diff --git a/guava/src/com/google/common/util/concurrent/TimeLimiter.java b/guava/src/com/google/common/util/concurrent/TimeLimiter.java index 600c6cf58f5d..431f5dae6712 100644 --- a/guava/src/com/google/common/util/concurrent/TimeLimiter.java +++ b/guava/src/com/google/common/util/concurrent/TimeLimiter.java @@ -19,12 +19,13 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtIncompatible; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.DoNotMock; import java.time.Duration; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Imposes a time limit on method calls. @@ -34,7 +35,6 @@ * @since 1.0 */ @Beta -@DoNotMock("Use FakeTimeLimiter") @GwtIncompatible public interface TimeLimiter { @@ -80,7 +80,8 @@ public interface TimeLimiter { * annotation type, rather than an interface */ @SuppressWarnings("GoodTime") // should accept a java.time.Duration - T newProxy(T target, Class interfaceType, long timeoutDuration, TimeUnit timeoutUnit); + T newProxy( + T target, Class interfaceType, long timeoutDuration, TimeUnit timeoutUnit); /** * Returns an instance of {@code interfaceType} that delegates all method calls to the {@code @@ -121,7 +122,8 @@ public interface TimeLimiter { * annotation type, rather than an interface * @since 28.0 */ - default T newProxy(T target, Class interfaceType, Duration timeout) { + default T newProxy( + T target, Class interfaceType, Duration timeout) { return newProxy(target, interfaceType, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); } @@ -144,7 +146,8 @@ default T newProxy(T target, Class interfaceType, Duration timeout) { */ @SuppressWarnings("GoodTime") // should accept a java.time.Duration @CanIgnoreReturnValue - T callWithTimeout(Callable callable, long timeoutDuration, TimeUnit timeoutUnit) + T callWithTimeout( + Callable callable, long timeoutDuration, TimeUnit timeoutUnit) throws TimeoutException, InterruptedException, ExecutionException; /** @@ -213,8 +216,8 @@ T callUninterruptiblyWithTimeout( * @since 28.0 */ @CanIgnoreReturnValue - default T callUninterruptiblyWithTimeout(Callable callable, Duration timeout) - throws TimeoutException, ExecutionException { + default T callUninterruptiblyWithTimeout( + Callable callable, Duration timeout) throws TimeoutException, ExecutionException { return callUninterruptiblyWithTimeout( callable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); } diff --git a/guava/src/com/google/common/util/concurrent/TimeoutFuture.java b/guava/src/com/google/common/util/concurrent/TimeoutFuture.java index af30d1f0a445..ff8f6274af6d 100644 --- a/guava/src/com/google/common/util/concurrent/TimeoutFuture.java +++ b/guava/src/com/google/common/util/concurrent/TimeoutFuture.java @@ -152,7 +152,7 @@ public synchronized Throwable fillInStackTrace() { } @Override - protected String pendingToString() { + protected @Nullable String pendingToString() { ListenableFuture localInputFuture = delegateRef; ScheduledFuture localTimer = timer; if (localInputFuture != null) { diff --git a/guava/src/com/google/common/util/concurrent/TrustedListenableFutureTask.java b/guava/src/com/google/common/util/concurrent/TrustedListenableFutureTask.java index 3a607c5b615f..4cef255b7ba8 100644 --- a/guava/src/com/google/common/util/concurrent/TrustedListenableFutureTask.java +++ b/guava/src/com/google/common/util/concurrent/TrustedListenableFutureTask.java @@ -33,7 +33,8 @@ class TrustedListenableFutureTask extends FluentFuture.TrustedFuture implements RunnableFuture { - static TrustedListenableFutureTask create(AsyncCallable callable) { + static TrustedListenableFutureTask create( + AsyncCallable callable) { return new TrustedListenableFutureTask(callable); } @@ -50,7 +51,8 @@ static TrustedListenableFutureTask create(Callable callable) { * result, consider using constructions of the form: {@code ListenableFuture f = * ListenableFutureTask.create(runnable, null)} */ - static TrustedListenableFutureTask create(Runnable runnable, @Nullable V result) { + static TrustedListenableFutureTask create( + Runnable runnable, V result) { return new TrustedListenableFutureTask(Executors.callable(runnable, result)); } @@ -61,7 +63,7 @@ static TrustedListenableFutureTask create(Runnable runnable, @Nullable V *

    {@code volatile} is required for j2objc transpiling: * https://developers.google.com/j2objc/guides/j2objc-memory-model#atomicity */ - private volatile InterruptibleTask task; + private volatile @Nullable InterruptibleTask task; TrustedListenableFutureTask(Callable callable) { this.task = new TrustedFutureInterruptibleTask(callable); @@ -99,7 +101,7 @@ protected void afterDone() { } @Override - protected String pendingToString() { + protected @Nullable String pendingToString() { InterruptibleTask localTask = task; if (localTask != null) { return "task=[" + localTask + "]"; @@ -126,12 +128,13 @@ V runInterruptibly() throws Exception { } @Override - void afterRanInterruptibly(V result, Throwable error) { - if (error == null) { - TrustedListenableFutureTask.this.set(result); - } else { - setException(error); - } + void afterRanInterruptiblySuccess(V result) { + TrustedListenableFutureTask.this.set(result); + } + + @Override + void afterRanInterruptiblyFailure(Throwable error) { + setException(error); } @Override @@ -164,12 +167,13 @@ ListenableFuture runInterruptibly() throws Exception { } @Override - void afterRanInterruptibly(ListenableFuture result, Throwable error) { - if (error == null) { - setFuture(result); - } else { - setException(error); - } + void afterRanInterruptiblySuccess(ListenableFuture result) { + setFuture(result); + } + + @Override + void afterRanInterruptiblyFailure(Throwable error) { + setException(error); } @Override diff --git a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java index b95cd905bf81..4ea709ff632e 100644 --- a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java +++ b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java @@ -32,6 +32,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Condition; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Utilities for treating interruptible operations as uninterruptible. In all cases, if a thread is @@ -229,7 +231,8 @@ public static void joinUninterruptibly(Thread toJoin, long timeout, TimeUnit uni * @throws CancellationException if the computation was cancelled */ @CanIgnoreReturnValue - public static V getUninterruptibly(Future future) throws ExecutionException { + public static V getUninterruptibly(Future future) + throws ExecutionException { boolean interrupted = false; try { while (true) { @@ -268,8 +271,8 @@ public static V getUninterruptibly(Future future) throws ExecutionExcepti @CanIgnoreReturnValue @GwtIncompatible // java.time.Duration @Beta - public static V getUninterruptibly(Future future, Duration timeout) - throws ExecutionException, TimeoutException { + public static V getUninterruptibly( + Future future, Duration timeout) throws ExecutionException, TimeoutException { return getUninterruptibly(future, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); } @@ -294,8 +297,8 @@ public static V getUninterruptibly(Future future, Duration timeout) @CanIgnoreReturnValue @GwtIncompatible // TODO @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static V getUninterruptibly(Future future, long timeout, TimeUnit unit) - throws ExecutionException, TimeoutException { + public static V getUninterruptibly( + Future future, long timeout, TimeUnit unit) throws ExecutionException, TimeoutException { boolean interrupted = false; try { long remainingNanos = unit.toNanos(timeout); @@ -319,7 +322,7 @@ public static V getUninterruptibly(Future future, long timeout, TimeUnit /** Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly. */ @GwtIncompatible // concurrency - public static E takeUninterruptibly(BlockingQueue queue) { + public static E takeUninterruptibly(BlockingQueue queue) { boolean interrupted = false; try { while (true) { @@ -345,7 +348,8 @@ public static E takeUninterruptibly(BlockingQueue queue) { * being added to the given queue */ @GwtIncompatible // concurrency - public static void putUninterruptibly(BlockingQueue queue, E element) { + public static void putUninterruptibly( + BlockingQueue queue, E element) { boolean interrupted = false; try { while (true) { diff --git a/guava/src/com/google/common/util/concurrent/WrappingExecutorService.java b/guava/src/com/google/common/util/concurrent/WrappingExecutorService.java index 217e0a770fee..4cfb63a1b3d8 100644 --- a/guava/src/com/google/common/util/concurrent/WrappingExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/WrappingExecutorService.java @@ -29,6 +29,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An abstract {@code ExecutorService} that allows subclasses to {@linkplain #wrapTask(Callable) @@ -79,7 +80,8 @@ public void run() { * * @throws NullPointerException if any element of {@code tasks} is null */ - private ImmutableList> wrapTasks(Collection> tasks) { + private ImmutableList> wrapTasks( + Collection> tasks) { ImmutableList.Builder> builder = ImmutableList.builder(); for (Callable task : tasks) { builder.add(wrapTask(task)); @@ -109,8 +111,8 @@ public final Future submit(Runnable task, T result) { } @Override - public final List> invokeAll(Collection> tasks) - throws InterruptedException { + public final List> invokeAll( + Collection> tasks) throws InterruptedException { return delegate.invokeAll(wrapTasks(tasks)); } @@ -128,7 +130,8 @@ public final T invokeAny(Collection> tasks) } @Override - public final T invokeAny(Collection> tasks, long timeout, TimeUnit unit) + public final T invokeAny( + Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return delegate.invokeAny(wrapTasks(tasks), timeout, unit); } diff --git a/guava/src/com/google/common/util/concurrent/WrappingScheduledExecutorService.java b/guava/src/com/google/common/util/concurrent/WrappingScheduledExecutorService.java index 4ab700fde574..424f3625d512 100644 --- a/guava/src/com/google/common/util/concurrent/WrappingScheduledExecutorService.java +++ b/guava/src/com/google/common/util/concurrent/WrappingScheduledExecutorService.java @@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.Nullable; /** * An abstract {@code ScheduledExecutorService} that allows subclasses to {@linkplain @@ -41,12 +42,14 @@ protected WrappingScheduledExecutorService(ScheduledExecutorService delegate) { } @Override - public final ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + public final ScheduledFuture schedule( + Runnable command, long delay, TimeUnit unit) { return delegate.schedule(wrapTask(command), delay, unit); } @Override - public final ScheduledFuture schedule(Callable task, long delay, TimeUnit unit) { + public final ScheduledFuture schedule( + Callable task, long delay, TimeUnit unit) { return delegate.schedule(wrapTask(task), delay, unit); } diff --git a/guava/src/com/google/common/xml/XmlEscapers.java b/guava/src/com/google/common/xml/XmlEscapers.java index b25fcfc187a1..a477217740da 100644 --- a/guava/src/com/google/common/xml/XmlEscapers.java +++ b/guava/src/com/google/common/xml/XmlEscapers.java @@ -30,7 +30,6 @@ * non-ASCII characters to their numeric entity replacements. These XML escapers provide the minimal * level of escaping to ensure that the output can be safely included in a Unicode XML document. * - * *

    For details on the behavior of the escapers in this class, see sections 2.2 and 2.4 of the XML specification. diff --git a/guava/src/com/google/common/xml/package-info.java b/guava/src/com/google/common/xml/package-info.java index bd4c952162f3..a2a720999254 100644 --- a/guava/src/com/google/common/xml/package-info.java +++ b/guava/src/com/google/common/xml/package-info.java @@ -13,9 +13,7 @@ */ /** - * Escapers - * for - * XML. + * Escapers for XML. * *

    This package is a part of the open-source Guava * library. diff --git a/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java b/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java index 4804669099d4..780f0ebcb1d2 100644 --- a/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java +++ b/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java @@ -23,15 +23,14 @@ import com.google.common.collect.ImmutableMap; /** - * Do not use this class directly. For access to public-suffix information, - * use {@link com.google.common.net.InternetDomainName}. + * Do not use this class directly. For access to public-suffix information, use {@link + * com.google.common.net.InternetDomainName}. * - * A generated static class containing public members which provide domain - * name patterns used in determining whether a given domain name is an - * effective top-level domain (public suffix). + *

    A generated static class containing public members which provide domain name patterns used in + * determining whether a given domain name is an effective top-level domain (public suffix). * - *

    Because this class is used in GWT, the data members are stored in - * a space-efficient manner. {@see TrieParser}. + *

    Because this class is used in GWT, the data members are stored in a space-efficient manner. + * {@see TrieParser}. * * @since 16.0 */ @@ -42,22 +41,23 @@ private PublicSuffixPatterns() {} /** If a hostname is contained as a key in this map, it is a public suffix. */ public static final ImmutableMap EXACT = - TrieParser.parseTrie("a&0&0trk9--nx?27qjf--nx?e9ebgn--nx?nbb0c7abgm--nx??1&2oa08--nx?apg6qpcbgm--nx?hbbgm--nx?rdceqa08--nx??2&8ugbgm--nx?eyh3la2ckx--nx?qbd9--nx??3&2wqq1--nx?60a0y8--nx??4x1d77xrck--nx?6&1f4a3abgm--nx?2yqyn--nx?3np8lv81qo3--nx?5b06t--nx?axq--nx?ec7q--nx?lbgw--nx??883xnn--nx?9d2c24--nx?a&a?it??b!.&gro?lim?moc?t&en?opsgolb,?ude?vog??abila?c?ihsot?m?n??c!.&b&a?m?n??c&b?g?q??ep?fn?k&s?y??ln?no?oc,pi-on,sn?t&n?opsgolb,?un?ysrab,?i&ma?r&emarp?fa??sroc??naiva?s??d&ats?n&eit?oh??om?sa?tl??eg?f&c?ob??g!emo?naripi?oy??hskihs?i&cnal?dem?hs?k!on??sa!.snduolc,??jnin?k&aso?dov?ede?usto??l!.&c,gro?m&oc?yn,?ofni?r&ep?nb,?t&en?ni??ude?vog??irgnahs?le&nisiuc?rbmuder???m!.&ca?gro?oc?sserp?ten?vog??ahokoy?e00sf7vqn--nx?m??n!.&ac?cc?eman?gro?ibom?loohcs?moc?ni?o&c?fni?rp??r&d?o??s&u?w??vt?xm??av?is?olecrab?tea??p!.&bog?ca?d&em?ls??g&ni?ro??mo&c?n??oba?ten?ude??c?g7hyabgm--nx?ra!.&461e?6pi?iru?nru?rdda-ni?siri???s??q!.&eman?gro?hcs?lim?mo&c?n,?t&en?opsgolb,?ude?vog???r&az?emac?f4a3abgm--nx?n!d5uhf8le58r4w--nx??u&kas?tan???s!.&bup?dem?gro?hcs?moc?ten?ude?vog??ac!.uban.iu,?iv??t&ad?elhta?led?oyot??u!.&a&cinniv?emirc?i&hzhziropaz?stynniv??s&edo?sedo??tlay?vatlop??bs?c&c,inimod??d&argovorik?o!roghzu??tl,?e&hzhziropaz?nvir?t??f&i?ni,?g&l?ro??hk?i&stvinrehc?ykstynlemhk??k&c?m?s&nagul?t&enod?ul??v&iknarf-onavi?orteporp&end?ind?????l&iponret?opotsa&bes?ves??p??m&k?oc?s?yrk??n&c?d?i?osrehk?v?ylov??o&c,nvor??p&d?p,z??r&c?imotihz?k?ymotyhz??sk?t&en?l?z??ude?v:c?e&alokin?ik??i&alokym?hinrehc?krahk?vl?yk??k?l?o&g!inrehc??krahk??r?,y&ikstinlemhk?mus?s&akrehc?sakrehc?tvonrehc???z&ib,u????v!aj?bb?et?iv??waniko?x&a?iacal??yogan?z&.&bew?c&a?i&n?rga???gro?l&im?oohcs??m&on?t??o&c!.topsgolb,?gn??radnorg?sin?t&en?la??ude?vog?wal??zip???b&00ave5a9iabgm--nx?1&25qhx--nx?68quv--nx?e2kc1--nx??2xtbgm--nx?3&b2kcc--nx?jca1d--nx??4&6&1rfz--nx?qif--nx??96rzc--nx??7w9u16qlj--nx?88uvor--nx?a&0dc4xbgm--nx?c?her?n?ra?t??b!.&erots?gro?moc?o&c?fni??ten?ude?v&og?t??zib??a??c&j?s??d&hesa08--nx?mi??ec?g?l!.&gro?moc?ten?ude?vog??m??s!.&gro?moc?ten?ude?vog???tc-retarebsnegmrev--nx?u&lc!.&snduolc,y&nop,srab,??smas??p!.ysrab,??wp-gnutarebsnegmrev--nx??c&1&1q54--nx?hbgw--nx??2e9c2czf--nx?4&4ub1km--nx?a1e--nx?byj9q--nx?erd5a9b1kcb--nx??779tbp--nx?8&4xx2g--nx?c9jrb2h--nx??9jr&b&2h--nx?54--nx?9s--nx??c&eg--nx?h3--nx?s2--nx???a!.&gro?lim?moc?ten?ude?vog??3a09--nx!.&ca1o--nx?gva1c--nx?h&ca1o--nx?za09--nx??ta1d--nx?ua08--nx???da??b&a?b?ci?f76a0c7ylqbgm--nx?sh??c!.&eugaelysatnaf,gnipparcs,liamwt,revres-emag,s&nduolc,otohpym,seccaptf,??0atf7b45--nx?a1l--nx??e!.&21k?bog?dem?gro?lim?m&oc?yn,?nif?o&fni?rp??ten?ude?vog??beuq?n?smoc?tnamys??fdh?i&l&buperananab?ohtac??n&agro?ilc?osanap??tic??l!.&gro?m&oc?yn,?oc?ten?ude?vog?yo,?l??m!.&mt?ossa??p1akcq--nx??n!.&mon?ossa??i?p??relcel?s!.&gro?moc?ten?ude?vog??c??t!s?w??v!.&e0,gro?lim?mo&c?n,?ten?ude?v&g:.d,,og???q??wp?yn??d&2urzc--nx?3&1wrpk--nx?c&4b11--nx?9jrcpf--nx???5xq55--nx?697uto--nx?75yrpk--nx?9ctdvkce--nx?a!.mon?d?er?olnwod??b2babgm--nx?c!.vog?g9a2g2b0ae0chclc--nx??e&m!bulc??r!k??sopxe?timil?w??fc?g!.mon,?h&d3tbgm--nx?p?t??i!.&ased?bew?ca?hcs?lim?o&c!.topsgolb,?g??ro?sepnop?ten?ym?zib??ar?b?ordna?p?rdam??l&iub?og?row??m!.topsgolb,?n&a&b?l!.citats:.&setis,ved,?,lohwen?raas???ob?uf??o&of?rp??r&a&c&tiderc?yalcrab??ugnav??ef506w4b--nx?k!.&oc,ude,?jh3a1habgm--nx??of??s!.&dem?gro?moc?ofni?ten?ude?v&og?t???m!kcrem???t!.topsgolb,excwkcc--nx?l??uolc!.&atcepsrep,drayknil,nworu,r&epolroov,opav,?xelpciffart,??za5cbgn--nx??e&1&53wlf--nx?7a1hbbgm--nx?ta3kg--nx??2a6a1b6b1i--nx?3ma0e1cvr--nx?418txh--nx?707b0e3--nx?a!.&ca?gro?hcs?lim?mon,oc?t&en?opsgolb,?vog??09--nx??b!.&ca?gnitsohbew,topsgolb,?ortal?ut!uoy???c&a&lp!.oc,?ps!.&lla4sx,rebu,slootiknil,tsafym,?artxe??sla??i!ffo??n&a&d?iler?nif?rus&e?ni!efil?srelevart????eics!.oby,??rofria??d!.&1sndnyd,42pi-nyd,7erauqs,amil4,brb-ni,decalpb,e&daregtmueart,mohsnd,nihcamyek,?hcierebsnoissuksid,keegnietsi,lsd-ni,moc,n&-i-g-o-l,aw-ym,esgnutiel,i&emtsi,lreb-n&i,yd,??oitatsksid-ygolonys,pv&-n&i,yd,?nyd,??orp-ytinummoc,p&h21,iog:ol,,?r&e&ntrapdeeps.remotsuc,su&-lautriv,lautriv,?t&adpusnd,tub-ni,uor-ym,?vres&-e&bucl,mohym,?bew-emoh:.nyd,,luhcs,??ogiv-&niem,ym,??s&d-&onys,ygolonys,?nd&-&dd,nufiat,sehcsimanyd,tenretni,yard,?isoc.nyd,ps,yard,?oper-&nvs,tig,?sndd:.&nyd,sndnyd,?,?topsgolb,vresi-&niem,tset,?xi2,y&awetag-&llawerif,ym,?srab,tic-amil,?zten&mitbel,sadtretteuf,??a&lg?rt!.oby,??i&s&doow?ruoyno??ug?wnoitan??nil?on--nx??e!.&bil?dem?eif?gro?irp?kiir?moc!.topsgolb,?pia?ude?vog??ei?ffoc?gg?r&f?ged???f&a&c?s??il!tem???g!.&gro?lim?mo&c?n,?t&en?vp??ude?vog??a&f?gtrom?p!.ycvrp,?rots?yov??elloc?na&hcxe?ro??roeg?ug??i!.&myn,topsgolb,vog??tilop?v&bba?om???j!.&gro?oc?ten???k!.&c&a?s??e&m?n??ibom?mon,o&c!.topsgolb,?fni?g??ro??i&b?l?n???l&a&dmrif?s!.rof,rof???b&a?i&b?dua???c&aro?ric??dnik?g!oog??i&bom?ms??l&asal?erauqa??ppa?uhcs?yts!efil???m!.&4&32i,pct,?66c,ailisarb,b&dnevar,g-raegelif,?ca?duolcsd,e&d-raegelif,i&-raegelif,lpad:.tsohlacol,,??g&ro?s-raegelif,?hctilg,k&catsegde,uoc,?myn,noitatsksid,o&bmoy,c!ku,?t&nigol,poh,??p&ion,j-raegelif,ohbew,?r&aegelif,ofsnd,?s&dym,ndd,ti??t&en?s&acdnuos,ohon,??u&a-raegelif,de?tcn,?v&irp?og??y&golonys,olpedew,srab,??a&g?n!.&reh.togrof,sih.togrof,???em?i&rp?twohs??o&htathgir?rhc??w??n!goloc?i&lno!.ysrab,?w??o!.&derno:.gnigats,,knilemoh,rof,?hp?latipac?ts&der?e&gdirb?rif???z!.&66duolc,amil,sh,???ruoblem??om?p!.&bog?gro?lim?m&o&c?n??yn,?t&en?opsgolb,?ude??irg?yks??r!.&mo&c?n??ossa?topsgolb,?a&c!htlaeh??pmoc?wtfos??bc?eh?if?ots?taeht?u&ces?sni?t&inruf?necca??za???s!.&a?b!ibnal?rofmok??c!a??d!b?n&arb?ubroflanummok???e?f!noc,?g!ro??h!f??i!trap??k!shf??l?m!oc,t??n!mygskurbrutan??o?p!p??r?s!serp??t!opsgolb,?u?vhf?w?x!uvmok??y?z??a&c?el?hc??i&er?urc??nesemoh?roh?uoh??t&a&d?ts&e!laer??lla???is!.&areduolc,enilnigol,n&eyb,oyc,?spvtsaf,xulel,ysrab,?bew??ov?ra?t&ioled?ol??utitsni??u&lb?qi&nilc?tuob???v!.&21e?b&ew?og??ce&r?t??erots?gro?lim?m&oc?rif??o&c?fni??stra?t&en?ni??ude?vog??as?e3gerb2h--nx?i&l?rd?ssergorp??ol??w&kct--nx?r??xul??f&0f3rkcg--nx?198xim--nx?280xim--nx?617upk--nx?7vqn--nx?a!.&gro?mo&c?n,?ten?ude?vog???b!.vog?wa9bgm--nx??c!.topsgolb,a1p--nx?ns??ea1j--nx?fo?g?iam?l&a1d--nx?og??n!.&bew?cer?erots?m&oc?rif??ofni?re&hto?p??stra?ten???orp?p!.&gro?moc?ude???rus?t!w??vd7ckaabgm--nx?w??g&2&4wq55--nx?8zrf6--nx??3&44sd3--nx?91w6j--nx!.&a5wqmg--nx?d&22svcw--nx?5xq55--nx??gla0do--nx?m1qtxm--nx?vta0cu--nx????455ses--nx?5mzt5--nx?69vqhr--nx?7&8a4d5a4prebgm--nx?rb2c--nx??a!.&gro?mo&c?n??oc?ten??vd??b!.&0?1?2?3?4?5?6?7?8?9?a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t!opsgolb,?u?v?w?x?y!srab,?z???c!b?za9a0cbgm--nx??e!.&eman?gro?ics?lim?moc!.topsgolb,?nue?ten?ude?vog??a??g!.&ayc,gro?lenap:.nomead,,oc?saak,ten???i&a?v??k!.&gro?lim?moc?ten?ude?vog???m!.&drp?gro?lim?m&o&c?n??t??oc?ude?vog??pk??n!.&dtl,eman?gro?hcs?i!bom??l&im?oc,?m&oc!.topsgolb,?rif,?neg,ogn,ten?ude?vog??aw?i!b!mulp??car?d&art?dew??h&sif?tolc??k&iv?oo&b?c???ls?n&aelc?iart??p!pohs??re&enigne?tac??t&ad?ekram?hgil?lusnoc?neg?ov?soh!.tfarcnepo,?tebdaerps??vi&g?l???o!s??u&rehcisrev?smas?tarebsnegömrev???o&d?lb?og!.duolc,??r&2n084qlj--nx?ebmoolb?o!.&77ndc.c:sr,,a&remacytirucesym,t&neimip,sivretla,?z,?d&ab-yrev-si,e&sufnocsim,vas-si,?nuof-si,oog-yrev-si,uolc&arfniarodef,mw,??e&a,cin-yrev-si,grof&loot,peh,?l&as-4-ffuts,poeparodef,?m&-morf,agevres,ohruoyslles,?n&ozdop,uma.elet,?r&ehwongniogyldlob,iwym,uces-77ndc.nigiro.lss,?t&adidnac-a-si,is&-ybboh,golb,???fehc-a-si,golbymdaer,k&eeg-a&-si,si,?h,nut,?l&i&amwt,ve-yrev-si,?lawerif&-ym,ym,?sd-ni,?m&acssecca,edom-elbac,?n&af&blm,cfu,egelloc,lfn,s&citlec-a-si,niurb-a-si,tap-a-si,?xos-a-si,?o&itatsksid,rviop,?pv-ni,?o&jodsnd,tp&az,oh,??p&i&-on,fles,?o&hbew,tksedeerf,?tf&e&moh,vres,?ym,??r&e&gatop,ppepteews,su-xunil-a-si,?gmtrec,vdmac,?s&a&ila&nyd,snd,?nymsd,?b&alfmw,bevres,?dylimaf,eirfotatophcuoc,gulku,j,koob-daer,ltbup,nd&-won,deerf,emoh,golb,kcud,mood,nyd:.&emoh,og,?,ps,rvd,tog,uolc,?s&a-skcik,ndd,?tnemhcattaomb,u,?t&ce&jorparodef.&duolc,gts.so.ppa,so.ppa,?riderbew,?e&ews-yrev-si,nretni&ehtfodne,fodne,??hgink-a-si,igude,oi-allizom,s&ixetn&od,seod,?o&h-emag,l-si,?rifyam,??ue:.&a&-q,c,?cm,dc,e&b,d,e,i,m,s,?g&b,n,?hc,i&f,s,?k&d,m,s,u,?l&a,i,n,p,?n&c,i,?o&n,r,ssa,?pj,r&f,g,h,k,t,?s&e,i:rap,,u,?t&a,en,i,l,m,ni,p,?u&a,de,h,l,r,?vl,y&c,m,?z&c,n,??,vresnyd,x&inuemoh,unilemoh,?y&limafxut,srab,???ub&mah?oj???s!.&gro?moc?rep?t&en?opsgolb,?ude?vog??gb639j43us5--nx??t?u!.&c&a?s??en?gro?mo&c?n,?o&c?g??ro?topsgolb,??v!.mon,a1c--nx??wsa08--nx??h&0ee5a3ld2ckx--nx?4wc3o--nx!.&a&2xyc3o--nx?3j0hc3m--nx?ve4b3c0oc21--nx??id1kzuc3h--nx?l8bxi8ifc21--nx?rb0ef1c21--nx???8&8yvfe--nx?a7maabgm--nx??b!.&gro?moc?ten?ude?vog??mg??c!.&7erauqs,amil4,duolc-drayknil,gniksnd,ph21,sndtog,topsgolb,xi2,ytic-amil,?aoc?et?ir!euz??r&aes!errecnac??uhc??sob?taw!s???d0sbgp--nx?f&2lpbgm--nx?k??g!.&gro?lim?moc?ude?vog???iesac?m!a1j--nx??ocir?p!.&gro?i?lim?moc?ogn?ten?ude?vog???s!.&g&nabhsah,ro??lim?moc?ten?vog?won,yolpedew,?a&c?nom??i&d?f?ri???t!.&ca?enilno,im?ni?o&c?g??pohs,ro?ten??iaf!.oby,?laeh?orxer?ra&ba?e???vo!.lopdren,?zb??i&3tupk--nx?7a0oi--nx?a!.&ffo?gro?mo&c?n,?ten?uwu,?1p--nx?bud?dnuyh?tnihc??b!.&gro?moc?oc?ro?ude??ahduba?o!m!.&duolcsd,ysrab,???s??c!.&ayb-tropora--nx?ca?d&e?m??esserp?gro?moc?nif,o&c?g?ssa??ro?t&en?ni?roporéa??ude?vuog??cug?t??d&dk?ua??e&bhf--nx?piat??f!.&aw5-nenikkh--nx,dnala?iki,nenikkäh,topsgolb,yd,?onas??g!.&d&om?tl??gro?moc?ude?vog???h&c&atih?ra??s&abodoy?ibustim???juohs?k!.&gro?moc?ofni?ten?ude?vog?zib??b4gc--nx?iw?nisleh?s?uzus??l!.&aac,m&on,yn,?topsgolb,?drahcir?iamsi??maim?n!.&b&ew?og??ca?gro?lim?mo&c?n??ni?o&c?fni??pp?t&en?ni??ude?zib??airpic?i&hgrobmal?m??re??om?rarref?s!.&mon,topsgolb,?ed??t&aresam?i&c?nifni??rahb?tagub??ut?v!.&21k?gro?moc?oc?ten???wik?xa&rp?t??yf??j&6pqgza9iabgm--nx?8da1tabbgl--nx?b!.&ossa?topsgolb,uaerrab?vuog???d?f!.&ca?eman?gro?lim?moc?o&fni?rp??ten?vog?zib???nj?s?t!.&bew?c&a?in??eman?gro?lim?mo&c?n,?o&c?g??t&en?ni?set??ude?vog?zib???yqx94qit--nx??k&8uxp3--nx?924tcf--nx?arfel?c&a&bdeef?lb??ebdnul?ilc?reme?ud??d!.&erots,ger,mrif,oc,topsgolb,zib,?t??e&es?samet??h!.&a&4ya0cu--nx?5wqmg--nx??b3qa0do--nx?cni,d&2&2svcw--nx?3rvcl--nx??5xq55--nx?tl,?g&a0nt--nx?la0do--nx?ro??i&050qmg--nx?7a0oi--nx?xa0km--nx??m&1qtxm--nx?oc?yn,?npqic--nx?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??xva0fz--nx?人&个?個?箇??司公?府政?絡&網?网??織&組?组??织&組?组??络&網?网??育&敎?教???n??i&tsob?vdnas??l!.&bew?c&a?os??dtl?gro?hcs?letoh?moc?nssa?ogn?prg?t&en?ni??ude?vog??at?cd?is??m!.&eman?fni?gro?mo&c?n,?t&en?opsgolb,?ude?vog???n&ab!cfdh?etats?mmoc?t&en?fos??u??i!.gn,l!.&noyc,pepym,??p???oob?p!.&b&ew?og??gro?kog?m&af?oc??nog?ofni?pog?sog?ten?ude?vog?zib???row!.&fo,ot,?ten!.&htumiza,o&c,vra,??doof???s!.&myn,topsgolb,??t?u!.&c&a?lp??d&om?tl??e&cilop?m??gro!.&gul:g,,sgul,??nnoc,o&c!.&e&lddiwg,n&ilnoysrab,ozgniebllew,??krametyb.&hd,mv,?pi-on,topsgolb,vres-hn,ysrab,??rpoc,?shn?ten?vog!.eci&ffoemoh,vres,??ysrab,???l&04sr4w--nx?a!.&gro?lim?mo&c?n,?t&en?opsgolb,?ude?vog??bolg?c?ed?g!el??i&c&nanif!.oc,lpl??os??romem?tnedurp??n&if?oitanretni??t&i&gid!.sppaduolc:.nodnol,,?p&ac?soh???ned?ot??utum!nretsewhtron???c!.&bog?lim?mon,oc?samednerpa?topsgolb,vog???dil?e&datic?n&ahc?nahc!gnikooc?levart?rehtaew???t!ni?ria?tam??vart??f&8f&pbgo--nx?tbgm--nx??a?n??g!.&gro?mo&c?n,?oc?ten?ude?zib,??h&d?op??i!.&21k?ca?fdi?gro?inum?oc!.topsgolb,?ten?vog??a&f?m&e?g?toh???m?r?xil??l&a&b&esab?t&eksab?oof!.fo,???c?mt??e&d?hs??ihmailliw?j??m!.&esserp?gro?moc?ten?ude?v&og?uog????n!.&n&iemodleeutriv,o&med,rtsic,??oc,retsulc-gnitsoh,topsgolb,wsma,yalphk,?o??o&a?btuf?l?o&c!.ed,?hcs!.gn,??rit?u??p!.&a&cin&diws?gel??d&g,ortso?urawon??i&dem?mraw?nydg,?k&elo&guld?rtso??slopolam?tsu?ytsyrut??l&ip?o&kzs?w&-awolats?oksnok????n&img?zcel,?rog&-ai&bab?nelej??j?z??syn?tsaim?w&a&l&eib?i?o??zsraw??o&namil?tainop,??z&eiwolaib?mol???c&e&iw&alselob?o&nsos?rtso???le&im?zrogz???orw,p??d&em,ia?ragrats??e&c&i&lrog?w&ilg,o&hc&arats?orp??klop?tak????yzreibok??i&csjuoniws?ksromop?saldop??l&ahdop?opo??napokaz,tatselaer?z&romop?swozam???g&alble?ezrbo&lok?nrat??ro??hcyzrblaw?i&csomohcurein?grat?klawus??k&e&rut?walcolw??in&byr?diws,sark,?le?o&nas?tsylaib??rob&el?lam??s&als?jazel?nadg,puls?rowezrp???l&colw?e&r?vart??i&am?m???m&o&c?dar?n?tyb??s&g?iruot??t!a???n&a&gaz?nzop,?i&bul?cezczs?lbul,molow?nok?zd&eb?obeiws???uleiw?y&tzslo?z&rtek?seic????o&c,fni?k&celo?zdolk??lkan?n&leim?pek?t&uk?yzczs??z&copo?eing?rowaj???rga?tua?w&ejarg?ogarm???p&e&eb,lks??klwwortso?ohs??romophcaz?sos?t&aiwop?en?opos,ra,sezc??ude?v&irp?og!.&a&p?s!w???bni&p?w??ci?dtiw?essp?fiw?g&imu?u??hiiw?m&igu?rio?u!o???nds?o&ks?p!pu??s?wtsorats??p&a?sp!mk?pk?wk??u&m?p??wk?z??r&ksw?s??s&i?oiw?u?zu??talusnok?w&gzr?i&p?rg?w??m?opu?u!imzw???zouw????w&a&l&corw?sizdow??w??o&golg?k&ark,ul?zsurp??r&az?gew??t&rabul,sugua??z&coks?sezr????xes?y&buzsak?d&azczseib?ikseb??hcyt?n&jes?lod-zreimizak??pal?r&ogt?uzam??walup?zutrak??z&am-awar?c&aprak?iwol?zsogdyb??dalezc?ib?s&i&lak?p??uklo????l??r&as?f?s??s!.&gro?moc?ten?ude?vog???t!.vog??ubnatsi?x3b689qq6--nx?yc5rb54--nx??m&00tsb3--nx?1qtxm--nx?981rvj--nx?a!.&enummoc?gro?moc?oc?t&en?opsgolb,??c!bew??dretsma?e&rts?t!.esruocsid,??fma?rirhs?xq--nx??b!.&gro?moc?ten?ude?vog??i??c!.&moc?oc?ten?vog???d!.&gro?moc?ten?ude?vog???f!i??g!vu96d8syzf--nx??h?i!.&ca?gro?mo&c?n,?o&c!.&clp?dtl???r,?t&en?t??vt??k?rbg4--nx??k!.&drp?e&rianiretev?sserp??gro?lim?m&o&c?n??t??nicedem?ossa?pooc?s&eriaton?neicamrahp?sa??ude?v&og?uog????l&if?ohkcots??o!.&dem?gro?m&oc?uesum??o&c?rp??ten?ude?vog??b?c!.&2aq,3pmevres,a&c&-morf,ir&bafno,fa,??g&-morf,oy-sehcaet,?i-morf,m&-morf,all&-a-si,amai,??p&-morf,c-a-si,?remacytirucesym,s,tadtsudgniht,v-morf,w-morf,z,?b&dnevarym,ew&-sndnyd,ottad,?g,ildts.ipa,?c&amytirucesemoh,d-morf,esyrcs,n&-morf,vym,?p&kroweht,ytirucesemoh,?q,rievres,s-morf,?d&aerotffuts,e&calpb,ifitrec-&si,ton-si,?llortnocduolc,?i-morf,m-morf,n&-morf,abeht-htiw-si,?s-morf,uolc&-noitatsyalp,hr,meaeboda,panqym:-&ahpla,ved,?,smetsystuo,ved&j,pw,??wetomer,?e&butuoyhtiw,ciffo-sndnyd,d:-morf,o&celgoog,n&il.&recnalabedon,srebmem,?neve.&1-&su,ue,?2-&su,ue,?3-&su,ue,?4-&su,ue,????,erf&-sndnyd,sndd,?filflahevres,gnahcxeevres,i&hcet-a-si,p-sekil,?k&auqevres,irtsretnuocevres,?l&bitpa-no,googhtiw,?m&agevres,ina-otni-si,oh-&sndnyd,ta-sndnyd,??n&-morf,ilnoysrab,og-si,?r&alfduolcyrt,ihcec,uzanoppanex,?srun-a-si,t&i&nuarepo,s&-ybboh,aloy,tipohs,??omer-sndnyd,ysgolb,?v&als-elcibuc-a-si,i&lsndd,tavresnoc-a-si,??z&amkcar,eelg,iig,??fehc-a-si,g&ni&gats-swennwot,ksndd,robsikrow,?o&fgp,lb&-sndnyd,sihtsetirw,???h&n-morf,o-morf,?i&fiwehtno,h-morf,kiw-sndnyd,m-morf,r-morf,w-morf,z&ihcppa,nilppa,??jn-morf,k&a&-morf,erfocsic,?cils-si,eeg&-a&-si,si,?sndd,?h,latsnaebcitsale:.&1-&htuos-pa,lartnec-&ac,ue,?ts&ae&-&as,su,?ht&ron-pa,uos-pa,??ew-&su,ue,vog-su,???2-ts&ae&-su,ht&ron-pa,uos-pa,??ew-&su,ue,??3-ts&aehtron-pa,ew-ue,??,o-morf,r&adhtiwtliub,ow&-&sndnyd,ta-sndnyd,?ten-orehkcats,??u,?l&a&-morf,colottad,rebil-a-si,?f-morf,i&-morf,am-sndnyd,?l&ecelffaw,uf-ytnuob:.a&hpla,teb,?,?ppmswa,ru-&elpmis,taen,?ssukoreh,?m&n-morf,pml.ppa,rofererac-htlaeh,sacrasevres,uirarret-yltsaf,?n&a&cilbuper-a-si,f&-sllub-a-si,racsan-a-si,?i&cisum-a-si,ratrebil-a-si,??c,eerg-a-si,i-morf,m-morf,o&ehtnaptog,isam-al-a-tse,ollabtib,rtap-el-tse,s&iam-al-a-tse,replausunu,??pj,t-morf,?o&bordym,c,jodsnd,m-morf,n:iloxip,,ttadym,?p&2pevres,aelutym,i&-sndnyd,fles,ogol,ruoy&esol,hctid,?ymteg,?pa&-rettalp,anis:piv,,esaberif,k1,lortnocduolc,oifilauq,r&aegyks,oetem:.ue,,?tnorfegap,ukoreh,?t&fevres,thevres,??r&a:-morf,tskcor-a-si,,b,e&d&ivorpnwo,ner&.ppa,no,??e&bevres,nigne-na-si,?ggolb-a-si,h&caet-a-si,pargotohp-a-si,?krow-drah-a-si,n&gised-a-si,ia&rtlanosrep-a-si,tretne-na-si,??p&acsdnal-a-si,eekkoob-a-si,?retac-a-si,subq,tn&ecysrab,iap-a-si,uh-a-si,?vres&-s&ndnyd,pvtsaf,?inim,nmad,?y&alp-a-si,wal-a-si,?zilibomdeepsegap,?g,k,mgrp.nex,o&-morf,sivdalaicnanif-a-si,t&c&a-na-si,od-a-si,?susaym,??p-morf,u&as-o-nyd,eugolb-nom-tse,omuhevres,??s&a&ila&nyd,snd,?nymsd,?bbevres,ci&p&-sndnyd,evres,?tcatytiruces,?dylimaf,e&cived-anelab,itilitu3,lahw-eht-sevas,mag-otni-si,tyskciuq,?i&ht2tniop,paelgoog,?k&-morf,aerf-ten,colbpohsym,?m&-morf,cxolb,?n&d&-pmet,dyard,golb,mood,tog,?nyd,ootrac-otni-si,?o&-xobeerf,xobeerf,?ppatneg,r&ac-otni-si,etsohmaerd,?s&e&l-rof-slles,rtca-na-si,?ibodym,?u,wanozama.&1-&htuos-pa&-3s,.&3s,etisbew-3s,kcatslaud.3s,??la&nretxe-3s,rtnec-&ac&-3s,.&3s,etisbew-3s,kcatslaud.3s,??ue&-3s,.&3s,etisbew-3s,kcatslaud.3s,????ts&ae&-&as&-&3s,etisbew-3s,?.kcatslaud.3s,?su:-etisbew-3s,.kcatslaud.3s,,?ht&ron-pa&-&3s,etisbew-3s,?.kcatslaud.3s,?uos-pa&-&3s,etisbew-3s,?.kcatslaud.3s,???ew-&su-&3s,etisbew-3s,?ue&-&3s,etisbew-3s,?.kcatslaud.3s,?vog-su-&3s,spif-3s,????2-ts&ae&-su&-3s,.&3s,etisbew-3s,kcatslaud.3s,??ht&ron-pa&-3s,.&3s,etisbew-3s,kcatslaud.3s,??uos-pa&-&3s,etisbew-3s,?.kcatslaud.3s,???ew-&su-&3s,etisbew-3s,?ue&-3s,.&3s,etisbew-3s,kcatslaud.3s,????3&-tsew-ue&-3s,.&3s,etisbew-3s,kcatslaud.3s,??s,???t&arcomed-a-si,c-morf,eel&-si,rebu-si,?m-morf,n&atnuocca-na-si,e&duts-a-si,r-ot-ecaps,tnocresu&buhtig,elbavresbo.citats,pl,???ops&edoc,golb,ppa,?s&i&hcrana-&a-si,na-si,?laicos-a-si,pareht-a-si,tra-na-si,xetn&od,seod,??oh&piym,sfn,??u&-morf,nyekcoh-asi,?v-morf,?u&-rof-slles,4,e,h,oynahtretramssi,r:ug-a-si,,?v&n-morf,w-morf,?w&ozok,ww100,?x&bsbf.sppa,em,inuemoh,obaniateb,t-morf,unilemoh,?y&a&bnx:.&2u,lacol-2u,?,lerottad,wetag-llawerif,?dnacsekil,filten,k&-morf,niksisnd,?rotceridevitcaym,u:goo,,w-morf,x&alagkeeg,orphsilbup,???inu??m!.&dna,rof,??or?tsla??p!.nwo,?raf!.jrots,etats??s?t!.&gro?lim?mo&c?n??oc?ten?ude?vog???u&esum!.&a&92chg-seacinumocelet-e-soierroc--nx?atnav?c&i&aduj?rfatsae??rollam??d&anac?enomaledasac?irolf??e&raaihpledalihp?srednu??g&hannavas?oonattahc??hamo?i&auhsu?bmuloc!hsitirb??dem?groeg?hpledalihp?l&artsua?etalif??n&igriv?rofilac??ssur?tsonod??ksa&la?rben??l&lojal?q-snl--nx?uossim!trof???m&a&bala?nap??enic?o&m?r???n&a&cirema?idni??edasap?ilorachtuos?olecrab??r&abrabatnas?ezzivs??su?t&nalta?osennim??zalp??c&dnotgnihsaw?ebeuq?i&depolcycne?ficap?hpargonaeco?lbup?sum?t&carporihc?lec?naltadim??vu??yn??d&a&dhgab?etsmraf?m?orliar??i&rdam?ulegnedleeb??leif?n&a!l&gne?nif?ragyduj?t&ocs?rop??yram???u&brofsdgybmeh?osdnaegami???r&augria?ofxo???e&c&a&l&ap?phtrib??ps??n&a&lubma?tsiser??e&fedlatsaoc?gilletni?ics!foyrotsih????pein?rof??d&nukneklov?revasem??e&rt?tsurt??f&atnas?ildliw??g&a&lliv?tireh!lanoitan???dirbmac?rog??i&cnum?nollaw??koorbrehs?l&ab?bib?cycrotom?i&ssim?txet??oks?tsac??m&affollah?it!iram??utsoc??n&golos?ilno?recul??r&a&uqs?waled!foetats???i&hs&acnal?kroy?pmahwen??otsih??omitlab?ut&an?cetihcra?inruf?luc!irga?su???vuol??s&abatad?iacnarf?sius?uoh!lum???t&a&locohc?rak?ts!e!yrtnuoc!su?????imesoy?tevroc??u&qihpargonaeco?velleb??vit&caretni?omotua???f&iuj?ohgrub??g&n&i&dliub?ginerevmuesum?kiv?lahw?nim?peekemit?vil??ulmmastsnuk??orf?r&ebnrats?u&b&ierf?le?m&ah?uan??ram?s&mailliw!lainoloc??naitsirhc?retepts??zlas??ob&irf?mexul?????h&atu?c&raeser?sirotsih?uot??g&ea1h--nx?rubsttip??si&tirb?wej??t&laeh?ro&n?wtrof??uo&mnom?y????i&d6glbhbd9--nx?iawah?k&nisleh?s??lad!rodavlas??sissa?tannicnic??k&c&nivleeg?olc!-dna-hctaw?dnahctaw???fj?inebis?l&is?ofron??na&rfenna?t??oorbnarc?r&am&ned?reiets??oy!wen????l&a&ci&dem?golo&eahcra?meg?oz??natob?rotsih??ertnom?iromem?noita&cude?n??oc?rutluc?trop?utriv?van??e&nurb?s&ab?surb??utriv??i&artnogero?sarb??l&a&besab?hsnoegrus??e&hs?rdnevle??i&b?m!dniw????o&bup?ohcs?tsirb???m&a&dretsma?ets?h&netlehc?rud???ct?elas!urej??l&if?ohkcots?u??raf?silanruoj?u&esumyrotsihlarutan?ira&tenalp?uqa??terobra???n&a&c!irema!evitan???gihcim?i&dni?tpyge??mfoelsi?wehctaksas??e&d&alokohcs?ews?rag!cinatob?lacinatob?s&nerdlihc?u????gahnepoc?hcneum?laftsew?ppahcsnetewruutan?r&dlihc?ednaalv?hu!dnutamieh???sseig??gised!dn&atra?utsnuk???h&ab!nesie??ojts??i&lreb?tsua??l&eok?ocnil??n&ob?urbneohcs??o&dnol?gero?i&s&iv&dnadnuos?elet??nam??t&a&c&inummoc?ude!tra???dnuof?erc?i&cossa?va??kinummokelet?nissassa?r&belectsevrah?oproc?tsulli??silivic?t&nalp?s??vres&erp?noclatnemnorivne??zilivic??c&elloc?if-ecneics??ibihxe???ri?s&dnah?imaj?reffej?sral??t&erbepac?nilc?sob???r&e&b?dom?tsew?uab?zul??obredap??vahnebeok?wot??o&2a6v-seacinumoc--nx?ablib?c&edtra?ixemwen?sicnarfnas??elap?g&a&cihc?to??eidnas??i&cadnuf?diserp?ratno??llecitnom?mitiram?nirot?r&htna?ienajedoir???pohskrow?qari?r&aw!dloc?livic??dd?e&b&ma?yc??irrac?llimsiwel?naksiznarf?papswen?t&aeht?exe?nec!ecneics?larutluc?muesum?tra??s&ehc&nam?or??neum??upmoc???ia!nepo??obal?u&asonid?obal?takirak???s&a&l&g?l&ad?eh???xet??di&k?pardnarg??e&cneics!larutan??dnal?hcsi&deuj?rotsih!nizidem?rutan??selhcs??itinamuh?l&aw?egnasol?l&e&rutansecneics?xurb??iasrev???r&e&em?ugif??tsac??suohcirotsih?u&en?q&adac?itna!nacirema?su????õçacinumoc!elet-e-soierroc???gnirpsmlap?htab?i&lopanaidni?rap?uoltnias?xa??l&essurb?lod??mraeriflanoitan?n&a&blats?l??erdlihc?oi&snam?tacinummoc!elet-dna-stsop???äl??re&dnalf?lttes?mraf?nim?tnececneics??s&alg?erp??t&farc!dnastra??nalp?olip?ra!e&nif?vitaroced!su???su?xuaeb???u&b!muloc??cric???t&agilltrop?cejorp?dats?e&esum?kramnaidni??iorted?ne&m&elttes?norivne?piuqemraf??vnoc??oped?r&a!drib?enif?gttuts?hsiwej?kcor?n&acirema?ootrac??tamsa?yraropmetnoc??op&aes?snart?wen??ufknarf??s&a&cdaorb?octsae??ewhtuos?ilayol?nuk?r&ohnemled?uhlyram??urt???u&a&bgreb?etalpodaroloc??rmyc??w&ocsom?rn??x&esse?ineohp?nam?tas??y&a&bekaepasehc?w&etag?liar???camrahp?doc?e&hsub?l&ekreb?l&av!eniwydnarb??ort???n&dys?om??rrus?s&nreug?rejwen???golo&e&ahcra?g??motne?nh&cet?te??oz?po&rhtna?t??roh??hpargotohp?l&etalihp?imaf??m&edaca?onortsa??n&atob?yn??ps?r&a&ropmetnoc?tilim??e&diorbme?llag!tra??vocsid??lewej?nosameerf?otsih!dnaecneics?ecneics?gnivil!su??la&col?rutan??retupmoc?su??tsudnidnaecneics??spelipe?t&eicos!lacirotsih??i&nummoc?srevinu??nuoc???z&arg?iewhcs?nil?ojadab?urcatnas??моки?םילשורי???rof??z!.&ca?gro?hcs?lim?moc?o&c?fni??ten?ude?vog?zib????n&315rmi--nx?a&brud?cilbuper?f?grompj?hkaga?idraug?m?ol?ssin?u&hix?qna??varac?yalo??b!.&gro?moc?oc,ten?ude?vog??c??c!.&ah?bh?c&a?s??d&5xq55--nx?g?s?uolctnatsni,?eh?g&la0do--nx?ro??h&a?q?s??i&7a0oi--nx?h??j&b?f?t?x?z??kh?l&h?im?j??m&n?oc!.swanozama.&1-htron-nc.3s,be.1-&htron-nc,tsewhtron-nc,????n&h?l?s?y??om?qc?s&g?j??ten?ude?vog?wt?x&g?j?n?s??z&g?x??司公?絡網?络网??b??d&g!.ypnc,?ka??e&drag?erg?fuak?gawsklov?hctik?i&libommi?w??m!.rof,?po?r!ednaalv??sier?ves??g!.&ca?gro?moc?ten?ude?vog??is&ed!.ssb,?irev???h!.&bog?gro?lim?mo&c?n,?ten?ude???i!.&c&a?in??dni?gro?lim?mrif?neg?oc?s&er?nduolc,?t&en?opsgolb,?ude?vog?ysrab,?elknivlac?griv?ks?lreb?p!ul??v?w?x??k!.&gro?ten?ude?vog???l&eok?ocnil??m!.&cyn,gro?myn,ude?vog???o&dnol!.&fo,ni,??i&hsaf!.&fo,no,??n&o?utiderc??siv!orue??t&a&cude!.oc,?dnuof?tsyalp??c&etorp?u&a?rtsnoc?????kin?las?mrom?nac?p&q?uoc??s&iam?nhojcs?pe?scire??t&ron?sob??zama??p!.&gro?oc?ten?ude?vog??k??r&e&c?yab??op??s!.&gro?moc?osrep?t&opsgolb,ra??ude?v&inu?uog????t!.&dni?esnefed?gro?ltni?m&oc!nim??siruot??n&erut?if??o&fni?srep??sn&e?r??t&an?en!irga?ude??rnr??unr?vog??m??u&f?r!.&bdnevar,lper,sh,tnempoleved,??stad?xamay?y??v!.&ca?eman?gro?htlaeh?moc?o&fni?rp??t&en?ni?opsgolb,?ude?vog?zib???wo&rc?t!epac????o&76i4orfy--nx?a!.&bp?de?go?oc?ti?vg??boat??b!.&a&ci&sum?tilop??i&c&arcomed?neic??golo&ce?ncet??m&edaca?onoce??rt&ap?sudni??vilob??n&egidni?icidem??serpme?tsiver?vitarepooc??b&ew?og??dulas?e&rbmon?tr&a?op&ed?snart????g&olb?ro??ikiw?l&a&noi&canirulp?seforp??rutan??im??moc?o&fni?lbeup?rga?tneimivom??saiciton?t&askt?en?ni??ude?vt??h?iew?olg??c!.&bew?cer?dr&c,rac,?gro?ipym,l&im?per,?m&o&c!.topsgolb,?n??rif?udon,?ofni?s&egap&dael,l,?tra??t&4n,en?ni??ude?vog??a?e!vi??in?mara?s&edarb?ic???d!.&b&ew?og??dls?gro?lim?moc?t&en?ra??ude?vog??agoba?if?zd7acbgm--nx??e&c?d&iv?or??morafla??f!ni!.&e&g&delwonk-fo-l&errab,lerrab,?ellocevoli,?ht-skorg,rom-rof-ereh,tadpusn:d,,?llatiswonk,macrvd,ofni-v,p&i&-on,fles,?ohbew,?ruo-rof,s&iht-skorg,nd&-cimanyd,nyd,uolc,??tsrifyam,ysrab,zmurof,???g&el?ia?n!am?ib???hwsohw?i!.&35nyd,8302,a&minifed,tad-b,?b&altig,uhtig,?c&inone:.remotsuc,,zh,?d&in,u&olc&iaznab.ppa,noitacilppa,ropav,?rd,??e&civedniser,donppad.sndnyd,egipa,nilnigol,sufxob,t&isnoehtnap,newtu,??gnigatsniser.secived,k&orgn,ramytefasresworb,?m&oc?udon,?nyded,p&opilol,pa&-arusah,cs,enalpkcab,??r&evres&cisab,lautriv,?ial.sppa,?s&codehtdaer,nemeis-om,pparevelc,tacdnas,?t&enotorp,i&belet,detfihs,kecaps,?raedon.egats,sudgniht.&cersid.tsuc,dorp.tsuc,gnitset.tsuc,ved.tsuc,??vgib.0ku,xcq,y&olpedew,srab,??b?d&ar?u&a?ts???j?r?syhp??j!.&eman?gro?hcs?lim?moc?ten?ude?vog???ll&ag?o??m!.&gro?moc?ten?ude?vog??g?il?mi?orp??n!.&a&0&b-ekhgnark--nx?c-iehsrgev--nx?g-lksedlig--nx?k-negnanvk--nx??1&p-nedragy--nx?q-&asierrs--nx?grebsnt--nx?lado-rs--nx?n&egnidl--nx?orf-rs--nx??regnayh--nx?ssofenh--nx??r-datsgrt--nx?s-ladrjts--nx?v-y&senner--nx?vrejks--nx???3g-datsobegh--nx?4&5-&dnaleprj--nx?goksnerl--nx?tednalyh--nx??6-neladnjm--nx?s-&antouvachb--nx?impouvtalm--nx??y-&agrjnevvad--nx?ikhvlaraeb--nx???7k-antouvacchb--nx?8&k-rekie-erv--nx?l-ladrua-rs--nx?m-darehsdrk--nx??a!.sg??bct-eimeuvejsemn--nx?d&do?iisevvad?lov?narts?uas??f&1-&l--nx?s--nx??2-h--nx??g&10aq0-ineve--nx?av?ev?lot?r&ajn&evvad?u??ájn&evvad?u????h?iz-lf--nx?j&ddadab?sel??k&el?hoj&sarak?šárák??iiv&ag&na&el?g??ŋ&ael?ág???ran???l&f?lahrevo?o&ms?s??sennev?t-&ilm--nx?tom--nx??u&-edr--nx?s??øms??muar?n&0-tsr--nx?2-dob--nx?5-&asir--nx?tals--nx??a&r!-i-om?f?t??t??douvsatvid?kiv?m&os?øs??n&od?ød??ra?sen?t&aouvatheig?ouv&a&c&ch&ab?áb??h&ab?áb???n??i&ag?ág??sa&mo?ttvid??án???z-rey--nx?ær&f?t???o&p-&ladr--nx?sens--nx??q-nagv--nx?r-asns--nx?s-kjks--nx?v-murb--nx?w-&anr&f--nx?t--nx??ublk--nx???ppol?q&0-t&baol--nx?soum--nx?veib--nx??x-&ipphl--nx?r&embh--nx?imph--nx???y-tinks--nx??r&f-atsr--nx?g-&an&ms--nx?nd--nx??e&drf--nx?ngs--nx??murs--nx?netl--nx?olmb--nx?sorr--nx??h-&a&lms--nx?yrf--nx??emjt--nx??i&-&lboh--nx?rsir--nx?y&d&ar--nx?na--nx??ksa--nx?lem--nx?r&ul--nx?yd--nx????stu??j-&drav--nx?rolf--nx?sdav--nx??kua?l-&drojf--nx?lares--nx??m-tlohr--nx?n-esans--nx?olf?p-sdnil--nx?s-ladrl--nx?tih?v-rvsyt--nx??s&a&ns?ons??i&ar?er&dron?r&os?øs???ár??la&g?h??mor!t??sir?uf?åns??t&koulo&nka?ŋká??la?p-raddjb--nx?r-agrjnu--nx?s&aefr&ammah?ámmáh??orf?r&o?ø???u-vreiks--nx??u&h-dnusel--nx?i-&drojfk--nx?vleslm--nx??j-ekerom--nx?k-rekrem--nx?u-&dnalr--nx?goksr--nx?sensk--nx??v-nekyr--nx?w-&k&abrd--nx?ivjg--nx??oryso--nx??y-y&dnas--nx?mrak--nx?n&art--nx?nif--nx??reva--nx??z-smort--nx??v!.sg?ledatskork?reiks??wh-antouvn--nx?x&9-dlofts--nx.aoq-relv--nx?d-nmaherk--nx?f-dnalnks--nx?h-neltloh--nx?i-drgeppo--nx?j-gve&gnal--nx?lreb--nx??m-negnilr--nx?n-drojfvk--nx??y&7-ujdaehal--nx?8-antouvig--nx?b-&dlofrs--nx?goksmr--nx?kivryr--nx?retslj--nx??e-nejsom--nx?f-y&krajb--nx?re&dni--nx?tso--nx??stivk--nx??g-regark--nx?orf?ørf??z9-drojfstb--nx??b&25-akiivagael--nx?53ay7-olousech--nx?a&iy-gv--nx?le-tl&b--nx?s--nx??n0-ydr--nx??c&0-dnal-erdns--nx?z-netot-erts--nx??g&g-regnarav-rs--nx?o-nejssendnas--nx??ju-erdils-ertsy--nx?nj-dnalh-goksrua--nx?q&q-ladsmor-go-erm--nx.&ari-yreh--nx?ednas??s-neslahsladrjts--nx???ca&4s-atsaefrmmh--nx?8m-dnusynnrb--nx?il-tl--nx?le-slg--nx?n5-rdib--nx?op-drgl--nx?uw-ynnrb--nx??d&a&qx-tggrv--nx?reh!nnivk?sd&ork?ørk??uas??ts&e&bi?kkar?llyh?nnan??g&ort?ørt??k&alf?irderf??levev?mirg?obeg&ah?æh??r&ah?ejg????barm-jdddb--nx?ie!rah?s&etivk?ladman???lof&r&os?øs??ts&ev.ednas?o.relav?ø.relåv???n&a&l&-erd&n&os?øs??ron??adroh.so?dron.&a&g5-b--nx?ri-yreh--nx??ob?y&oreh?øreh??øb??e&m!lejh??pr&oj?øj??vi??gyb?n&aks?åks??o&h-goksrua?rf??r&o?ua?ø??tros?øh-goksrua??rts!e&devt?lab?mloh???s&ellil?naitsirk?rof???u&l!os??s!d&im?lejt??e&guah?l&a?å???kkoh?lavk?naitsirk?r&af?eg&e?ie???tef?y&onnorb?ønnørb?????r&a&blavs!.sg??g&eppo?la???o&j&f&a!dniv?k?vk??die?e&dnas?kkelf??llins?r&iel?ots??s&lab?t&ab?åb??yt??å!k??ævk??les??ts??åg&eppo?lå???ureksub.sen??e&ayb-yrettn--nx?d&ar?lom?r&of?øf??år??g&gyr?nats??i&meuv&ejsem&aan?åån??sekaal??rjea??j&d&ef?oks??les??k&er&aom?åom??hgna&ark?årk??iregnir?kot!s??s&ig?uaf???l&bmab?kyb?l&av?ehtats??oh??m&it?ojt?øjt??n&arg?g&os?øs??meh?reil?te?ummok?yrb??r&dils-erts&ev?y&o?ø???ua?vod??sa&ans?åns??t&robraa?spaav??urg??f&62ats-ugsrop--nx?a&10-ujvrekkhr--nx?7k-tajjrv-attm--nx??o!.sg?h??s!.sg??v!.sg???g&5aly-yr&n--nx?v--nx??a&llor?ve&gnal?lreb???n&av!snellu??org??oks&die?m&or?ør??ner&ol?øl??r&o?ø???r&eb!adnar?edyps?s&die?elf?gnok?n&ot?øt????obspras??uahatsla?åve&gnal?lreb???h&0alu-ysm--nx?7&4ay8-akiivagg--nx?5ay7-atkoulok--nx??a!.sg???i&e&hsr&agev?ågev??rf??k&h&avlaraeb?ávlaraeb??s??lm&a?å??mpouvtal&am?ám??pph&al?ál??rrounaddleid?ssaneve?ššáneve??j&0aoq-ysgv--nx?94bawh-akhojrk--nx??k&a&b&ord?ørd??jks?lleis??iv!aklejps?l&am?evs?u??mag?nel?ojg?r&a&l?n??epok?iel?y&or?ør???s&ah?kel?om??øjg??kabene?ojsarak?ram&deh.&aoq-relv--nx?rel&av?åv??so??e&let.&ag5-b--nx?ob?øb??ra???åjks??l&a!d&anrus?d&numurb?ron??e&gnard?nte?s&meh?sin??ttin??g&is?nyl??kro?l&em?l&ejfttah?of??u&ag-ertdim?s???n&am?era?gos?i&b?nroh?r??kos?nus?oj??o-&dron?r&os?øs???ppo?r&a!l?nram??e&gne?l?v??is?o&jts?ts??u&a-&dron?r&os?øs???h??å?æl?øjts??s&e&jg?nivk?ryf??kav?mor-go-er&om.&ednas?yoreh??øm.&ednas?yøreh???uag??t&las?rajh?suan??v&l&a?e-rots??u-go-eron??yt??ksedlig?res&a?å???bib&eklof?seklyf??es!dah??h!.sg??i&m?syrt??l&ejf?ov&etsua?gnit?ksa?sdie???n!.sg??o!.sg?boh?g?h??r!.sg??å!ksedlig??øboh??m&a&rah?vk??f!.sg??h!.sg??i&e&h&dnort?rtsua?ssej??rkrejb??ksa??ol?t!.sg??u&dom?esum?r&ab?drejg?evle?os?uh?æb?øs??ttals???n&a&g&av?okssman?åv??jlis?or?r&g?rev???e&d&do&sen?ton??lah?r&agy&o?ø??ojfsam???g&iets?n&a&l&as?lab??n&avk?ævk??t&arg?ddosen??v&al?essov???i&d&ol?øl??l&ar?ær???yl??reb??iks?k&srot?y&or?ør???l&a&d&gnos?n&er?ojm?øjm??om??tloh??ug?åtloh??mmard?ojs&om?sendnas??ppolg?s&lahsladr&ojts?øjts??o??t&o&l?t-erts&ev?o?ø???roh?øl??vly&kkys?nav??yam-naj!.sg??øjs&om?sendnas???g&orf?ujb??i&dnaort?vnarg??kob?ladendua?maherk&a?å??n&it?urgsrop??orf-&dron?r&os?øs???r&aieb?evats??sfev?uaks?yrts??o&6axi-ygvtsev--nx?c,d&ob?rav??ievs?kssouf?l&m&ob?øb??ous&adna?ech&ac?áč???so!.sg???msdeks?niekotuak?r&egark?olf?y&oso?øso???s&dav?mort???p&ed?p&akdron?elk???r&a&d&dj&ab?áb??iab??jtif?luag?mah?vsyt??e&gn&a&k&iel?ro??merb?n&at?mas??rav-r&os?øs??srop?talf?v&ats?el??y&oh?øh???ivsgnok??il?jkniets?k&a&nvej?rem?s&gnir?nellu???ie-er&den?v&o?ø???ram?sa?årem??la&jf?vh??m&b&ah?áh??mahellil??nnul?ts&l&oj?øj??ul??y&o?ø???imp&ah?áh??m!.sg??osir?t!.sg??ádiáb?ævsyt?øsir??s&adnil?en&dnas?e&dga?k&ri&b?k??som??ve??me&h?jg??nroh-go-ejve?s&a?ednil?k&o?ø??of?yt?å??tsev??gv?hf?igaval?o&r&or?ør??sman??so&fen&oh?øh??m?v??uh&lem?sreka.sen??å!dnil???t&a&baol?g&aov?grav??jjr&av-attam?áv-attám??l&a&b?s??ás??soum?ts?v&eib?our???e&dnaly&oh?øh??f?s&nyt?rokomsdeks?sen??vtpiks??in&aks?áks??loh&ar?år??n!.sg??o&m&a?å??psgolb,?s!.sg?efremmah?or?ør??terdi?á&baol?ggráv?lá&b?s??soum?veib???u&b!.sg?alk?e&dna?gnir?nner??les?ælk??dra&b?eb??g&nasrop?vi?ŋásrop??j&daehal&a?á??jedub?v&arekkhar?árekkhár???ksiouf?n&diaegadvoug?taed???v&irp?lesl&am?åm???y&b&essen?nart?sebel?tsev??o&d&ar?na!s??or??gavtsev?k&rajb?sa??lem?mrak?n&art?n&if?orb???r&a&mah?n?v??e&dni?t&so?ton??va??ul?yd??s&am?enner?gav?lrak?tivk??vrejks??ø&d&ar?na!s??ør??gåvtsev?k&rajb?sa??lem?mrak?n&art?n&if?ørb???r&e&dni?t&so?tøn??va??ul?yd?æ&n?v???s&enner?gåv?tivk?åm??vrejks???á&slág?tlá?vreiks??å&gåv?h?jddådåb?lf??ø&d&ob?rav??r&egark?olf??s&dav?mort????aki?i&sac?tal??u??o&b?f?g?hay?o?ttat??r!.&cer?erots?gro?m&o&c?n??rif?t?yn,?ofni?pohs,stra?t&n?opsgolb,?www??e&a!.&a&ac?cgd?idem??bulc!orea??ci&ffartria?taborea??e&cn&a&l&lievrus-ria?ubma??netniam?rusni??erefnoc??gnahcxe?mordorea?ni&gne?lria?zagam??rawtfos??gni&d&art?ilg!arap?gnah???l&dnahdnuorg?ledom??noollab?retac?sael?t&lusnoc?uhcarap??vidyks??hcraeser?l&anruoj?euf?icnuoc?ortnoc!-ciffart-ria???n&gised?oi&nu?t&a&cifitrec?ercer?gi&tsevni-tnedicca?van??i&cossa!-regnessap??valivic??redef??cudorp?neverp-tnedicca????ograc?p&ihsnoipmahc?uorg!gnikrow???r&e&dart?enigne?korb?niart?trahc??o&htua?tacude???s&citsigol?e&civres?r??krow?serp!xe??tnega??t&farcr&ia?otor??hgil&f?orcim??liubemoh?n&atlusnoc?e&duts?m&esuma?n&iatretne?revog??piuqe????olip?ropria?si&lanruoj?tneics???w&erc?ohs??y&cnegreme?dobper?tefas????rref?z??p!.&a&aa?ca?pc??dem?ecartsnd.icb,gne?r&ab?uj??snduolc,t&acova?cca?hcer??wal?ysrab,???s!.&em?gro?hcs,moc?ten?ude?vog???t!.&ayo,gro?lim?moc?sulpnpv,t&cennockciuq.tcerid,en??ude?vog??o&hp?m?v?yk??tol?ua??v&iv?lov??xas?ykot??p&a&ehc?g?m?s??cj?eej?g!.&gro?ibom?moc?ossa?ten?ude???i&r!.nalc,?v?z??j!.&a&3&5xq6f--nx?xqi0ostn--nx??5wtb6--nx?85uwuu--nx?9xtlk--nx?bihc!.&a&bihciakoy?don?ma&him?ye&ragan?tat???r&a&bom?gan?hihci??u&agedos?kas?ustak???s&os?ufomihs??t&amihcay?iran??w&a&g&im&anah?o??omak??kihci?zustum??ihsak??y&agamak?imonihci???e&akas?nagot??i&azni?esohc?h&asa?s&abanuf?ohc???ka&to?zok??musi?orihs?r&akihabihsokoy?o&dim?tak??ukujuk??usihs??nano&hc?yk??o&d&iakustoy?ustam??hsonhot?k&a&rihs?t??iba??nihsaran?sobimanim?tas&arihsimao?imot??uhc?yihcay??u&kujno?s&ayaru?t&imik?tuf???zarasik????g&as!.&a&gas?m&a&tamah?yik??ihsak??rat?t&a&gatik?hatik??ira!ihsin????e&kaira?nimimak??i&akneg?g&aruyk?o??h&c&amo?uo??siorihs??kaznak?modukuf?ra&gonihsoy?mi???nezih?u&k&at?ohuok??s&ot?tarak?????ihs!.&a&kok?m&a&hagan?yirom??ihsakat??rabiam?wagoton??e&miharot?nokih??houyr?i&azaihsin?esok?kustakat?moihsagih??na&mihcahimo?nok??o&hsia?mag?t&asoyot?ok?tir???us&ay?t&asuk?o??????k&aso!.&a&d&awihsik?eki??k&a&noyot?s&akaayahihc?oihsagih???oadat?uziak??m&ayas!akaso??odak??r&a&bustam?wihsak??ediijuf??t&akarih?i&k?us???wag&ayen?odoyihsagih???e&son?tawanojihs??honim?i&akas?h&cugirom?s&ayabadnot?i&a&kat?t??n??oyimusihsagih???k&a&rabi?sim??ustakat??muzi?r&ijat?otamuk???nan&ak?n&ah?es???o&ay?n&a&ganihcawak?simuzi?tak??eba?ikibah?oyot??t&anim?iad?omamihs??uhc??ust&oimuzi?tes????ou&kuf!.&a&d&amay?eos??g&no?ok?usak??hiku?k&awayim?uzii??ma&kan?y&asih?im???rawak?t&a&gon?ka&h?num?t???umo??wa&g&a&kan?nay?t??ias??ko!rih???y&ihsa?usak???e&m&ay?uruk??taruk?us??i&a&nohs?raihcat??goruk?h&cukuf?s&a&gih?hukuy??in???k&a&gako?muzim??iust?o?ustani??m&anim?otihsoynihs?u??r&ogo?ugasas??usu??ne&siek?zu&b?kihc???o&gukihc?h&ak?ot?ukihc??j&ono?ukihc??kayim?nihsukihc?to?uhc??u&fiazad?gnihs?stoyot????zihs!.&a&bmetog?d&amihs?eijuf?ihsoy?omihs??kouzihs?mihsim?ra&biah?honikam??tawi?wa&g&ekak?ukik??kijuf??yimonijuf??i&a&ra?sok??hcamirom?juf?kaz&eamo?ustam??ma&nnak?ta??nukonuzi?orukuf??nohenawak?o&nosus?ti??u&stamamah?z&a&mun?wak??i!ay?i&hs&agih?in??manim??mihs????????m&a&tias!.&a&d&ihsoy?ot?usah??k&a&dih?sa??o&arihs?s???m&a&tias?y&as?o&rom?tah??ustamihsagih???i&hsagurust?jawak??uri??ni?wa&g&e&ko?man??ikot?o??k&ara?i&hsoy?mak???ru?zorokot??y&a&g&amuk?ihsok?otah??kuf??imo??ziin??e&bakusak?ogawak?sogo?ttas?zokoy??i&baraw?h&cugawak?s&oyim?ubustam???iroy?k&ato?ihs?u&k?stawi???m&akoyr?i&hsoy?juf??uziimak???naznar?o&dakas?ihsay?jnoh?n&a&go?nim??imijuf?nah?oy??r&ihsayim?otagan??t&asim!ak??igus?omatik??zak??u&bihcihc!ihsagih??sonuok?ynah????y&ak&aw!.&a&d&ira?notimak??kadih?ma&h&arihs?im??y&a&kaw?tik??oduk???ru&ustakihcan?y??sauy?wa&g&a&dira?zok??orih??konik??yok?zok??e&banat?dawi??i&garustak?jiat?mani??naniak?o&bog?nimik?t&asim?omihs&ah?uk????ugnihs???o!.&a&jos?koasak?m&ay&ako?ust??ihsayah??r&abi?ukawaihsin??wi&aka?nam???e&gakay?kaw??i&gan?h&cu&kasa?otes??sahakat??k&asim?ihsaruk??miin??n&anemuk?ezib??o&hsotas?jnihs?n&amat?imagak??ohs?uhcibik?????ot!.&a&damay?got?koakat?may&etat?ot??nahoj?riat?waki&inakan?reman???eb&ayo?oruk??i&h&asa?ciimak?sahanuf??kuzanu?m&an&i?ot??ih???nezuyn?otnan?u&hcuf?stimukuf?z&imi?ou???????ihs&o&gak!.&a&m&ayuok?ihsogak??si?yonak??e&banawak?n&at&akan?imanim??uka??tomoonihsin??i&adnesamustas?k&azarukam?oih??m&ama?uzi??usuy??nesi?o&knik?os?tomustam??uzimurat???rih!.&a&ka&n?s??m&ayukuf?i&hsorihihsagih?j&ate?imakikaso????r&a&bohs?h&ekat?im???es??tiak?wiad??e&kato?ruk??i&h&ci&akustah?mono?nihs??s&inares?oyim???manimasa?uk??negokikesnij?o&gnoh?namuk??uhcuf????uk&ot!.&a&bihci?mi&hsu&kot?stamok??m??wagakan??egihsustam?i&gum?h&coganas?soyim??kijaw?m&anim?uzia??ukihsihs??nan&a?iak??o&nati?turan????uf!.&a&batuf?m&a&to?y&enak?irok???ihs&im?ukuf??os?uko??r&aboihsatik?uganat??ta&katik?mawak?rih??w&a&g&akus?emas?uy??k&a&mat?rihs?sa??ihsi??nah??ohs???e&gnabuzia?iman?ta&d?tii???i&adnab?enet?hs&agih?iimagak??k&a&wi?zimuzi??ubay??minuk?r&ook?ustamay???nihsiat?o&g&etomo?ihsin?nan?omihs??no!duruf?rih??rihsawani?ta&may?simuzia???u&rahim?stamakawuzia?zia&ihsin?nay???????nug!.&a&bawak?doyihc?k&anna?oi&hsoy?juf?mot???m&ayakat?ustagaihsagih??n&ihsatak?nak??r&ahonagan?nak?o?u&kati?mamat???t&amun?inomihs?o??w&akubihs?iem?ohs???i&hsa&beam?yabetat??kas&akat?esi??m&akanim?uzio??ogamust?rodim??o&jonakan?n&eu?oyikust??tnihs??u&komnan?stasuk?yrik?????ran!.&a&bihsak?d&akatotamay?u!o???guraki?m&ay&atik&imak?omihs??irokotamay??oki??ra&hihsak?n??wa&geson?knet???e&kayim?ozamay?sog?ustim??i&a&rukas?wak??garustak?h&ciomihs?sinawak??jo?ka&mnak?toruk??makawak?nos?r&net?otakat?ugeh???o&d&na?oyo??gnas?jnihs?nihsoy!ihsagih??tomarawat?yrok????t&ag&amay!.&a&dihsio?k&atarihs?ourust??may&a&kan?rum??enak?onimak??rukho?ta&ga&may?nuf??hakat?kas??wa&g&ekas?orumam??ki&hsin?m??z&anabo?enoy?ot???zuy??e&agas?bonamay?dii?nihsagih?o??i&a&gan?nohs??h&asa?sinawak??nugo??o&dnet?jnihs?ynan??ukohak???iin!.&a&ga?k&ium?oagan??munou!imanim??t&a&bihs?giin??ioy??w&a&gioti?kikes?zuy??irak??yijo??e&kustim?mabust??i&aniat?hcamakot?kaz&awihsak?omuzi??m&a&gat?karum??o???n&anust?esog??o&das?ihcot?jnas?k&ihay?oym??mak?naga?ries??u&ories?steoj?????i&ka!.&a&go?k&asok?oimak??t&ago!rihcah??ika!atik???w&aki?oyk???e&mojog?natim?suranihsagih?t&ado?okoy???i&hsoyirom?magatak?naokimak??nesiad?o&hakin?jnoh!iruy??nuzak?rihson?tasi&juf?m??yjnoh??u&kobmes?oppah????o!.&a&dakatognub?m&asah?ihsemih??su?t&ekat?i&h?o????e&onokok?ustimak??i&jih?k&asinuk?ias?usu??mukust??onoognub?u&fuy?juk?ppeb?suk??????wa&ga&k!.&a&mihsoan?rihotok?waga&kihsagih?ya???emaguram?i&j&nonak?ustnez??kunas?monihcu??o&hsonot?nnam?yotim??u&st&amakat?odat??zatu????nak!.&a&dustam?kus&okoy?tarih??maz?nibe?r&a&gihsaimanim?h&esi?imagas??wa&do?guy???u&im?kamak???tikamay?wa&k&ia?oyik?umas??sijuf??yimonin??e&nokah?saya??i&akan?esiak?gusta?hsuz?kasagihc?o?ukust??o&nadah?sio?tamay?????kihsi!.&a&danihcu?gak?kihs?mijaw?t&abust?ikawak??wazanak??i&gurust?hcionon?mon?ukah??nasukah?o&anan?ton!akan???u&kohak?stamok?z&imana?us?????niko!.&a&han?m&arat?ijemuk?uru??n&e&dak?zi??no??ra&hihsin?rih??wa&kihsi?niko??yehi?zonig??e&osaru?seay??i&hsagih?jomihs?k&a&gihsi?not??ihsakot??m&a&ginuk?kihsug?maz??igo?otekat??nuga!noy???n&a&moti?timoy?wonig??i&jikan?k???o&gan?jnan?tiad&atik?imanim???u&botom?kusug&akan!atik??imot??rab&anoy?eah???????c&204ugv--nx?462a0t7--nx?678z7vq5d--nx?94ptr5--nx?a??d&17sql1--nx?3thr--nx?5&20xbz--nx?40sj5--nx??7&87tlk--nx?ptlk--nx??861ti4--nx?a?e??e&16thr--nx?5&1a4m2--nx?9ny7k--nx??im!.&a&bot?k&asustam?uzus??m&a&him?y&emak?im???ihs??nawuk?wi&em?k???e&bani?ogawak?si!imanim???i&arataw?gusim?h&asa?ciakkoy??k&a&mat?sosik?t??iat??raban??o&dat?hik?n&amuk?ihseru?o&du?mok????ust???mihe!.&a&m&a&h&ataway?iin??yustam??ij&awu?imak???taki!man???ebot?i&anoh?kasam?rabami??n&ania?egokamuk?oot??o&jias?kihcu?nustam?uhcukokihs?yi!es???u&kohik?zo????n!.&nriheg,teniesa.resu,?amihs!.&a&d&amah?ho?usam??kustay?m&a?ihsoni&hsin?ko???wakih??e&namihs?ustam??i&g&aka?usay??konikak?mikih??nannu?o&mu&kay?zi!ihsagih?uko???nawust?tasim??u&stog?yamat?????tawi!.&a&bahay?d&amay?on??koirom?t&a&honat?katnezukir??imus??w&as&ijuf?uzim??ihs???e&hon&i&hci?n??uk??tawi??i&a&duf?murak?wak??h&custo?si&amak?ukuzihs???j&oboj?uk??k&a&m&anah?uzuk??sagenak??esonihci??m&akatik?uzia&rih?wi????o&kayim?no&rih?t??tanufo??uhso????g&3zsiu--nx?71qstn--nx?l??h&03pv23--nx?13ynr--nx?22tsiu--nx?61qqle--nx??i&54urkm--nx?g&ayim!.&a&dukak?m&a&goihs?kihs??ihsustam!ihsagih??unawi??r&awago?iho??ta&bihs?rum??w&a&gano?kuruf??iat??y&imot?ukaw???e&mot?nimes??i&hsiorihs?ka&monihsi?s&awak?o???mak?r&ataw?o&muram?tan????o&az?jagat?t&asim?omamay???u&fir?k&irnasimanim?uhsakihcihs?????ihcot!.&a&g&a&h?kihsa??ust??kom?m&ay&o?usarak??unak??r&a&boihsusan?watho??iho?ukas??t&akihsin?iay??wa&konimak?zenakat??y&imonustu?oihs???e&iiju?kustomihs?nufawi??i&akihci?g&etom?ihcot?on???o&k&ihsam?kin??nas?sioruk?tab??u&bim?san?????h&c&ia!.&a&dnah?m&a!h&akat?im??yuni??ihs&ibot?ust???r&a&hat?tihs??ik?u&ihsagih?kawi???t&ihc?o&k?yot???wa&koyot?zani??yi&monihci?rak???e&inak?k&aoyot?usa??manokot?noyot??i&a&gusak?kot?sia??eot?h&asairawo?cugo?s&ahoyot?oyim???k&a&mok?zako??ihssi??motay?rogamag??n&an&ikeh?ok??ihssin??o&got?ihsin?jna?rihsnihs?suf?tes??u&bo?raho?s&oyik?takihs??yrihc?zah????ok!.&a&dusay?kadih?mayotom?r&ah&im?usuy??umakan??sot!ihsin??wa&g&atik?odoyin??k&as?o????i&esieg?hco!k??jamu?k&a!sus??usto??ma&gak?k??rahan??o&mukus?n&i?ust!ihsagih???torum?yot!o???u&koknan?zimihsasot????ugamay!.&a&m&ayukot?ihso??toyot??e&bu?subat??i&gah?kesonomihs?nukawi?rakih??nanuhs?otagan?u&ba?foh?otim?stamaduk?uy?????sanamay!.&a&dihsoyijuf?mayabat?r&ahoneu?ustakihsin??w&a&k&ayah?ijuf??suran??ohs???egusok?i&ak?h&cimakan?s&anamay?od???k&asarin?u&feuf?sto????o&k&akanamay?ihcugawakijuf??nihso?t&asimawakihci?ukoh??uhc??spla-imanim?u&b&nan?onim??fok?hsok?rust?????ka&rabi!.&a&bukust?gok?kan!ihcatih??m&a&sak?timo?wi??ihsak?ustomihs??ni?r&a&hihcu?way??u&agimusak?ihcust???t&ag&amay?eman??oihcatih??w&ag&arukas?o??os??yi&moihcatih?rom???e&bomot?dirot?not?tadomihs??i&a&k&as?ot??rao??esukihc?gahakat?h&asa?catih??k&a&rabi?saguyr??ihsani?uy??ma?rukustamat??o&dnab?giad?him?kati?rihsijuf?soj?t&asorihs?im??yihcay??u&fius?kihsu?simak????sagan!.&a&m&abo?ihsust??natawak?r&abamihs?u&mo?ustam???wijihc?yahasi??i&akias?hies?k&asagan?i??masah??neznu?o&besas?darih?t&eso?og!imaknihs????ust&igot?onihcuk?uf????zayim!.&a&biihs?guyh?k&oebon?ustorom??mihsuk?r&emihsin?uatik??ta&katik?mim??wag&atik?odak??ya??e&banakat?sakog??i&hsayabok?kaza&kat?yim??m&animawak?ot&inuk?nihs????nanihcin?o&j&ik?onokayim??n&ibe?ust??tias??urahakat????ro&moa!.&a&dawot?turust?wasim??e&hon&ihc&ah?ihs??nas?og?ukor??sario??i&anarih?ganayati?hsioruk?jehon?kasorih?makihsah?nawo?r&amodakan?omoa???o&gnihs?kkat??u&ragust?stum????ttot!.&a&r&ahawak?uotok??sa&kaw?sim???egok?irottot?nanihcin?o&ganoy?nih?tanimiakas??u&bnan?z&ay?ihc??????ukuf!.&a&deki?gurust?ma&bo?h&akat?im??yustak??sakaw??eabas?i&akas?ho?jiehie?ukuf??nezihce!imanim??ono????k&26rtl8--nx?4&3qtr5--nx?ytjd--nx??522tin--nx?797ti4--nx??l33ussp--nx?m&11tqqq--nx?41s3c--nx??n&30sql1--nx?65zqhe--nx?n7p7qrt0--nx??o&131rot--nx?7qrbk--nx?c?diakkoh!.&a&deki?gakihset?hcebihs?k&adih?u&fib?narihs???m&ayiruk?hot?ihs&orihatik?ukuf??oras?usta??r&ib&a!ka??o?uruf??ozo?u&gakihsagih?oyot???sakim?ta&gikust?mun??w&a&ga&k&an?uf??nus!imak???k&aru?i&h&asa?sagih??kat?mak??omihs?um??zimawi??ine?oyk??yot??e&a&mustam?nan??b&a&kihs?yak??o&noroh?to???ian?k&ihsam?ufoto??nakami?ppoko!ihsin??sotihc?tad!okah??uonikat??i&a&bib?mokamot?n&a&k&kaw?oroh??wi??eomak?ihsatu?okik?usta&moruk?sakan????eib?h&c&ioy?u&bmek?irihs???s&ase?ekka?oknar?uesom???jufirihsir?k&amamihs?i&at?n???m&atik?otoyot??oa&kihs?rihs??r&a&hs?kihsi?mot??ihs&aba?ir??otarib???n&a&hctuk?rorum?se?tokahs??uber??o&kayot?m&ire?ukay??naruf!ima&k?nim???orih?r&ih&ibo?suk??o&bah?h&i&b?hsimak??sa??pnan?yan??umen??t&asoyik?eko?ukoh???u&bassa?kotnihs?m&assaw?uo??pp&akiin?en&ioto?nuk??ip??rato?s&akat?t&eb&e?i&a?hs!a??robon??m&e?o&m?takan???no&h?tamah??o&mik?s?t??u&kir?ppihc?st???onihsnihs?ufuras??uaru??yru!koh??zimihs!ok?????g!oyh!.&a&bmat?dnas?gusak?k&at?o&oyot?y??uzarakat??m&ayasas?irah??wa&g&ani?okak??k&i&hci?mak??oy???yi&hsa?monihsin???i&asak?hs&aka?i&at?nawak???j&awa!imanim??emih??k&a&goa?s&agama?ukuf??wihsin??i&hsog?m???mati?oia?rogimak??n&annas?esnonihs??o&gasa!kat??ka?n&ikat?o?ustat??rihsay?sihs?tomus?yas??u&bay?gnihs?????nagan!.&a&bukah?d&a&w?yim??e&ki?u??ii??k&a&s&ay?uki??zus??ihsoo?ousay??m&ay&akat?ii??i&hsukufosik?jii??ukihc??n&i!hsetat??uzii??r&ah?ugot??saim?t&agamay?oyim??w&a&g&a&kan?n??o??kustam?ziurak??onim!imanim??u&koo?s!omihs????ya&ko?rih???e&akas?nagamok?subo??i&gakat?h&asa?c&a!mo!nanihs???uonamay??sukagot??k&a&kas?mimanim?to??ia&atik?imanim??oa?uzihcom??m&akawak?ijuf?o!t???r&ato?ijoihs?omakat???n&ana?esnoawazon??o&hukas?n&a&gan?kan??i&hc?muza??ustat??romok?si&gan?k??tomustam??u&k&as?ohukihc??stamega????to&mamuk!.&a&gamay?rahihsin?sukama!imak??tamanim??enufim?i&hcukik?k&ihsam?u??nugo!imanim??romakat??o&ara?rihsustay?sa?t&amay?om&amuk?us??u!koyg???yohc??u&sagan?zo????yk!.&a&bmatoyk?k&ies?oemak?uzaw??mayi&h&cukuf?sagih??muk??nihsamay?rawatiju?t&away?ik???e&ba&nat!oyk??ya??di?ni??i&ju?kazamayo?manim??natnan?o&gnatoyk?kum?mak?rihsamayimanim?y&gakan?ka&koagan?s??oj???u&ruziam?z&ayim?ik??????wtc1--nx?ykot!.&a&d&i&hcam?mus??oyihc??k&atim?ihsustak??m&a&t!uko??yarumihsa&gih?sum???i&hs&agoa?ika?o!t??uzuok??ren???r&a&honih?wasago??iadok?umah??ssuf?t&ik?o??wa&g&anihs?ode??k&ara?ihcat???y&agates?ubihs???e&amok?donih?m&o?urukihsagih??soyik??i&enagok?gani?h&ca&da?tinuk??sabati??j&nubukok?oihcah??manigus??o&huzim?jihcah?n&akan?ih!sasum??urika??rugem?t&a&mayihsagih?nim??iat?ok??uhc?yknub??u&fohc?hcuf?kujnihs?????r&2xro6--nx?g?o??s&9nvfe--nx?xvp4--nx??t&netnocresu,opsgolb,?u&4rvp8--nx?fig!.&a&d&eki?ih??kimot?m&ayakat?ihsah??ne?raha&gi&kes?makak??sak??taga&may?tik??wa&g&ibi?ustakan??karihs!ihsagih????e&katim?uawak??i&gohakas?hc&apna?uonaw??k&ago?es?ot??m&anuzim?ijat??nak?urat??nanig?o&dog?jug?makonim?nim?roy?sihcih??u&fig?s&otom?t&amasak?oay???????x5ytlk--nx?yu6d27srjd--nx?z72thr--nx?井福?京東?分大?取鳥?口山?城&宮?茨??媛愛?山&富?岡?歌和??岡&福?静??島&児鹿?広?徳?福??崎&宮?長??川&奈神?石?香??庫兵?形山?手岩?木栃?本熊?根島?梨山?森青?潟新?玉埼?田秋?知&愛?高??縄沖?良奈?葉千?賀&佐?滋??道海北?都京?重三?野長?阜岐?阪大?馬群???k!.&art?gro?moc?per?ude?vog???l&eh?l??m!ac?j??nd?o&g?h&pih?s!.ysrab,??lnud?oc?t!.&lldtn,snd-won,???pa!.&arusah,enilnigol,nur:.a,,t&ibelet,xenw,?yfilten,??ra&a?hs??u&ekam?llag?org!.esruocsid,cts?kouk?nayalo???vsr?xece4ibgm--nx??q&a!3a9y--nx??g?i!.&gro?lim?moc?ten?ude?vog???m?se??r&a!.&acisum?bog?gro?lim?moc!.topsgolb,?rut?t&en?ni??ude?vog??4d5a4prebgm--nx?b?c?eydoog?los?t&at?s!uen???ugaj??b!.&21g?a&b&a&coros?iuc??itiruc??cnogoas?dicerapa?gniram?i&naiog?ramatnas??n&erom?irdnol??op?p&acam?irolf?ma&j?s???rief?tsivaob??b!aj?mi?sb??c&ba?er?js?sp?t!e???d&em?mb?n&f?i??rt??e&dnarganipmac?ficer?ht?llivnioj?rdnaotnas??f&dj?ed?gg?ni??g&el!.&a&b,m,p,?bp,c&a,s,?e&c,p,s,?fd,gm,ip,jr,la,ma,nr,o&g,r,t,?p&a,s,?r&p,r,?s&e,m,r,?tm,??l&s?z??n&c?e?o??ol&b?f?v??pp?ro??hvp?i&du?kiw?nana?oretin?r&c?eurab??sp?te?xat??l&at&an?rof??el?im?sq??m&a?da?e&gatnoc?leb??f?ic?oc!.topsgolb,??nce?o&ariebir?c&e?narboir?saso??d&o?ranreboas??et?i&b?dar?ecam?r??rp?t&a?erpoir???p&m!e?t??ooc?se??qra?r&af?ga?o&davlas?j??tn?ut??s&a&ixac?mlap?nipmac??u&anam?j?m???t&am?e&n?v??nc?o&f?n??ra?sf??u&caug9?de?ja?rg??v&da?og!.&a&b?m?p??bp?c&a?s??e&c?p?s??fd?gm?ip?jr?la?ma?nr?o&g?r?t??p&a?s??r&p?r??s&e?m?r??tm???rs?t??xiv?z&hb?ls?of????c!.&as?ca?de?if?o&c?g??ro???e&bew?ccos?dnik?e&b?n&igne?oip??rac??gni&arg?rheob??h&cor?sok?t&aew?orb???itnorf?k&col?o&p?rb???l&aed?ffeahcs??mal?nes?pinuj?t&a&eht?rebsnegömrev??law?nec?s&acnal?nom?ubkcolb??upmoc??v&o&c&sid?tfiws??rdnal??resbo??wulksretlow?ywal?zifp??f!.&aterg?bew-no,drp?e&c&itsuj-reissiuh?narf-ne-setsitned-sneigrurihc,?rianiretev??i&cc?rgabmahc??m&o&c?n??t??n&eicamrahp?icedem??ossa?s&e&lbatpmoc-strepxe?riaton?tsitned-sneigrurihc?uova??o&-x&bf,obeerf,?x&bf,obeerf,???t&acova?o&or-ne,psgolb,?r&epxe-ertemoeg?op!orea????vuog??avc7ylqbgm--nx?s??g!.&gro?m&oc?yn,?t&en?opsgolb,?ude?vog???h!.&e&erf,man??mo&c?rf??topsgolb,zi??ur??i!.&a&61f4a3abgm--nx?rf4a3abgm--nx??ca?di?gro?hcs?oc?ten?vog?نار&يا?یا???a&h?per??ew?lf??k!.&c&a?s??e&n?p?r??gk?iggnoeyg?kub&gn&oeyg?uhc??noej??l&im?uoes??man&gn&oeyg?uhc??noej??n&as&lu?ub??o&e&hcni?jead??wgnag???o&c?g??ro?s&e?h?m??topsgolb,u&gead?j&ej?gnawg????cilf??l!.&gro?moc?ten?ude?vog???m!.&topsgolb,vog???n!.&gro?moc?ofni?ten?ude?vog?zib???o&cs?htua?odtnorf?t&c&a?od??laer???p!.&alsi?ca?eman?forp?gro?moc?o&fni?rp??t&en?se??ude?vog?zib???s?t!.&21k?bew?cn!.vog??eman?gro?kst?l&e&b?t??im?op??moc!.topsgolb,?neg?ofni?pek?rd?sbb?ten?ude?v&a?og?t??zib??f?m??ubad?vd??s&8sqif--nx?9zqif--nx?a!.vog?birappnb?gev?lliv?mtsirhc?s??b!.&ew,gro?moc?ten?ude?vog??c?oj?s?u??c&i&hparg?p?t&sigolyrrek?ylana???od??d&a?d?l?n&iwriaf?omaid??oogemoh?rac??e!.&bog?gro?mo&c!.topsgolb,?n??ude??civres!.enilnigol,?d&d2bgm--nx?oc??h&ctaw?guh??i&lppus?rtsudni?treporp!yrrek???jaiv?l&aw?cycrotom?etoh?gnis?pats??m&ag?oh?reh??nut?ohs?picer?r&it?ut&cip!.7331,?nev???s!i&rpretne?urc??ruoc??taicossa?vig??g!nidloh??h5c822qif--nx?i!.&ekacpuc,gro?moc?t&en?ni?opsgolb,?ude?vog??a09--nx?nnet?rap?targ??k&c&or!.&ecapsbew,snddym,ytic-amil,??us??hxda08--nx?row??l!.&c&a?s??gro?o&c?fni??ten?ude?vog?zib??a&ed?tner??e&ssurb?toh!yrrek???lahsram?m?oot??m!.&bal,gro?moc?ten?ude?vog??b?etsys!.tniopthgink,?ialc??n&a&f?gorf?ol??egassap?i&a&grab?mod??giro??o&it&acav?cudorp?ulos??puoc???o&dnoc?geuj?leuv?ppaz?t&ohp?ua???p!.&ces?gro?moc?olp?ten?ude?vog??i&hsralohcs?lihp?t??u??r!.&au,ca?gro?mon,ni?oc?topsgolb,ude?vog?xo,?a&c?p?tiug??c?e&dliub?erac?gor?levart?mraf?n&niw?trap??wolf??ot&cartnoc?omatat??pj?uot??s!.&gro?moc?ten?ude?vog?zib??alg?e&n&isub!.oc,?tif??rp!xe!nacirema???xnal??iws??t&a&e&b?ytic??ob??ek&cit?ram??fig?h&cay?gilf??n&atnuocca?e&mt&rapa?sevni??ve!.oc,???rap??u!.&a&c!.&21k?bil?cc???g!.&21k?bil?cc???i!.&21k?bil?cc???l!.&21k?bil?cc???m!.&21k!.&hcorap?rthc?tvp???bil?cc???p!.&21k?bil?cc???si?v!.&21k?bil?cc???w!.&21k?bil?cc????c&d!.&21k?bil?cc???n!.&21k?bil?cc???s!.&21k?bil?cc????d&ef?i!.&21k?bil?cc???m!.&21k?bil?cc???n!.&bil?cc???s!.&bil?cc???urd,?e&d!.&21k?bil,cc???las-4-&dnal,ffuts,?m!.&21k?bil?cc???n!.&21k?bil?cc????h&n!.&21k?bil?cc???o!.&21k?bil?cc????i&h!.&bil?cc???m!.&21k?bil?c&c?et??goc?n&eg?otae??robra-nna?sum?tsd?wanethsaw???nd?r!.&bil?cc???v!.&21k?bil?cc???w!.&21k?bil?cc????jn!.&21k?bil?cc???k&a!.&21k?bil?cc???o!.&21k?bil?cc????l&a!.&21k?bil?cc???f!.&21k?bil?cc???i!.&21k?bil?cc????mn!.&21k?bil?cc???n&afflog,i!.&21k?bil?cc???m!.&21k?bil?cc???sn?t!.&21k?bil?cc????o&c!.&21k?bil?cc???m!.&21k?bil?cc???ttniop,?p&ion,rettalp,?r&a!.&21k?bil?cc???o!.&21k?bil?cc???p!.&21k?bil?cc????s&a!.&21k?bil?cc???dik?k!.&21k?bil?cc???m!.&21k?bil?cc???nd&deerf,uolc,??t&c!.&21k?bil?cc???m!.&21k?bil?cc???u!.&21k?bil?cc???v!.&21k?bil?cc????ug!.&21k?bil?cc???v&n!.&21k?bil?cc???w!.cc???x&ohparg,t!.&21k?bil?cc????y&b-si,k!.&21k?bil?cc???n!.&21k?bil?cc???w!.&21k?bil?cc????za!.&21k?bil?cc????ah!uab??bria?col?e!.ytrap.resu,?ineserf?lp?xe&l?n???vt?w!.&66duolc,gro?moc?s&ndnyd,tepym,?ten?ude?vog??a?e&iver?n??odniw??y&alcrab?cam?ot???t&0srzc--nx?a!.&amil4,ca!.hts??gni&liamerutuf,tsoherutuf,?o&c!.topsgolb,?fni,?ph21,ro?v&g?irp,?xi2,ytic-amil,zib,?c?e!s??hc?if?l!asite??mami?rcomed??b!.&gro?moc?ten?ude?vog??b?gl??c&atnoc?e&les?rid!.lenaptsaf,txen????dimhcs?e!.&eman?gro?moc?ofni?ten?ude?vog?zib??b?em?grat?id?k&circ?ram??n!.&5inu,6vnyd,7&7ndc.r,erauqs,?a&l&-morf,moob,?minifed,remacytirucesym,tadsyawla,z,?b&boi,g,lyltsaf:.pam,,?c&inagro-gnitae,paidemym,?d&ecalpb,nab-eht-ni,uolc&meaeboda,xednay:.e&garots,tisbew,?,??e&cnarusnihtlaehezitavirp,ht-no-eciffo,l&acsnoom,ibom-eruza,?m&ecnuob,ohtanyd,tcerider,?nozdop,rehurht,s,tis-repparcs,zamkcar,?f&aeletis,crs.&cos,resu,?ehc-a-si,?g&ni&reesnes,tsohnnylf,?olbevres,?k&eeg-a&-si,si,?u,?l&acolottad,iamwt,s&d-ni,s-77ndc,??m&ac&asac,ih,?urofniem,?n&a&f&agp,lhn,?ibed,?dcduabkcalb,i,pv-ni,?o&c-morf,jodsnd,rp-ytinummoc,ttadym,?p&i&-&etsef,on,?emoh,fles,nwo,?j,mac-dnab-ta,o&-oidar-mah,hbew,?paduolc,tfe&moh,vres,?usnd,?r&e&tsulcyduolc,vres-xnk,?vdslennahc:.u,,?s&a&ila&nyd,snd,?nymsd,?bbevres,dylimaf,e&suohsyub,t&isbeweruza,ys,??kekokohcs,n&d&-won,d,golb,npv,?oitcnufduolc,?s&a-skcik,ecca&-citats,duolc,???t&ceffeym,e&nretnifodne,smem,?farcenimevres,i-&ekorb,s&eod,lles,teg,??n&essidym,orfduolc,?r0p3l3t,s&ixetnod,ohgnik,??u&h,nyd,r,?x&inuemoh,spym,unilemoh,?y&awetag-llawerif,ltsaf.&dorp.&a,labolg,?lss.&a,b,labolg,?pam,slteerf,?n&-morf,ofipi,?srab,tieduolc,?z&a-morf,tirfym,???p?tcip?v??f&ig?o&l?sorcim???g!.&bog?dni?gro?lim?mo&c?n,?ten?ude???h!.&dem?gro?l&er?op??m&oc?rif??o&fni?rp?s&rep?sa???po&hs?oc??t&en?luda?ra??ude?vuog???i!.&a&2n-loritds--nx?7e-etsoaellav--nx?8&c-aneseclrof--nx?i-lrofanesec--nx??at?b?c!cul??dv?i&blo&-oipmet?oipmet??cserb?drabmol?g&gof?urep??l&gup?i&cis?me&-oigger?oigger???uig&-&aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf???aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf????n&a&brev?cul?pmac?tac??idras?obrac&-saiselgi?saiselgi??resi??otsip?r&b&alac!-oigger?oigger??mu??dna&-&attelrab-inart?inart-attelrab??attelrabinart?inartattelrab?ssela??epmi?ugil??tnelav&-obiv?obiv??vap?z&e&nev?ps&-al?al???irog???l&iuqa!l??leib??m&or?rap??n!acsot?e&dom?is?sec&-&ilrof?ìlrof??ilrof?ìlrof???g&amor&-ailime?ailime??edras?olob??i&ssem?tal??ne!var??o&cna?merc?rev?vas???oneg?p?r!a&csep?rr&ac&-assam?assam??ef??von??etam?tsailgo!-lled?lled???s!ip?sam&-ararrac?ararrac??u&caris?gar???t!a&cilisab?recam??resac?soa!-&d&-&ellav?lav??ellav?lav??ellav??d&-&ellav?lav??ellav?lav??ellav??te&lrab&-&airdna-inart?inart-airdna??airdnainart?inartairdna??ssinatlac???udap?v!o&dap?neg?tnam???zn&airb&-a&lled-e-aznom?znom??a&lledeaznom?znom??eaznom??e&c&aip?iv??soc?top??om???b&-&23,46,61,?3c-lorit-ds-onitnert--nx?be-etsoa&-ellav--nx?dellav--nx??c!f-anesec-lrof--nx?m-lrof-anesec--nx??he-etsoa-d-ellav--nx?m!u??o2-loritds-nezob--nx?sn-loritds&-nasl&ab--nx?ub--nx??nitnert--nx??v!6-lorit-dsnitnert--nx?7-loritds&-nitnert--nx?onitnert--nx???z&r-lorit-ds&-nitnert--nx?onitnert--nx??s-loritds-onitnert--nx???c&f?is?l?m?p?r?v??d&p?u!olcnys,??e&c!cel?inev?nerolf??f?g!ida&-&a&-onitnert?onitnert??otla!-onitnert?onitnert???a&-onitnert?onitnert??otla!-on&azlob?itnert??onitnert????hcram?l?m!or??n&idu?o&n&edrop?isorf??torc???p?r?s&erav?ilom??t!nomeip?s&eirt?oa!-&d-e&ellav?éllav??e&ellav?éllav???de&ellav?éllav??e&ellav?éllav?????v?znerif??g&a?b?f?il?o?p?r?up?vf??hc?i&b?c?dol?f?l!lecrev?opan?rof&-anesec?anesec???m?n&a&part?rt&-attelrab-airdna?attelrabairdna???imir?ret??p?r!a&b?ilgac?ssas???s!idnirb??t&ei&hc?r??sa??v??l&a!c??b?c?o&m?rit&-&d&eus&-&nitnert?onitnert??nitnert?onitnert??us&-&nitnert?onitnert??nitnert?onitnert??üs&-&nitnert?onitnert??nitnert?onitnert???s&-onitnert?onitnert???d&eus!-&n&asl&ab?ub??ezob?itnert??onitnert??nitnert?onitnert??us&-&n&asl&ab?ub??ezob?itnert??onitnert??nitnert?onitnert??üs!-&n&asl&ab?ub??ezob?itnert??onitnert??nitnert?onitnert???s&-onitnert?onitnert?????m&ac?f?i?ol?r??n&a!lim?sl&ab?ub???b?c?e!v?zob??irut?m!p??p?r?t??o&a!v??b!retiv??c!cel??enuc?g!ivor??i&dem&-onadipmac?onadipmac??pmet&-aiblo?aiblo??rdnos?zal??l?m!a&greb?ret??oc?re&f?lap???n!a&dipmac&-oidem?oidem??lim?tsiro?zlob??ecip&-ilocsa?ilocsa??i&bru&-orasep?orasep??lleva?rot?tnert??r&elas?ovil??ulleb??p?r!a&sep&-onibru?onibru??znatac??oun??s!ivert?sabopmac??t!arp?e&nev?ssorg??n&arat?e&girga?rt?veneb????zz&era?urba???p&a?s?t??qa?r&a!m?s??b!a??c?f?g?k?me?o?p?s?t?v??s&a&b?iselgi&-ainobrac?ainobrac???b?c?elpan?i?m?ot?s?t?v??t&a?b?c?l?m?nomdeip?o!psgolb,?p?v??u&de?l?n?p??v&a?og?p?s?t?v??y&drabmol?ellav&-atsoa?atsoa??licis?nacsut??z&al?b?c?p??ìlrof&-anesec?anesec???derc?er?f!.sulptp,?m!r??utni??je3a3abgm--nx?kh?l!.&myn,topsgolb,vog??uda??m!.&gro?moc!.topsgolb,?ten?ude???n&a&morockivdnas?ruatser?tnuocca??e&g?m&eganam!.retuor,?piuqe??r??i!.ue?m?opdlog??opud?uocsid??o&b?cs!.vog,?d?g?h?j?oferab?p&edemoh?s???p!.&emon?gro?lbup?m&oc?yn,?t&en?ni?opsgolb,?ude?vog???r&a!m&law?s???epxe?op&er?pus!.ysrab,?s???s!.&adaxiabme?e&motoas?picnirp?rots??gro?lim?mo&c?n,?o&c?dalusnoc?hon,?ten?ude?vog??a&cmoc?f??e&b?padub?r?uq??i!rolf?tned??o&h!.&duolcp,etiseerf,flah,s&pvtsaf,seccaduolc,?tsafym,??p!sua???urt??t!.&eman?gro?ibom?levart?m&oc?uesum??o&c?fni?r&ea?p???pooc?sboj?t&en?ni??ude?vog?zib??ayh?n?o!bba?irram???uognah?xen?y?ztej??u&2&5te9--nx?yssp--nx??a!.&a&s?w??civ?d&i?lq??fnoc?gro?moc!.topsgolb,?nsa?ofni?sat?t&ca?en?n??ude!.&a&s?w??ci&lohtac?v??dlq?sat!.noitacude??t&ca?n??wsn!.sloohcs????vog!.&a&s?w??civ?dlq?sat???wsn?zo??ti??c!.&fni?gro?moc?ten?ude?vog??i??d&e!.tir.segap-tig,?iab??e!.&dcym,enozgniebllew,noitatsksid,snd&ps,uolc,?ysrab,??g!.&bew?gro?m&aug?oc??ofni?ten?ude?vog???h!.&0002?a&citore?idem?kitore??edszot?gro?ilus?letoh?m&alker?lif?t?urof??naltagni?o&c?ediv?fni?levynok?nisac??pohs?rarga?s&a&kal?zatu??emag?wen??t&lob?opsgolb,rops??virp?xe&s?zs??ytic?zsagoj??os?sut??l!.&myn,topsgolb,??m!.&ca?gro?moc?oc?ro?ten?vog???n!.&duolcesirpretne,eni&esrem,m,?mon,tenkcahs,?em!.ysrab,??o&ggnaw?y!c???r!.&a&i&kymlak,rikhsab,vodrom,?yegyda,?bps,ca,eniram,g&bc,ro,?ianatsuk,k&ihclan,s&m,rogitayp,??li&amdlc.bh,m,?moc,natsegad,onijym,pp,ri&b,midalv,?s&ar,itym,?t&en,ni,opsgolb,set,?ude,vo&g,n,?ynzorg,zakvakidalv,?myc?p?ug??s!.&a&d&golov,nagarak,?gulak,i&groeg,kymlak,lerak,nemra,rikhsab,ssakahk,vodrom,zahkba,?lut,rahkub,vut,yegyda,znep,?bps,da&baghsa,rgonilest,?gunel,i&anatsuk,hcos,ovan,ttailgot,?k&alhsygnam,ihclan,s&legnahkra,m,n&a&mrum,yrb,?i&buytka,nbo,??tiort,vorkop,??l&ocarak,ybmaj,?myn,na&gruk,jiabreza,ts&egad,hkazak-&htron,tsae,???ovonavi,r&adonsark,imidalv,?t&enxe,nek&hsat,mihc,??vo&hsalab,n,?ynzorg,z&akvakidalv,emret,??t&amok?i&juf?masih????v!.&gro?moc?ten?ude???ykuyr??v&b?c!.topsgolb,?ed!.&enilnigol,ppa-rettalp,srekrow,vr&esi,uc,???ih?l!.&di?fnoc?gro?lim?mo&c?n,?nsa?ten?ude?vog???m!.&eman?gro?lim?m&oc?uesum??o&fni?r&ea?p???pooc?t&en?ni??ude?vog?zib???o&g?m??rt?s!.&bog?der?gro?moc?ude???t!.&bew-eht-no,naht-&esrow,retteb,?sndnyd,?d?gh?i?won??uqhv--nx??w&a!.moc?hs?l??b!.&gro?oc???c!.&gro?moc?ten?ude??cp??e&iver!.oby,?n?s??g?k!.&bme?dni?gro?moc?ten?ude?vog???m!.&ca?gro?m&oc?uesum??oc?pooc?t&en?ni??ude?vog?zib??b??o&csom?h!s??n?w??p!.&344x,de?en?mon,o&c?g??ro?snduolc,ualeb???r!.&ca?gro?lim?oc?pooc?ten?vog??n??t!.&a46oa0fz--nx?b&82wrzc--nx?ulc??emag?gro?l&im?ru,?m&oc!.reliamym,?yn,?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??zibe?業商?織組?路網???z!.&ca?gro?lim?oc?vog????x&a!t??c!.&hta,ofni,vog???e&d&ef?nay??ma!nab??rof?s??ilften?jt?m!.&bog?gro?m&oc?yn,?t&en?opsgolb,?ude??g?ma2ibgy--nx??o&b!x??f?rex!ijuf???rbgn--nx?s!.&myn,vog???x&am&jt?kt??x???y&4punu--nx?7rr03--nx?a&d!i&loh?rfkcalb??ot??g?lp?p!ila??rot?ssin?wdaorb??b!.&fo?lim?m&oc!.topsgolb,?yn,?vog??ab?gur??c!.&ca?dtl?eman?gro?m&oc!.topsgolb,?t??orp?s&egolke?serp??t&en?nemailrap??vog?zib??amrahp?nega??d&dadog?uts??e&kcoh?ltneb?n&dys?om?rotta??snikcm??g!.&gro?m&oc?yn,?oc?ten?ude?vog??olonhcet!.oc,?rene??hpargotohp?id?k!.&gro?moc?ten?ude?vog??s??l!.&clp?d&em?i??gro?hcs?moc?ten?ude?vog??f?imaf!nacirema??l&a?il??ppus??m!.&eman?gro?lim?moc?t&en?opsgolb,?ude?vog??edaca!.laiciffo,?ra??n&a&ffit?pmoc!ylimafa???os??o&j?s??p!.&gro?lim?moc?pooc?ten?ude?vog???r&e&corg?grus?llag?viled??lewej?otcerid?tnuoc?uxul??s!.&gro?lim?moc?ten?ude?vog??pil??t&efas?i&c!.gn,?ledif?n&ifx?ummoc!.&bdnevar,murofym,???r&ahc?uces??srevinu??laer?r&ap!.oby,?eporp??uaeb??u!.&bug?gro?lim?mo&c!.topsgolb,?n,?ten?ude??b!tseb???van!dlo??xes??z&a!.&eman?gro?lim?moc?o&fni?rp??pp?t&en?ni??ude?vog?zib???b!.&az,gro?m&o&c?n,?yn,?ten?ude?vog???c!.&4e,inum.duolc.&rsu,tlf,?m&laer,urtnecatem.&duolc,motsuc,??oc,topsgolb,??d!.&gro?lop?moc?ossa?t&en?ra??ude?vog???ib!.&duolcsd,e&ht-rof,mos-rof,rom-rof,?lpb,nafamm,p&i&-on,fles,?ohbew,tfym,?retteb-rof,snd&nyd,uolc,?xro,?g??k!.&gro?lim?m&oc?yn,?ten?ude?vog???m!.&ca?gro?lim?oc?ten?ude?v&da?og????n!.&asq-irom--nx?ca?gro?htlaeh?i&r&c?o&am?ām???wi!k???keeg?l&im?oohcs??myn,neg?oc!.topsgolb,?t&en?nemailrap?vog???a!niflla???rawhcs?s!.&ca?gro?oc???t!.&c&a?s??e&m?n??ibom?l&etoh?im??o&c?fni?g??ro?vt???u!.&gro?moc?oc?ten??rwon??yx!.&etisgolb,gnitfarc,otpaz,ppahf,??zub??λε?υε?авксом?брс!.&гро?до?ка?р&бо?п!у?????г&б?ро??дкм?зақ?итед?килотак?леб?мок?н&йално?ом??рку?сур?тйас?фр?юе?յահ?םוק?اي&روس?سيلم?ناتيروم??بر&ع?غملا??ة&كبش?ي&دوعسلا?روس??یدوعسلا??ت&ا&راما?لاصتا??را&ب?ڀ?ھب???ر&ئازجلا?ازاب?صم?طق??سنوت?عقوم?قارع?ك&تيب?يلوثاك??موك?ن&ا&تس&كاپ?کاپ??دوس?ر&يا?یا??مع?يلعلا??درالا?ميلا?ي&رحبلا?طسلف???ه&ارمه?يدوعسلا??وكمارا?يبظوبا?ۃیدوعسلا?टेन?त&राभ?ोराभ??नठगंस?मॉक?्मतराभ?ত&রাভ?ৰাভ??ালংাব?ਤਰਾਭ?તરાભ?ତରାଭ?ாயித்நஇ?ைக்ஙலஇ?்ரூப்பக்ஙிச?్తరాభ?ತರಾಭ?ംതരാഭ?ාකංල?มอค?ยทไ!.&จิกรุธ?ต็นเ?ร&ก์คงอ?าหท??ลาบฐัร?าษกึศ???ວາລ?ეგ?なんみ?アトス?トンイポ?ドウラク?ムコ?ル&グーグ?ーセ??ン&ゾマア?ョシッァフ??业企?东广?乐娱?亚基诺?你爱我?信中?务政?动移?博微?卦八?厅餐?司公?品食?善慈?团集?国中?國中?址网?坡加新?城商?宝珠?尚时?山佛?店&商?网?酒大里嘉??府政?康健?息信?戏游?拉里格香?拿大?教主天?机手?构机!织组??标商?歌谷?浦利飞?港香!.&人個?司公?府政?絡網?織組?育教???湾台?灣&台?臺??物购?界世?益公?看点?科盈訊電?站网?籍書?线在?络网?网文中?聘招?表手?販通?车汽众大?逊马亚?通联?里嘉?锡马淡?門澳?门澳?闻新?電家?국한?넷닷?성삼?컴닷??"); + TrieParser.parseTrie( + "a&0&0trk9--nx?27qjf--nx?e9ebgn--nx?nbb0c7abgm--nx??1&2oa08--nx?apg6qpcbgm--nx?hbbgm--nx?rdceqa08--nx??2&8ugbgm--nx?eyh3la2ckx--nx?qbd9--nx??3&2wqq1--nx?60a0y8--nx??4x1d77xrck--nx?6&1f4a3abgm--nx?2yqyn--nx?3np8lv81qo3--nx?5b06t--nx?axq--nx?ec7q--nx?lbgw--nx??883xnn--nx?9d2c24--nx?a&a?it??b!.&gro?lim?moc?t&en?opsgolb,?ude?vog??abila?c?ihsot?m?n??c!.&b&a?m?n??c&b?g?q??ep?fn?k&s?y??ln?no?oc,pi-on,sn?t&n?opsgolb,?un?ysrab,?i&ma?r&emarp?fa??sroc??naiva?s??d&ats?n&eit?oh??om?sa?tl??eg?f&c?ob??g!emo?naripi?oy??hskihs?i&cnal?dem?hs?k!on??sa!.snduolc,??jnin?k&aso?dov?ede?usto??l!.&c,gro?m&oc?yn,?ofni?r&ep?nb,?t&en?ni??ude?vog??irgnahs?le&nisiuc?rbmuder???m!.&ca?gro?oc?sserp?ten?vog??ahokoy?e00sf7vqn--nx?m??n!.&ac?cc?eman?gro?ibom?loohcs?moc?ni?o&c?fni?rp??r&d?o??s&u?w??vt?xm??av?is?olecrab?tea??p!.&bog?ca?d&em?ls??g&ni?ro??mo&c?n??oba?ten?ude??c?g7hyabgm--nx?ra!.&461e?6pi?iru?nru?rdda-ni?siri???s??q!.&eman?gro?hcs?lim?mo&c?n,?t&en?opsgolb,?ude?vog???r&az?emac?f4a3abgm--nx?n!d5uhf8le58r4w--nx??u&kas?tan???s!.&bup?dem?gro?hcs?moc?ten?ude?vog??ac!.uban.iu,?iv??t&ad?elhta?led?oyot??u!.&a&cinniv?emirc?i&hzhziropaz?stynniv??s&edo?sedo??tlay?vatlop??bs?c&c,inimod??d&argovorik?o!roghzu??tl,?e&hzhziropaz?nvir?t??f&i?ni,?g&l?ro??hk?i&stvinrehc?ykstynlemhk??k&c?m?s&nagul?t&enod?ul??v&iknarf-onavi?orteporp&end?ind?????l&iponret?opotsa&bes?ves??p??m&k?oc?s?yrk??n&c?d?i?osrehk?v?ylov??o&c,nvor??p&d?p,z??r&c?imotihz?k?ymotyhz??sk?t&en?l?z??ude?v:c?e&alokin?ik??i&alokym?hinrehc?krahk?vl?yk??k?l?o&g!inrehc??krahk??r?,y&ikstinlemhk?mus?s&akrehc?sakrehc?tvonrehc???z&ib,u????v!aj?bb?et?iv??waniko?x&a?iacal??yogan?z&.&bew?c&a?i&n?rga???gro?l&im?oohcs??m&on?t??o&c!.topsgolb,?gn??radnorg?sin?t&en?la??ude?vog?wal??zip???b&00ave5a9iabgm--nx?1&25qhx--nx?68quv--nx?e2kc1--nx??2xtbgm--nx?3&b2kcc--nx?jca1d--nx??4&6&1rfz--nx?qif--nx??96rzc--nx??7w9u16qlj--nx?88uvor--nx?a&0dc4xbgm--nx?c?her?n?ra?t??b!.&erots?gro?moc?o&c?fni??ten?ude?v&og?t??zib??a??c&j?s??d&hesa08--nx?mi??ec?g?l!.&gro?moc?ten?ude?vog??m??s!.&gro?moc?ten?ude?vog???tc-retarebsnegmrev--nx?u&lc!.&snduolc,y&nop,srab,??smas??p!.ysrab,??wp-gnutarebsnegmrev--nx??c&1&1q54--nx?hbgw--nx??2e9c2czf--nx?4&4ub1km--nx?a1e--nx?byj9q--nx?erd5a9b1kcb--nx??779tbp--nx?8&4xx2g--nx?c9jrb2h--nx??9jr&b&2h--nx?54--nx?9s--nx??c&eg--nx?h3--nx?s2--nx???a!.&gro?lim?moc?ten?ude?vog??3a09--nx!.&ca1o--nx?gva1c--nx?h&ca1o--nx?za09--nx??ta1d--nx?ua08--nx???da??b&a?b?ci?f76a0c7ylqbgm--nx?sh??c!.&eugaelysatnaf,gnipparcs,liamwt,revres-emag,s&nduolc,otohpym,seccaptf,??0atf7b45--nx?a1l--nx??e!.&21k?bog?dem?gro?lim?m&oc?yn,?nif?o&fni?rp??ten?ude?vog??beuq?n?smoc?tnamys??fdh?i&l&buperananab?ohtac??n&agro?ilc?osanap??tic??l!.&gro?m&oc?yn,?oc?ten?ude?vog?yo,?l??m!.&mt?ossa??p1akcq--nx??n!.&mon?ossa??i?p??relcel?s!.&gro?moc?ten?ude?vog??c??t!s?w??v!.&e0,gro?lim?mo&c?n,?ten?ude?v&g:.d,,og???q??wp?yn??d&2urzc--nx?3&1wrpk--nx?c&4b11--nx?9jrcpf--nx???5xq55--nx?697uto--nx?75yrpk--nx?9ctdvkce--nx?a!.mon?d?er?olnwod??b2babgm--nx?c!.vog?g9a2g2b0ae0chclc--nx??e&m!bulc??r!k??sopxe?timil?w??fc?g!.mon,?h&d3tbgm--nx?p?t??i!.&ased?bew?ca?hcs?lim?o&c!.topsgolb,?g??ro?sepnop?ten?ym?zib??ar?b?ordna?p?rdam??l&iub?og?row??m!.topsgolb,?n&a&b?l!.citats:.&setis,ved,?,lohwen?raas???ob?uf??o&of?rp??r&a&c&tiderc?yalcrab??ugnav??ef506w4b--nx?k!.&oc,ude,?jh3a1habgm--nx??of??s!.&dem?gro?moc?ofni?ten?ude?v&og?t???m!kcrem???t!.topsgolb,excwkcc--nx?l??uolc!.&atcepsrep,drayknil,nworu,r&epolroov,opav,?xelpciffart,??za5cbgn--nx??e&1&53wlf--nx?7a1hbbgm--nx?ta3kg--nx??2a6a1b6b1i--nx?3ma0e1cvr--nx?418txh--nx?707b0e3--nx?a!.&ca?gro?hcs?lim?mon,oc?t&en?opsgolb,?vog??09--nx??b!.&ca?gnitsohbew,topsgolb,?ortal?ut!uoy???c&a&lp!.oc,?ps!.&lla4sx,rebu,slootiknil,tsafym,?artxe??sla??i!ffo??n&a&d?iler?nif?rus&e?ni!efil?srelevart????eics!.oby,??rofria??d!.&1sndnyd,42pi-nyd,7erauqs,amil4,brb-ni,decalpb,e&daregtmueart,mohsnd,nihcamyek,?hcierebsnoissuksid,keegnietsi,lsd-ni,moc,n&-i-g-o-l,aw-ym,esgnutiel,i&emtsi,lreb-n&i,yd,??oitatsksid-ygolonys,pv&-n&i,yd,?nyd,??orp-ytinummoc,p&h21,iog:ol,,?r&e&ntrapdeeps.remotsuc,su&-lautriv,lautriv,?t&adpusnd,tub-ni,uor-ym,?vres&-e&bucl,mohym,?bew-emoh:.nyd,,luhcs,??ogiv-&niem,ym,??s&d-&onys,ygolonys,?nd&-&dd,nufiat,sehcsimanyd,tenretni,yard,?isoc.nyd,ps,yard,?oper-&nvs,tig,?sndd:.&nyd,sndnyd,?,?topsgolb,vresi-&niem,tset,?xi2,y&awetag-&llawerif,ym,?srab,tic-amil,?zten&mitbel,sadtretteuf,??a&lg?rt!.oby,??i&s&doow?ruoyno??ug?wnoitan??nil?on--nx??e!.&bil?dem?eif?gro?irp?kiir?moc!.topsgolb,?pia?ude?vog??ei?ffoc?gg?r&f?ged???f&a&c?s??il!tem???g!.&gro?lim?mo&c?n,?t&en?vp??ude?vog??a&f?gtrom?p!.ycvrp,?rots?yov??elloc?na&hcxe?ro??roeg?ug??i!.&myn,topsgolb,vog??tilop?v&bba?om???j!.&gro?oc?ten???k!.&c&a?s??e&m?n??ibom?mon,o&c!.topsgolb,?fni?g??ro??i&b?l?n???l&a&dmrif?s!.rof,rof???b&a?i&b?dua???c&aro?ric??dnik?g!oog??i&bom?ms??l&asal?erauqa??ppa?uhcs?yts!efil???m!.&4&32i,pct,?66c,ailisarb,b&dnevar,g-raegelif,?ca?duolcsd,e&d-raegelif,i&-raegelif,lpad:.tsohlacol,,??g&ro?s-raegelif,?hctilg,k&catsegde,uoc,?myn,noitatsksid,o&bmoy,c!ku,?t&nigol,poh,??p&ion,j-raegelif,ohbew,?r&aegelif,ofsnd,?s&dym,ndd,ti??t&en?s&acdnuos,ohon,??u&a-raegelif,de?tcn,?v&irp?og??y&golonys,olpedew,srab,??a&g?n!.&reh.togrof,sih.togrof,???em?i&rp?twohs??o&htathgir?rhc??w??n!goloc?i&lno!.ysrab,?w??o!.&derno:.gnigats,,knilemoh,rof,?hp?latipac?ts&der?e&gdirb?rif???z!.&66duolc,amil,sh,???ruoblem??om?p!.&bog?gro?lim?m&o&c?n??yn,?t&en?opsgolb,?ude??irg?yks??r!.&mo&c?n??ossa?topsgolb,?a&c!htlaeh??pmoc?wtfos??bc?eh?if?ots?taeht?u&ces?sni?t&inruf?necca??za???s!.&a?b!ibnal?rofmok??c!a??d!b?n&arb?ubroflanummok???e?f!noc,?g!ro??h!f??i!trap??k!shf??l?m!oc,t??n!mygskurbrutan??o?p!p??r?s!serp??t!opsgolb,?u?vhf?w?x!uvmok??y?z??a&c?el?hc??i&er?urc??nesemoh?roh?uoh??t&a&d?ts&e!laer??lla???is!.&areduolc,enilnigol,n&eyb,oyc,?spvtsaf,xulel,ysrab,?bew??ov?ra?t&ioled?ol??utitsni??u&lb?qi&nilc?tuob???v!.&21e?b&ew?og??ce&r?t??erots?gro?lim?m&oc?rif??o&c?fni??stra?t&en?ni??ude?vog??as?e3gerb2h--nx?i&l?rd?ssergorp??ol??w&kct--nx?r??xul??f&0f3rkcg--nx?198xim--nx?280xim--nx?617upk--nx?7vqn--nx?a!.&gro?mo&c?n,?ten?ude?vog???b!.vog?wa9bgm--nx??c!.topsgolb,a1p--nx?ns??ea1j--nx?fo?g?iam?l&a1d--nx?og??n!.&bew?cer?erots?m&oc?rif??ofni?re&hto?p??stra?ten???orp?p!.&gro?moc?ude???rus?t!w??vd7ckaabgm--nx?w??g&2&4wq55--nx?8zrf6--nx??3&44sd3--nx?91w6j--nx!.&a5wqmg--nx?d&22svcw--nx?5xq55--nx??gla0do--nx?m1qtxm--nx?vta0cu--nx????455ses--nx?5mzt5--nx?69vqhr--nx?7&8a4d5a4prebgm--nx?rb2c--nx??a!.&gro?mo&c?n??oc?ten??vd??b!.&0?1?2?3?4?5?6?7?8?9?a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t!opsgolb,?u?v?w?x?y!srab,?z???c!b?za9a0cbgm--nx??e!.&eman?gro?ics?lim?moc!.topsgolb,?nue?ten?ude?vog??a??g!.&ayc,gro?lenap:.nomead,,oc?saak,ten???i&a?v??k!.&gro?lim?moc?ten?ude?vog???m!.&drp?gro?lim?m&o&c?n??t??oc?ude?vog??pk??n!.&dtl,eman?gro?hcs?i!bom??l&im?oc,?m&oc!.topsgolb,?rif,?neg,ogn,ten?ude?vog??aw?i!b!mulp??car?d&art?dew??h&sif?tolc??k&iv?oo&b?c???ls?n&aelc?iart??p!pohs??re&enigne?tac??t&ad?ekram?hgil?lusnoc?neg?ov?soh!.tfarcnepo,?tebdaerps??vi&g?l???o!s??u&rehcisrev?smas?tarebsnegömrev???o&d?lb?og!.duolc,??r&2n084qlj--nx?ebmoolb?o!.&77ndc.c:sr,,a&remacytirucesym,t&neimip,sivretla,?z,?d&ab-yrev-si,e&sufnocsim,vas-si,?nuof-si,oog-yrev-si,uolc&arfniarodef,mw,??e&a,cin-yrev-si,grof&loot,peh,?l&as-4-ffuts,poeparodef,?m&-morf,agevres,ohruoyslles,?n&ozdop,uma.elet,?r&ehwongniogyldlob,iwym,uces-77ndc.nigiro.lss,?t&adidnac-a-si,is&-ybboh,golb,???fehc-a-si,golbymdaer,k&eeg-a&-si,si,?h,nut,?l&i&amwt,ve-yrev-si,?lawerif&-ym,ym,?sd-ni,?m&acssecca,edom-elbac,?n&af&blm,cfu,egelloc,lfn,s&citlec-a-si,niurb-a-si,tap-a-si,?xos-a-si,?o&itatsksid,rviop,?pv-ni,?o&jodsnd,tp&az,oh,??p&i&-on,fles,?o&hbew,tksedeerf,?tf&e&moh,vres,?ym,??r&e&gatop,ppepteews,su-xunil-a-si,?gmtrec,vdmac,?s&a&ila&nyd,snd,?nymsd,?b&alfmw,bevres,?dylimaf,eirfotatophcuoc,gulku,j,koob-daer,ltbup,nd&-won,deerf,emoh,golb,kcud,mood,nyd:.&emoh,og,?,ps,rvd,tog,uolc,?s&a-skcik,ndd,?tnemhcattaomb,u,?t&ce&jorparodef.&duolc,gts.so.ppa,so.ppa,?riderbew,?e&ews-yrev-si,nretni&ehtfodne,fodne,??hgink-a-si,igude,oi-allizom,s&ixetn&od,seod,?o&h-emag,l-si,?rifyam,??ue:.&a&-q,c,?cm,dc,e&b,d,e,i,m,s,?g&b,n,?hc,i&f,s,?k&d,m,s,u,?l&a,i,n,p,?n&c,i,?o&n,r,ssa,?pj,r&f,g,h,k,t,?s&e,i:rap,,u,?t&a,en,i,l,m,ni,p,?u&a,de,h,l,r,?vl,y&c,m,?z&c,n,??,vresnyd,x&inuemoh,unilemoh,?y&limafxut,srab,???ub&mah?oj???s!.&gro?moc?rep?t&en?opsgolb,?ude?vog??gb639j43us5--nx??t?u!.&c&a?s??en?gro?mo&c?n,?o&c?g??ro?topsgolb,??v!.mon,a1c--nx??wsa08--nx??h&0ee5a3ld2ckx--nx?4wc3o--nx!.&a&2xyc3o--nx?3j0hc3m--nx?ve4b3c0oc21--nx??id1kzuc3h--nx?l8bxi8ifc21--nx?rb0ef1c21--nx???8&8yvfe--nx?a7maabgm--nx??b!.&gro?moc?ten?ude?vog??mg??c!.&7erauqs,amil4,duolc-drayknil,gniksnd,ph21,sndtog,topsgolb,xi2,ytic-amil,?aoc?et?ir!euz??r&aes!errecnac??uhc??sob?taw!s???d0sbgp--nx?f&2lpbgm--nx?k??g!.&gro?lim?moc?ude?vog???iesac?m!a1j--nx??ocir?p!.&gro?i?lim?moc?ogn?ten?ude?vog???s!.&g&nabhsah,ro??lim?moc?ten?vog?won,yolpedew,?a&c?nom??i&d?f?ri???t!.&ca?enilno,im?ni?o&c?g??pohs,ro?ten??iaf!.oby,?laeh?orxer?ra&ba?e???vo!.lopdren,?zb??i&3tupk--nx?7a0oi--nx?a!.&ffo?gro?mo&c?n,?ten?uwu,?1p--nx?bud?dnuyh?tnihc??b!.&gro?moc?oc?ro?ude??ahduba?o!m!.&duolcsd,ysrab,???s??c!.&ayb-tropora--nx?ca?d&e?m??esserp?gro?moc?nif,o&c?g?ssa??ro?t&en?ni?roporéa??ude?vuog??cug?t??d&dk?ua??e&bhf--nx?piat??f!.&aw5-nenikkh--nx,dnala?iki,nenikkäh,topsgolb,yd,?onas??g!.&d&om?tl??gro?moc?ude?vog???h&c&atih?ra??s&abodoy?ibustim???juohs?k!.&gro?moc?ofni?ten?ude?vog?zib??b4gc--nx?iw?nisleh?s?uzus??l!.&aac,m&on,yn,?topsgolb,?drahcir?iamsi??maim?n!.&b&ew?og??ca?gro?lim?mo&c?n??ni?o&c?fni??pp?t&en?ni??ude?zib??airpic?i&hgrobmal?m??re??om?rarref?s!.&mon,topsgolb,?ed??t&aresam?i&c?nifni??rahb?tagub??ut?v!.&21k?gro?moc?oc?ten???wik?xa&rp?t??yf??j&6pqgza9iabgm--nx?8da1tabbgl--nx?b!.&ossa?topsgolb,uaerrab?vuog???d?f!.&ca?eman?gro?lim?moc?o&fni?rp??ten?vog?zib???nj?s?t!.&bew?c&a?in??eman?gro?lim?mo&c?n,?o&c?g??t&en?ni?set??ude?vog?zib???yqx94qit--nx??k&8uxp3--nx?924tcf--nx?arfel?c&a&bdeef?lb??ebdnul?ilc?reme?ud??d!.&erots,ger,mrif,oc,topsgolb,zib,?t??e&es?samet??h!.&a&4ya0cu--nx?5wqmg--nx??b3qa0do--nx?cni,d&2&2svcw--nx?3rvcl--nx??5xq55--nx?tl,?g&a0nt--nx?la0do--nx?ro??i&050qmg--nx?7a0oi--nx?xa0km--nx??m&1qtxm--nx?oc?yn,?npqic--nx?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??xva0fz--nx?人&个?個?箇??司公?府政?絡&網?网??織&組?组??织&組?组??络&網?网??育&敎?教???n??i&tsob?vdnas??l!.&bew?c&a?os??dtl?gro?hcs?letoh?moc?nssa?ogn?prg?t&en?ni??ude?vog??at?cd?is??m!.&eman?fni?gro?mo&c?n,?t&en?opsgolb,?ude?vog???n&ab!cfdh?etats?mmoc?t&en?fos??u??i!.gn,l!.&noyc,pepym,??p???oob?p!.&b&ew?og??gro?kog?m&af?oc??nog?ofni?pog?sog?ten?ude?vog?zib???row!.&fo,ot,?ten!.&htumiza,o&c,vra,??doof???s!.&myn,topsgolb,??t?u!.&c&a?lp??d&om?tl??e&cilop?m??gro!.&gul:g,,sgul,??nnoc,o&c!.&e&lddiwg,n&ilnoysrab,ozgniebllew,??krametyb.&hd,mv,?pi-on,topsgolb,vres-hn,ysrab,??rpoc,?shn?ten?vog!.eci&ffoemoh,vres,??ysrab,???l&04sr4w--nx?a!.&gro?lim?mo&c?n,?t&en?opsgolb,?ude?vog??bolg?c?ed?g!el??i&c&nanif!.oc,lpl??os??romem?tnedurp??n&if?oitanretni??t&i&gid!.sppaduolc:.nodnol,,?p&ac?soh???ned?ot??utum!nretsewhtron???c!.&bog?lim?mon,oc?samednerpa?topsgolb,vog???dil?e&datic?n&ahc?nahc!gnikooc?levart?rehtaew???t!ni?ria?tam??vart??f&8f&pbgo--nx?tbgm--nx??a?n??g!.&gro?mo&c?n,?oc?ten?ude?zib,??h&d?op??i!.&21k?ca?fdi?gro?inum?oc!.topsgolb,?ten?vog??a&f?m&e?g?toh???m?r?xil??l&a&b&esab?t&eksab?oof!.fo,???c?mt??e&d?hs??ihmailliw?j??m!.&esserp?gro?moc?ten?ude?v&og?uog????n!.&n&iemodleeutriv,o&med,rtsic,??oc,retsulc-gnitsoh,topsgolb,wsma,yalphk,?o??o&a?btuf?l?o&c!.ed,?hcs!.gn,??rit?u??p!.&a&cin&diws?gel??d&g,ortso?urawon??i&dem?mraw?nydg,?k&elo&guld?rtso??slopolam?tsu?ytsyrut??l&ip?o&kzs?w&-awolats?oksnok????n&img?zcel,?rog&-ai&bab?nelej??j?z??syn?tsaim?w&a&l&eib?i?o??zsraw??o&namil?tainop,??z&eiwolaib?mol???c&e&iw&alselob?o&nsos?rtso???le&im?zrogz???orw,p??d&em,ia?ragrats??e&c&i&lrog?w&ilg,o&hc&arats?orp??klop?tak????yzreibok??i&csjuoniws?ksromop?saldop??l&ahdop?opo??napokaz,tatselaer?z&romop?swozam???g&alble?ezrbo&lok?nrat??ro??hcyzrblaw?i&csomohcurein?grat?klawus??k&e&rut?walcolw??in&byr?diws,sark,?le?o&nas?tsylaib??rob&el?lam??s&als?jazel?nadg,puls?rowezrp???l&colw?e&r?vart??i&am?m???m&o&c?dar?n?tyb??s&g?iruot??t!a???n&a&gaz?nzop,?i&bul?cezczs?lbul,molow?nok?zd&eb?obeiws???uleiw?y&tzslo?z&rtek?seic????o&c,fni?k&celo?zdolk??lkan?n&leim?pek?t&uk?yzczs??z&copo?eing?rowaj???rga?tua?w&ejarg?ogarm???p&e&eb,lks??klwwortso?ohs??romophcaz?sos?t&aiwop?en?opos,ra,sezc??ude?v&irp?og!.&a&p?s!w???bni&p?w??ci?dtiw?essp?fiw?g&imu?u??hiiw?m&igu?rio?u!o???nds?o&ks?p!pu??s?wtsorats??p&a?sp!mk?pk?wk??u&m?p??wk?z??r&ksw?s??s&i?oiw?u?zu??talusnok?w&gzr?i&p?rg?w??m?opu?u!imzw???zouw????w&a&l&corw?sizdow??w??o&golg?k&ark,ul?zsurp??r&az?gew??t&rabul,sugua??z&coks?sezr????xes?y&buzsak?d&azczseib?ikseb??hcyt?n&jes?lod-zreimizak??pal?r&ogt?uzam??walup?zutrak??z&am-awar?c&aprak?iwol?zsogdyb??dalezc?ib?s&i&lak?p??uklo????l??r&as?f?s??s!.&gro?moc?ten?ude?vog???t!.vog??ubnatsi?x3b689qq6--nx?yc5rb54--nx??m&00tsb3--nx?1qtxm--nx?981rvj--nx?a!.&enummoc?gro?moc?oc?t&en?opsgolb,??c!bew??dretsma?e&rts?t!.esruocsid,??fma?rirhs?xq--nx??b!.&gro?moc?ten?ude?vog??i??c!.&moc?oc?ten?vog???d!.&gro?moc?ten?ude?vog???f!i??g!vu96d8syzf--nx??h?i!.&ca?gro?mo&c?n,?o&c!.&clp?dtl???r,?t&en?t??vt??k?rbg4--nx??k!.&drp?e&rianiretev?sserp??gro?lim?m&o&c?n??t??nicedem?ossa?pooc?s&eriaton?neicamrahp?sa??ude?v&og?uog????l&if?ohkcots??o!.&dem?gro?m&oc?uesum??o&c?rp??ten?ude?vog??b?c!.&2aq,3pmevres,a&c&-morf,ir&bafno,fa,??g&-morf,oy-sehcaet,?i-morf,m&-morf,all&-a-si,amai,??p&-morf,c-a-si,?remacytirucesym,s,tadtsudgniht,v-morf,w-morf,z,?b&dnevarym,ew&-sndnyd,ottad,?g,ildts.ipa,?c&amytirucesemoh,d-morf,esyrcs,n&-morf,vym,?p&kroweht,ytirucesemoh,?q,rievres,s-morf,?d&aerotffuts,e&calpb,ifitrec-&si,ton-si,?llortnocduolc,?i-morf,m-morf,n&-morf,abeht-htiw-si,?s-morf,uolc&-noitatsyalp,hr,meaeboda,panqym:-&ahpla,ved,?,smetsystuo,ved&j,pw,??wetomer,?e&butuoyhtiw,ciffo-sndnyd,d:-morf,o&celgoog,n&il.&recnalabedon,srebmem,?neve.&1-&su,ue,?2-&su,ue,?3-&su,ue,?4-&su,ue,????,erf&-sndnyd,sndd,?filflahevres,gnahcxeevres,i&hcet-a-si,p-sekil,?k&auqevres,irtsretnuocevres,?l&bitpa-no,googhtiw,?m&agevres,ina-otni-si,oh-&sndnyd,ta-sndnyd,??n&-morf,ilnoysrab,og-si,?r&alfduolcyrt,ihcec,uzanoppanex,?srun-a-si,t&i&nuarepo,s&-ybboh,aloy,tipohs,??omer-sndnyd,ysgolb,?v&als-elcibuc-a-si,i&lsndd,tavresnoc-a-si,??z&amkcar,eelg,iig,??fehc-a-si,g&ni&gats-swennwot,ksndd,robsikrow,?o&fgp,lb&-sndnyd,sihtsetirw,???h&n-morf,o-morf,?i&fiwehtno,h-morf,kiw-sndnyd,m-morf,r-morf,w-morf,z&ihcppa,nilppa,??jn-morf,k&a&-morf,erfocsic,?cils-si,eeg&-a&-si,si,?sndd,?h,latsnaebcitsale:.&1-&htuos-pa,lartnec-&ac,ue,?ts&ae&-&as,su,?ht&ron-pa,uos-pa,??ew-&su,ue,vog-su,???2-ts&ae&-su,ht&ron-pa,uos-pa,??ew-&su,ue,??3-ts&aehtron-pa,ew-ue,??,o-morf,r&adhtiwtliub,ow&-&sndnyd,ta-sndnyd,?ten-orehkcats,??u,?l&a&-morf,colottad,rebil-a-si,?f-morf,i&-morf,am-sndnyd,?l&ecelffaw,uf-ytnuob:.a&hpla,teb,?,?ppmswa,ru-&elpmis,taen,?ssukoreh,?m&n-morf,pml.ppa,rofererac-htlaeh,sacrasevres,uirarret-yltsaf,?n&a&cilbuper-a-si,f&-sllub-a-si,racsan-a-si,?i&cisum-a-si,ratrebil-a-si,??c,eerg-a-si,i-morf,m-morf,o&ehtnaptog,isam-al-a-tse,ollabtib,rtap-el-tse,s&iam-al-a-tse,replausunu,??pj,t-morf,?o&bordym,c,jodsnd,m-morf,n:iloxip,,ttadym,?p&2pevres,aelutym,i&-sndnyd,fles,ogol,ruoy&esol,hctid,?ymteg,?pa&-rettalp,anis:piv,,esaberif,k1,lortnocduolc,oifilauq,r&aegyks,oetem:.ue,,?tnorfegap,ukoreh,?t&fevres,thevres,??r&a:-morf,tskcor-a-si,,b,e&d&ivorpnwo,ner&.ppa,no,??e&bevres,nigne-na-si,?ggolb-a-si,h&caet-a-si,pargotohp-a-si,?krow-drah-a-si,n&gised-a-si,ia&rtlanosrep-a-si,tretne-na-si,??p&acsdnal-a-si,eekkoob-a-si,?retac-a-si,subq,tn&ecysrab,iap-a-si,uh-a-si,?vres&-s&ndnyd,pvtsaf,?inim,nmad,?y&alp-a-si,wal-a-si,?zilibomdeepsegap,?g,k,mgrp.nex,o&-morf,sivdalaicnanif-a-si,t&c&a-na-si,od-a-si,?susaym,??p-morf,u&as-o-nyd,eugolb-nom-tse,omuhevres,??s&a&ila&nyd,snd,?nymsd,?bbevres,ci&p&-sndnyd,evres,?tcatytiruces,?dylimaf,e&cived-anelab,itilitu3,lahw-eht-sevas,mag-otni-si,tyskciuq,?i&ht2tniop,paelgoog,?k&-morf,aerf-ten,colbpohsym,?m&-morf,cxolb,?n&d&-pmet,dyard,golb,mood,tog,?nyd,ootrac-otni-si,?o&-xobeerf,xobeerf,?ppatneg,r&ac-otni-si,etsohmaerd,?s&e&l-rof-slles,rtca-na-si,?ibodym,?u,wanozama.&1-&htuos-pa&-3s,.&3s,etisbew-3s,kcatslaud.3s,??la&nretxe-3s,rtnec-&ac&-3s,.&3s,etisbew-3s,kcatslaud.3s,??ue&-3s,.&3s,etisbew-3s,kcatslaud.3s,????ts&ae&-&as&-&3s,etisbew-3s,?.kcatslaud.3s,?su:-etisbew-3s,.kcatslaud.3s,,?ht&ron-pa&-&3s,etisbew-3s,?.kcatslaud.3s,?uos-pa&-&3s,etisbew-3s,?.kcatslaud.3s,???ew-&su-&3s,etisbew-3s,?ue&-&3s,etisbew-3s,?.kcatslaud.3s,?vog-su-&3s,spif-3s,????2-ts&ae&-su&-3s,.&3s,etisbew-3s,kcatslaud.3s,??ht&ron-pa&-3s,.&3s,etisbew-3s,kcatslaud.3s,??uos-pa&-&3s,etisbew-3s,?.kcatslaud.3s,???ew-&su-&3s,etisbew-3s,?ue&-3s,.&3s,etisbew-3s,kcatslaud.3s,????3&-tsew-ue&-3s,.&3s,etisbew-3s,kcatslaud.3s,??s,???t&arcomed-a-si,c-morf,eel&-si,rebu-si,?m-morf,n&atnuocca-na-si,e&duts-a-si,r-ot-ecaps,tnocresu&buhtig,elbavresbo.citats,pl,???ops&edoc,golb,ppa,?s&i&hcrana-&a-si,na-si,?laicos-a-si,pareht-a-si,tra-na-si,xetn&od,seod,??oh&piym,sfn,??u&-morf,nyekcoh-asi,?v-morf,?u&-rof-slles,4,e,h,oynahtretramssi,r:ug-a-si,,?v&n-morf,w-morf,?w&ozok,ww100,?x&bsbf.sppa,em,inuemoh,obaniateb,t-morf,unilemoh,?y&a&bnx:.&2u,lacol-2u,?,lerottad,wetag-llawerif,?dnacsekil,filten,k&-morf,niksisnd,?rotceridevitcaym,u:goo,,w-morf,x&alagkeeg,orphsilbup,???inu??m!.&dna,rof,??or?tsla??p!.nwo,?raf!.jrots,etats??s?t!.&gro?lim?mo&c?n??oc?ten?ude?vog???u&esum!.&a&92chg-seacinumocelet-e-soierroc--nx?atnav?c&i&aduj?rfatsae??rollam??d&anac?enomaledasac?irolf??e&raaihpledalihp?srednu??g&hannavas?oonattahc??hamo?i&auhsu?bmuloc!hsitirb??dem?groeg?hpledalihp?l&artsua?etalif??n&igriv?rofilac??ssur?tsonod??ksa&la?rben??l&lojal?q-snl--nx?uossim!trof???m&a&bala?nap??enic?o&m?r???n&a&cirema?idni??edasap?ilorachtuos?olecrab??r&abrabatnas?ezzivs??su?t&nalta?osennim??zalp??c&dnotgnihsaw?ebeuq?i&depolcycne?ficap?hpargonaeco?lbup?sum?t&carporihc?lec?naltadim??vu??yn??d&a&dhgab?etsmraf?m?orliar??i&rdam?ulegnedleeb??leif?n&a!l&gne?nif?ragyduj?t&ocs?rop??yram???u&brofsdgybmeh?osdnaegami???r&augria?ofxo???e&c&a&l&ap?phtrib??ps??n&a&lubma?tsiser??e&fedlatsaoc?gilletni?ics!foyrotsih????pein?rof??d&nukneklov?revasem??e&rt?tsurt??f&atnas?ildliw??g&a&lliv?tireh!lanoitan???dirbmac?rog??i&cnum?nollaw??koorbrehs?l&ab?bib?cycrotom?i&ssim?txet??oks?tsac??m&affollah?it!iram??utsoc??n&golos?ilno?recul??r&a&uqs?waled!foetats???i&hs&acnal?kroy?pmahwen??otsih??omitlab?ut&an?cetihcra?inruf?luc!irga?su???vuol??s&abatad?iacnarf?sius?uoh!lum???t&a&locohc?rak?ts!e!yrtnuoc!su?????imesoy?tevroc??u&qihpargonaeco?velleb??vit&caretni?omotua???f&iuj?ohgrub??g&n&i&dliub?ginerevmuesum?kiv?lahw?nim?peekemit?vil??ulmmastsnuk??orf?r&ebnrats?u&b&ierf?le?m&ah?uan??ram?s&mailliw!lainoloc??naitsirhc?retepts??zlas??ob&irf?mexul?????h&atu?c&raeser?sirotsih?uot??g&ea1h--nx?rubsttip??si&tirb?wej??t&laeh?ro&n?wtrof??uo&mnom?y????i&d6glbhbd9--nx?iawah?k&nisleh?s??lad!rodavlas??sissa?tannicnic??k&c&nivleeg?olc!-dna-hctaw?dnahctaw???fj?inebis?l&is?ofron??na&rfenna?t??oorbnarc?r&am&ned?reiets??oy!wen????l&a&ci&dem?golo&eahcra?meg?oz??natob?rotsih??ertnom?iromem?noita&cude?n??oc?rutluc?trop?utriv?van??e&nurb?s&ab?surb??utriv??i&artnogero?sarb??l&a&besab?hsnoegrus??e&hs?rdnevle??i&b?m!dniw????o&bup?ohcs?tsirb???m&a&dretsma?ets?h&netlehc?rud???ct?elas!urej??l&if?ohkcots?u??raf?silanruoj?u&esumyrotsihlarutan?ira&tenalp?uqa??terobra???n&a&c!irema!evitan???gihcim?i&dni?tpyge??mfoelsi?wehctaksas??e&d&alokohcs?ews?rag!cinatob?lacinatob?s&nerdlihc?u????gahnepoc?hcneum?laftsew?ppahcsnetewruutan?r&dlihc?ednaalv?hu!dnutamieh???sseig??gised!dn&atra?utsnuk???h&ab!nesie??ojts??i&lreb?tsua??l&eok?ocnil??n&ob?urbneohcs??o&dnol?gero?i&s&iv&dnadnuos?elet??nam??t&a&c&inummoc?ude!tra???dnuof?erc?i&cossa?va??kinummokelet?nissassa?r&belectsevrah?oproc?tsulli??silivic?t&nalp?s??vres&erp?noclatnemnorivne??zilivic??c&elloc?if-ecneics??ibihxe???ri?s&dnah?imaj?reffej?sral??t&erbepac?nilc?sob???r&e&b?dom?tsew?uab?zul??obredap??vahnebeok?wot??o&2a6v-seacinumoc--nx?ablib?c&edtra?ixemwen?sicnarfnas??elap?g&a&cihc?to??eidnas??i&cadnuf?diserp?ratno??llecitnom?mitiram?nirot?r&htna?ienajedoir???pohskrow?qari?r&aw!dloc?livic??dd?e&b&ma?yc??irrac?llimsiwel?naksiznarf?papswen?t&aeht?exe?nec!ecneics?larutluc?muesum?tra??s&ehc&nam?or??neum??upmoc???ia!nepo??obal?u&asonid?obal?takirak???s&a&l&g?l&ad?eh???xet??di&k?pardnarg??e&cneics!larutan??dnal?hcsi&deuj?rotsih!nizidem?rutan??selhcs??itinamuh?l&aw?egnasol?l&e&rutansecneics?xurb??iasrev???r&e&em?ugif??tsac??suohcirotsih?u&en?q&adac?itna!nacirema?su????õçacinumoc!elet-e-soierroc???gnirpsmlap?htab?i&lopanaidni?rap?uoltnias?xa??l&essurb?lod??mraeriflanoitan?n&a&blats?l??erdlihc?oi&snam?tacinummoc!elet-dna-stsop???äl??re&dnalf?lttes?mraf?nim?tnececneics??s&alg?erp??t&farc!dnastra??nalp?olip?ra!e&nif?vitaroced!su???su?xuaeb???u&b!muloc??cric???t&agilltrop?cejorp?dats?e&esum?kramnaidni??iorted?ne&m&elttes?norivne?piuqemraf??vnoc??oped?r&a!drib?enif?gttuts?hsiwej?kcor?n&acirema?ootrac??tamsa?yraropmetnoc??op&aes?snart?wen??ufknarf??s&a&cdaorb?octsae??ewhtuos?ilayol?nuk?r&ohnemled?uhlyram??urt???u&a&bgreb?etalpodaroloc??rmyc??w&ocsom?rn??x&esse?ineohp?nam?tas??y&a&bekaepasehc?w&etag?liar???camrahp?doc?e&hsub?l&ekreb?l&av!eniwydnarb??ort???n&dys?om??rrus?s&nreug?rejwen???golo&e&ahcra?g??motne?nh&cet?te??oz?po&rhtna?t??roh??hpargotohp?l&etalihp?imaf??m&edaca?onortsa??n&atob?yn??ps?r&a&ropmetnoc?tilim??e&diorbme?llag!tra??vocsid??lewej?nosameerf?otsih!dnaecneics?ecneics?gnivil!su??la&col?rutan??retupmoc?su??tsudnidnaecneics??spelipe?t&eicos!lacirotsih??i&nummoc?srevinu??nuoc???z&arg?iewhcs?nil?ojadab?urcatnas??моки?םילשורי???rof??z!.&ca?gro?hcs?lim?moc?o&c?fni??ten?ude?vog?zib????n&315rmi--nx?a&brud?cilbuper?f?grompj?hkaga?idraug?m?ol?ssin?u&hix?qna??varac?yalo??b!.&gro?moc?oc,ten?ude?vog??c??c!.&ah?bh?c&a?s??d&5xq55--nx?g?s?uolctnatsni,?eh?g&la0do--nx?ro??h&a?q?s??i&7a0oi--nx?h??j&b?f?t?x?z??kh?l&h?im?j??m&n?oc!.swanozama.&1-htron-nc.3s,be.1-&htron-nc,tsewhtron-nc,????n&h?l?s?y??om?qc?s&g?j??ten?ude?vog?wt?x&g?j?n?s??z&g?x??司公?絡網?络网??b??d&g!.ypnc,?ka??e&drag?erg?fuak?gawsklov?hctik?i&libommi?w??m!.rof,?po?r!ednaalv??sier?ves??g!.&ca?gro?moc?ten?ude?vog??is&ed!.ssb,?irev???h!.&bog?gro?lim?mo&c?n,?ten?ude???i!.&c&a?in??dni?gro?lim?mrif?neg?oc?s&er?nduolc,?t&en?opsgolb,?ude?vog?ysrab,?elknivlac?griv?ks?lreb?p!ul??v?w?x??k!.&gro?ten?ude?vog???l&eok?ocnil??m!.&cyn,gro?myn,ude?vog???o&dnol!.&fo,ni,??i&hsaf!.&fo,no,??n&o?utiderc??siv!orue??t&a&cude!.oc,?dnuof?tsyalp??c&etorp?u&a?rtsnoc?????kin?las?mrom?nac?p&q?uoc??s&iam?nhojcs?pe?scire??t&ron?sob??zama??p!.&gro?oc?ten?ude?vog??k??r&e&c?yab??op??s!.&gro?moc?osrep?t&opsgolb,ra??ude?v&inu?uog????t!.&dni?esnefed?gro?ltni?m&oc!nim??siruot??n&erut?if??o&fni?srep??sn&e?r??t&an?en!irga?ude??rnr??unr?vog??m??u&f?r!.&bdnevar,lper,sh,tnempoleved,??stad?xamay?y??v!.&ca?eman?gro?htlaeh?moc?o&fni?rp??t&en?ni?opsgolb,?ude?vog?zib???wo&rc?t!epac????o&76i4orfy--nx?a!.&bp?de?go?oc?ti?vg??boat??b!.&a&ci&sum?tilop??i&c&arcomed?neic??golo&ce?ncet??m&edaca?onoce??rt&ap?sudni??vilob??n&egidni?icidem??serpme?tsiver?vitarepooc??b&ew?og??dulas?e&rbmon?tr&a?op&ed?snart????g&olb?ro??ikiw?l&a&noi&canirulp?seforp??rutan??im??moc?o&fni?lbeup?rga?tneimivom??saiciton?t&askt?en?ni??ude?vt??h?iew?olg??c!.&bew?cer?dr&c,rac,?gro?ipym,l&im?per,?m&o&c!.topsgolb,?n??rif?udon,?ofni?s&egap&dael,l,?tra??t&4n,en?ni??ude?vog??a?e!vi??in?mara?s&edarb?ic???d!.&b&ew?og??dls?gro?lim?moc?t&en?ra??ude?vog??agoba?if?zd7acbgm--nx??e&c?d&iv?or??morafla??f!ni!.&e&g&delwonk-fo-l&errab,lerrab,?ellocevoli,?ht-skorg,rom-rof-ereh,tadpusn:d,,?llatiswonk,macrvd,ofni-v,p&i&-on,fles,?ohbew,?ruo-rof,s&iht-skorg,nd&-cimanyd,nyd,uolc,??tsrifyam,ysrab,zmurof,???g&el?ia?n!am?ib???hwsohw?i!.&35nyd,8302,a&minifed,tad-b,?b&altig,uhtig,?c&inone:.remotsuc,,zh,?d&in,u&olc&iaznab.ppa,noitacilppa,ropav,?rd,??e&civedniser,donppad.sndnyd,egipa,nilnigol,sufxob,t&isnoehtnap,newtu,??gnigatsniser.secived,k&orgn,ramytefasresworb,?m&oc?udon,?nyded,p&opilol,pa&-arusah,cs,enalpkcab,??r&evres&cisab,lautriv,?ial.sppa,?s&codehtdaer,nemeis-om,pparevelc,tacdnas,?t&enotorp,i&belet,detfihs,kecaps,?raedon.egats,sudgniht.&cersid.tsuc,dorp.tsuc,gnitset.tsuc,ved.tsuc,??vgib.0ku,xcq,y&olpedew,srab,??b?d&ar?u&a?ts???j?r?syhp??j!.&eman?gro?hcs?lim?moc?ten?ude?vog???ll&ag?o??m!.&gro?moc?ten?ude?vog??g?il?mi?orp??n!.&a&0&b-ekhgnark--nx?c-iehsrgev--nx?g-lksedlig--nx?k-negnanvk--nx??1&p-nedragy--nx?q-&asierrs--nx?grebsnt--nx?lado-rs--nx?n&egnidl--nx?orf-rs--nx??regnayh--nx?ssofenh--nx??r-datsgrt--nx?s-ladrjts--nx?v-y&senner--nx?vrejks--nx???3g-datsobegh--nx?4&5-&dnaleprj--nx?goksnerl--nx?tednalyh--nx??6-neladnjm--nx?s-&antouvachb--nx?impouvtalm--nx??y-&agrjnevvad--nx?ikhvlaraeb--nx???7k-antouvacchb--nx?8&k-rekie-erv--nx?l-ladrua-rs--nx?m-darehsdrk--nx??a!.sg??bct-eimeuvejsemn--nx?d&do?iisevvad?lov?narts?uas??f&1-&l--nx?s--nx??2-h--nx??g&10aq0-ineve--nx?av?ev?lot?r&ajn&evvad?u??ájn&evvad?u????h?iz-lf--nx?j&ddadab?sel??k&el?hoj&sarak?šárák??iiv&ag&na&el?g??ŋ&ael?ág???ran???l&f?lahrevo?o&ms?s??sennev?t-&ilm--nx?tom--nx??u&-edr--nx?s??øms??muar?n&0-tsr--nx?2-dob--nx?5-&asir--nx?tals--nx??a&r!-i-om?f?t??t??douvsatvid?kiv?m&os?øs??n&od?ød??ra?sen?t&aouvatheig?ouv&a&c&ch&ab?áb??h&ab?áb???n??i&ag?ág??sa&mo?ttvid??án???z-rey--nx?ær&f?t???o&p-&ladr--nx?sens--nx??q-nagv--nx?r-asns--nx?s-kjks--nx?v-murb--nx?w-&anr&f--nx?t--nx??ublk--nx???ppol?q&0-t&baol--nx?soum--nx?veib--nx??x-&ipphl--nx?r&embh--nx?imph--nx???y-tinks--nx??r&f-atsr--nx?g-&an&ms--nx?nd--nx??e&drf--nx?ngs--nx??murs--nx?netl--nx?olmb--nx?sorr--nx??h-&a&lms--nx?yrf--nx??emjt--nx??i&-&lboh--nx?rsir--nx?y&d&ar--nx?na--nx??ksa--nx?lem--nx?r&ul--nx?yd--nx????stu??j-&drav--nx?rolf--nx?sdav--nx??kua?l-&drojf--nx?lares--nx??m-tlohr--nx?n-esans--nx?olf?p-sdnil--nx?s-ladrl--nx?tih?v-rvsyt--nx??s&a&ns?ons??i&ar?er&dron?r&os?øs???ár??la&g?h??mor!t??sir?uf?åns??t&koulo&nka?ŋká??la?p-raddjb--nx?r-agrjnu--nx?s&aefr&ammah?ámmáh??orf?r&o?ø???u-vreiks--nx??u&h-dnusel--nx?i-&drojfk--nx?vleslm--nx??j-ekerom--nx?k-rekrem--nx?u-&dnalr--nx?goksr--nx?sensk--nx??v-nekyr--nx?w-&k&abrd--nx?ivjg--nx??oryso--nx??y-y&dnas--nx?mrak--nx?n&art--nx?nif--nx??reva--nx??z-smort--nx??v!.sg?ledatskork?reiks??wh-antouvn--nx?x&9-dlofts--nx.aoq-relv--nx?d-nmaherk--nx?f-dnalnks--nx?h-neltloh--nx?i-drgeppo--nx?j-gve&gnal--nx?lreb--nx??m-negnilr--nx?n-drojfvk--nx??y&7-ujdaehal--nx?8-antouvig--nx?b-&dlofrs--nx?goksmr--nx?kivryr--nx?retslj--nx??e-nejsom--nx?f-y&krajb--nx?re&dni--nx?tso--nx??stivk--nx??g-regark--nx?orf?ørf??z9-drojfstb--nx??b&25-akiivagael--nx?53ay7-olousech--nx?a&iy-gv--nx?le-tl&b--nx?s--nx??n0-ydr--nx??c&0-dnal-erdns--nx?z-netot-erts--nx??g&g-regnarav-rs--nx?o-nejssendnas--nx??ju-erdils-ertsy--nx?nj-dnalh-goksrua--nx?q&q-ladsmor-go-erm--nx.&ari-yreh--nx?ednas??s-neslahsladrjts--nx???ca&4s-atsaefrmmh--nx?8m-dnusynnrb--nx?il-tl--nx?le-slg--nx?n5-rdib--nx?op-drgl--nx?uw-ynnrb--nx??d&a&qx-tggrv--nx?reh!nnivk?sd&ork?ørk??uas??ts&e&bi?kkar?llyh?nnan??g&ort?ørt??k&alf?irderf??levev?mirg?obeg&ah?æh??r&ah?ejg????barm-jdddb--nx?ie!rah?s&etivk?ladman???lof&r&os?øs??ts&ev.ednas?o.relav?ø.relåv???n&a&l&-erd&n&os?øs??ron??adroh.so?dron.&a&g5-b--nx?ri-yreh--nx??ob?y&oreh?øreh??øb??e&m!lejh??pr&oj?øj??vi??gyb?n&aks?åks??o&h-goksrua?rf??r&o?ua?ø??tros?øh-goksrua??rts!e&devt?lab?mloh???s&ellil?naitsirk?rof???u&l!os??s!d&im?lejt??e&guah?l&a?å???kkoh?lavk?naitsirk?r&af?eg&e?ie???tef?y&onnorb?ønnørb?????r&a&blavs!.sg??g&eppo?la???o&j&f&a!dniv?k?vk??die?e&dnas?kkelf??llins?r&iel?ots??s&lab?t&ab?åb??yt??å!k??ævk??les??ts??åg&eppo?lå???ureksub.sen??e&ayb-yrettn--nx?d&ar?lom?r&of?øf??år??g&gyr?nats??i&meuv&ejsem&aan?åån??sekaal??rjea??j&d&ef?oks??les??k&er&aom?åom??hgna&ark?årk??iregnir?kot!s??s&ig?uaf???l&bmab?kyb?l&av?ehtats??oh??m&it?ojt?øjt??n&arg?g&os?øs??meh?reil?te?ummok?yrb??r&dils-erts&ev?y&o?ø???ua?vod??sa&ans?åns??t&robraa?spaav??urg??f&62ats-ugsrop--nx?a&10-ujvrekkhr--nx?7k-tajjrv-attm--nx??o!.sg?h??s!.sg??v!.sg???g&5aly-yr&n--nx?v--nx??a&llor?ve&gnal?lreb???n&av!snellu??org??oks&die?m&or?ør??ner&ol?øl??r&o?ø???r&eb!adnar?edyps?s&die?elf?gnok?n&ot?øt????obspras??uahatsla?åve&gnal?lreb???h&0alu-ysm--nx?7&4ay8-akiivagg--nx?5ay7-atkoulok--nx??a!.sg???i&e&hsr&agev?ågev??rf??k&h&avlaraeb?ávlaraeb??s??lm&a?å??mpouvtal&am?ám??pph&al?ál??rrounaddleid?ssaneve?ššáneve??j&0aoq-ysgv--nx?94bawh-akhojrk--nx??k&a&b&ord?ørd??jks?lleis??iv!aklejps?l&am?evs?u??mag?nel?ojg?r&a&l?n??epok?iel?y&or?ør???s&ah?kel?om??øjg??kabene?ojsarak?ram&deh.&aoq-relv--nx?rel&av?åv??so??e&let.&ag5-b--nx?ob?øb??ra???åjks??l&a!d&anrus?d&numurb?ron??e&gnard?nte?s&meh?sin??ttin??g&is?nyl??kro?l&em?l&ejfttah?of??u&ag-ertdim?s???n&am?era?gos?i&b?nroh?r??kos?nus?oj??o-&dron?r&os?øs???ppo?r&a!l?nram??e&gne?l?v??is?o&jts?ts??u&a-&dron?r&os?øs???h??å?æl?øjts??s&e&jg?nivk?ryf??kav?mor-go-er&om.&ednas?yoreh??øm.&ednas?yøreh???uag??t&las?rajh?suan??v&l&a?e-rots??u-go-eron??yt??ksedlig?res&a?å???bib&eklof?seklyf??es!dah??h!.sg??i&m?syrt??l&ejf?ov&etsua?gnit?ksa?sdie???n!.sg??o!.sg?boh?g?h??r!.sg??å!ksedlig??øboh??m&a&rah?vk??f!.sg??h!.sg??i&e&h&dnort?rtsua?ssej??rkrejb??ksa??ol?t!.sg??u&dom?esum?r&ab?drejg?evle?os?uh?æb?øs??ttals???n&a&g&av?okssman?åv??jlis?or?r&g?rev???e&d&do&sen?ton??lah?r&agy&o?ø??ojfsam???g&iets?n&a&l&as?lab??n&avk?ævk??t&arg?ddosen??v&al?essov???i&d&ol?øl??l&ar?ær???yl??reb??iks?k&srot?y&or?ør???l&a&d&gnos?n&er?ojm?øjm??om??tloh??ug?åtloh??mmard?ojs&om?sendnas??ppolg?s&lahsladr&ojts?øjts??o??t&o&l?t-erts&ev?o?ø???roh?øl??vly&kkys?nav??yam-naj!.sg??øjs&om?sendnas???g&orf?ujb??i&dnaort?vnarg??kob?ladendua?maherk&a?å??n&it?urgsrop??orf-&dron?r&os?øs???r&aieb?evats??sfev?uaks?yrts??o&6axi-ygvtsev--nx?c,d&ob?rav??ievs?kssouf?l&m&ob?øb??ous&adna?ech&ac?áč???so!.sg???msdeks?niekotuak?r&egark?olf?y&oso?øso???s&dav?mort???p&ed?p&akdron?elk???r&a&d&dj&ab?áb??iab??jtif?luag?mah?vsyt??e&gn&a&k&iel?ro??merb?n&at?mas??rav-r&os?øs??srop?talf?v&ats?el??y&oh?øh???ivsgnok??il?jkniets?k&a&nvej?rem?s&gnir?nellu???ie-er&den?v&o?ø???ram?sa?årem??la&jf?vh??m&b&ah?áh??mahellil??nnul?ts&l&oj?øj??ul??y&o?ø???imp&ah?áh??m!.sg??osir?t!.sg??ádiáb?ævsyt?øsir??s&adnil?en&dnas?e&dga?k&ri&b?k??som??ve??me&h?jg??nroh-go-ejve?s&a?ednil?k&o?ø??of?yt?å??tsev??gv?hf?igaval?o&r&or?ør??sman??so&fen&oh?øh??m?v??uh&lem?sreka.sen??å!dnil???t&a&baol?g&aov?grav??jjr&av-attam?áv-attám??l&a&b?s??ás??soum?ts?v&eib?our???e&dnaly&oh?øh??f?s&nyt?rokomsdeks?sen??vtpiks??in&aks?áks??loh&ar?år??n!.sg??o&m&a?å??psgolb,?s!.sg?efremmah?or?ør??terdi?á&baol?ggráv?lá&b?s??soum?veib???u&b!.sg?alk?e&dna?gnir?nner??les?ælk??dra&b?eb??g&nasrop?vi?ŋásrop??j&daehal&a?á??jedub?v&arekkhar?árekkhár???ksiouf?n&diaegadvoug?taed???v&irp?lesl&am?åm???y&b&essen?nart?sebel?tsev??o&d&ar?na!s??or??gavtsev?k&rajb?sa??lem?mrak?n&art?n&if?orb???r&a&mah?n?v??e&dni?t&so?ton??va??ul?yd??s&am?enner?gav?lrak?tivk??vrejks??ø&d&ar?na!s??ør??gåvtsev?k&rajb?sa??lem?mrak?n&art?n&if?ørb???r&e&dni?t&so?tøn??va??ul?yd?æ&n?v???s&enner?gåv?tivk?åm??vrejks???á&slág?tlá?vreiks??å&gåv?h?jddådåb?lf??ø&d&ob?rav??r&egark?olf??s&dav?mort????aki?i&sac?tal??u??o&b?f?g?hay?o?ttat??r!.&cer?erots?gro?m&o&c?n??rif?t?yn,?ofni?pohs,stra?t&n?opsgolb,?www??e&a!.&a&ac?cgd?idem??bulc!orea??ci&ffartria?taborea??e&cn&a&l&lievrus-ria?ubma??netniam?rusni??erefnoc??gnahcxe?mordorea?ni&gne?lria?zagam??rawtfos??gni&d&art?ilg!arap?gnah???l&dnahdnuorg?ledom??noollab?retac?sael?t&lusnoc?uhcarap??vidyks??hcraeser?l&anruoj?euf?icnuoc?ortnoc!-ciffart-ria???n&gised?oi&nu?t&a&cifitrec?ercer?gi&tsevni-tnedicca?van??i&cossa!-regnessap??valivic??redef??cudorp?neverp-tnedicca????ograc?p&ihsnoipmahc?uorg!gnikrow???r&e&dart?enigne?korb?niart?trahc??o&htua?tacude???s&citsigol?e&civres?r??krow?serp!xe??tnega??t&farcr&ia?otor??hgil&f?orcim??liubemoh?n&atlusnoc?e&duts?m&esuma?n&iatretne?revog??piuqe????olip?ropria?si&lanruoj?tneics???w&erc?ohs??y&cnegreme?dobper?tefas????rref?z??p!.&a&aa?ca?pc??dem?ecartsnd.icb,gne?r&ab?uj??snduolc,t&acova?cca?hcer??wal?ysrab,???s!.&em?gro?hcs,moc?ten?ude?vog???t!.&ayo,gro?lim?moc?sulpnpv,t&cennockciuq.tcerid,en??ude?vog??o&hp?m?v?yk??tol?ua??v&iv?lov??xas?ykot??p&a&ehc?g?m?s??cj?eej?g!.&gro?ibom?moc?ossa?ten?ude???i&r!.nalc,?v?z??j!.&a&3&5xq6f--nx?xqi0ostn--nx??5wtb6--nx?85uwuu--nx?9xtlk--nx?bihc!.&a&bihciakoy?don?ma&him?ye&ragan?tat???r&a&bom?gan?hihci??u&agedos?kas?ustak???s&os?ufomihs??t&amihcay?iran??w&a&g&im&anah?o??omak??kihci?zustum??ihsak??y&agamak?imonihci???e&akas?nagot??i&azni?esohc?h&asa?s&abanuf?ohc???ka&to?zok??musi?orihs?r&akihabihsokoy?o&dim?tak??ukujuk??usihs??nano&hc?yk??o&d&iakustoy?ustam??hsonhot?k&a&rihs?t??iba??nihsaran?sobimanim?tas&arihsimao?imot??uhc?yihcay??u&kujno?s&ayaru?t&imik?tuf???zarasik????g&as!.&a&gas?m&a&tamah?yik??ihsak??rat?t&a&gatik?hatik??ira!ihsin????e&kaira?nimimak??i&akneg?g&aruyk?o??h&c&amo?uo??siorihs??kaznak?modukuf?ra&gonihsoy?mi???nezih?u&k&at?ohuok??s&ot?tarak?????ihs!.&a&kok?m&a&hagan?yirom??ihsakat??rabiam?wagoton??e&miharot?nokih??houyr?i&azaihsin?esok?kustakat?moihsagih??na&mihcahimo?nok??o&hsia?mag?t&asoyot?ok?tir???us&ay?t&asuk?o??????k&aso!.&a&d&awihsik?eki??k&a&noyot?s&akaayahihc?oihsagih???oadat?uziak??m&ayas!akaso??odak??r&a&bustam?wihsak??ediijuf??t&akarih?i&k?us???wag&ayen?odoyihsagih???e&son?tawanojihs??honim?i&akas?h&cugirom?s&ayabadnot?i&a&kat?t??n??oyimusihsagih???k&a&rabi?sim??ustakat??muzi?r&ijat?otamuk???nan&ak?n&ah?es???o&ay?n&a&ganihcawak?simuzi?tak??eba?ikibah?oyot??t&anim?iad?omamihs??uhc??ust&oimuzi?tes????ou&kuf!.&a&d&amay?eos??g&no?ok?usak??hiku?k&awayim?uzii??ma&kan?y&asih?im???rawak?t&a&gon?ka&h?num?t???umo??wa&g&a&kan?nay?t??ias??ko!rih???y&ihsa?usak???e&m&ay?uruk??taruk?us??i&a&nohs?raihcat??goruk?h&cukuf?s&a&gih?hukuy??in???k&a&gako?muzim??iust?o?ustani??m&anim?otihsoynihs?u??r&ogo?ugasas??usu??ne&siek?zu&b?kihc???o&gukihc?h&ak?ot?ukihc??j&ono?ukihc??kayim?nihsukihc?to?uhc??u&fiazad?gnihs?stoyot????zihs!.&a&bmetog?d&amihs?eijuf?ihsoy?omihs??kouzihs?mihsim?ra&biah?honikam??tawi?wa&g&ekak?ukik??kijuf??yimonijuf??i&a&ra?sok??hcamirom?juf?kaz&eamo?ustam??ma&nnak?ta??nukonuzi?orukuf??nohenawak?o&nosus?ti??u&stamamah?z&a&mun?wak??i!ay?i&hs&agih?in??manim??mihs????????m&a&tias!.&a&d&ihsoy?ot?usah??k&a&dih?sa??o&arihs?s???m&a&tias?y&as?o&rom?tah??ustamihsagih???i&hsagurust?jawak??uri??ni?wa&g&e&ko?man??ikot?o??k&ara?i&hsoy?mak???ru?zorokot??y&a&g&amuk?ihsok?otah??kuf??imo??ziin??e&bakusak?ogawak?sogo?ttas?zokoy??i&baraw?h&cugawak?s&oyim?ubustam???iroy?k&ato?ihs?u&k?stawi???m&akoyr?i&hsoy?juf??uziimak???naznar?o&dakas?ihsay?jnoh?n&a&go?nim??imijuf?nah?oy??r&ihsayim?otagan??t&asim!ak??igus?omatik??zak??u&bihcihc!ihsagih??sonuok?ynah????y&ak&aw!.&a&d&ira?notimak??kadih?ma&h&arihs?im??y&a&kaw?tik??oduk???ru&ustakihcan?y??sauy?wa&g&a&dira?zok??orih??konik??yok?zok??e&banat?dawi??i&garustak?jiat?mani??naniak?o&bog?nimik?t&asim?omihs&ah?uk????ugnihs???o!.&a&jos?koasak?m&ay&ako?ust??ihsayah??r&abi?ukawaihsin??wi&aka?nam???e&gakay?kaw??i&gan?h&cu&kasa?otes??sahakat??k&asim?ihsaruk??miin??n&anemuk?ezib??o&hsotas?jnihs?n&amat?imagak??ohs?uhcibik?????ot!.&a&damay?got?koakat?may&etat?ot??nahoj?riat?waki&inakan?reman???eb&ayo?oruk??i&h&asa?ciimak?sahanuf??kuzanu?m&an&i?ot??ih???nezuyn?otnan?u&hcuf?stimukuf?z&imi?ou???????ihs&o&gak!.&a&m&ayuok?ihsogak??si?yonak??e&banawak?n&at&akan?imanim??uka??tomoonihsin??i&adnesamustas?k&azarukam?oih??m&ama?uzi??usuy??nesi?o&knik?os?tomustam??uzimurat???rih!.&a&ka&n?s??m&ayukuf?i&hsorihihsagih?j&ate?imakikaso????r&a&bohs?h&ekat?im???es??tiak?wiad??e&kato?ruk??i&h&ci&akustah?mono?nihs??s&inares?oyim???manimasa?uk??negokikesnij?o&gnoh?namuk??uhcuf????uk&ot!.&a&bihci?mi&hsu&kot?stamok??m??wagakan??egihsustam?i&gum?h&coganas?soyim??kijaw?m&anim?uzia??ukihsihs??nan&a?iak??o&nati?turan????uf!.&a&batuf?m&a&to?y&enak?irok???ihs&im?ukuf??os?uko??r&aboihsatik?uganat??ta&katik?mawak?rih??w&a&g&akus?emas?uy??k&a&mat?rihs?sa??ihsi??nah??ohs???e&gnabuzia?iman?ta&d?tii???i&adnab?enet?hs&agih?iimagak??k&a&wi?zimuzi??ubay??minuk?r&ook?ustamay???nihsiat?o&g&etomo?ihsin?nan?omihs??no!duruf?rih??rihsawani?ta&may?simuzia???u&rahim?stamakawuzia?zia&ihsin?nay???????nug!.&a&bawak?doyihc?k&anna?oi&hsoy?juf?mot???m&ayakat?ustagaihsagih??n&ihsatak?nak??r&ahonagan?nak?o?u&kati?mamat???t&amun?inomihs?o??w&akubihs?iem?ohs???i&hsa&beam?yabetat??kas&akat?esi??m&akanim?uzio??ogamust?rodim??o&jonakan?n&eu?oyikust??tnihs??u&komnan?stasuk?yrik?????ran!.&a&bihsak?d&akatotamay?u!o???guraki?m&ay&atik&imak?omihs??irokotamay??oki??ra&hihsak?n??wa&geson?knet???e&kayim?ozamay?sog?ustim??i&a&rukas?wak??garustak?h&ciomihs?sinawak??jo?ka&mnak?toruk??makawak?nos?r&net?otakat?ugeh???o&d&na?oyo??gnas?jnihs?nihsoy!ihsagih??tomarawat?yrok????t&ag&amay!.&a&dihsio?k&atarihs?ourust??may&a&kan?rum??enak?onimak??rukho?ta&ga&may?nuf??hakat?kas??wa&g&ekas?orumam??ki&hsin?m??z&anabo?enoy?ot???zuy??e&agas?bonamay?dii?nihsagih?o??i&a&gan?nohs??h&asa?sinawak??nugo??o&dnet?jnihs?ynan??ukohak???iin!.&a&ga?k&ium?oagan??munou!imanim??t&a&bihs?giin??ioy??w&a&gioti?kikes?zuy??irak??yijo??e&kustim?mabust??i&aniat?hcamakot?kaz&awihsak?omuzi??m&a&gat?karum??o???n&anust?esog??o&das?ihcot?jnas?k&ihay?oym??mak?naga?ries??u&ories?steoj?????i&ka!.&a&go?k&asok?oimak??t&ago!rihcah??ika!atik???w&aki?oyk???e&mojog?natim?suranihsagih?t&ado?okoy???i&hsoyirom?magatak?naokimak??nesiad?o&hakin?jnoh!iruy??nuzak?rihson?tasi&juf?m??yjnoh??u&kobmes?oppah????o!.&a&dakatognub?m&asah?ihsemih??su?t&ekat?i&h?o????e&onokok?ustimak??i&jih?k&asinuk?ias?usu??mukust??onoognub?u&fuy?juk?ppeb?suk??????wa&ga&k!.&a&mihsoan?rihotok?waga&kihsagih?ya???emaguram?i&j&nonak?ustnez??kunas?monihcu??o&hsonot?nnam?yotim??u&st&amakat?odat??zatu????nak!.&a&dustam?kus&okoy?tarih??maz?nibe?r&a&gihsaimanim?h&esi?imagas??wa&do?guy???u&im?kamak???tikamay?wa&k&ia?oyik?umas??sijuf??yimonin??e&nokah?saya??i&akan?esiak?gusta?hsuz?kasagihc?o?ukust??o&nadah?sio?tamay?????kihsi!.&a&danihcu?gak?kihs?mijaw?t&abust?ikawak??wazanak??i&gurust?hcionon?mon?ukah??nasukah?o&anan?ton!akan???u&kohak?stamok?z&imana?us?????niko!.&a&han?m&arat?ijemuk?uru??n&e&dak?zi??no??ra&hihsin?rih??wa&kihsi?niko??yehi?zonig??e&osaru?seay??i&hsagih?jomihs?k&a&gihsi?not??ihsakot??m&a&ginuk?kihsug?maz??igo?otekat??nuga!noy???n&a&moti?timoy?wonig??i&jikan?k???o&gan?jnan?tiad&atik?imanim???u&botom?kusug&akan!atik??imot??rab&anoy?eah???????c&204ugv--nx?462a0t7--nx?678z7vq5d--nx?94ptr5--nx?a??d&17sql1--nx?3thr--nx?5&20xbz--nx?40sj5--nx??7&87tlk--nx?ptlk--nx??861ti4--nx?a?e??e&16thr--nx?5&1a4m2--nx?9ny7k--nx??im!.&a&bot?k&asustam?uzus??m&a&him?y&emak?im???ihs??nawuk?wi&em?k???e&bani?ogawak?si!imanim???i&arataw?gusim?h&asa?ciakkoy??k&a&mat?sosik?t??iat??raban??o&dat?hik?n&amuk?ihseru?o&du?mok????ust???mihe!.&a&m&a&h&ataway?iin??yustam??ij&awu?imak???taki!man???ebot?i&anoh?kasam?rabami??n&ania?egokamuk?oot??o&jias?kihcu?nustam?uhcukokihs?yi!es???u&kohik?zo????n!.&nriheg,teniesa.resu,?amihs!.&a&d&amah?ho?usam??kustay?m&a?ihsoni&hsin?ko???wakih??e&namihs?ustam??i&g&aka?usay??konikak?mikih??nannu?o&mu&kay?zi!ihsagih?uko???nawust?tasim??u&stog?yamat?????tawi!.&a&bahay?d&amay?on??koirom?t&a&honat?katnezukir??imus??w&as&ijuf?uzim??ihs???e&hon&i&hci?n??uk??tawi??i&a&duf?murak?wak??h&custo?si&amak?ukuzihs???j&oboj?uk??k&a&m&anah?uzuk??sagenak??esonihci??m&akatik?uzia&rih?wi????o&kayim?no&rih?t??tanufo??uhso????g&3zsiu--nx?71qstn--nx?l??h&03pv23--nx?13ynr--nx?22tsiu--nx?61qqle--nx??i&54urkm--nx?g&ayim!.&a&dukak?m&a&goihs?kihs??ihsustam!ihsagih??unawi??r&awago?iho??ta&bihs?rum??w&a&gano?kuruf??iat??y&imot?ukaw???e&mot?nimes??i&hsiorihs?ka&monihsi?s&awak?o???mak?r&ataw?o&muram?tan????o&az?jagat?t&asim?omamay???u&fir?k&irnasimanim?uhsakihcihs?????ihcot!.&a&g&a&h?kihsa??ust??kom?m&ay&o?usarak??unak??r&a&boihsusan?watho??iho?ukas??t&akihsin?iay??wa&konimak?zenakat??y&imonustu?oihs???e&iiju?kustomihs?nufawi??i&akihci?g&etom?ihcot?on???o&k&ihsam?kin??nas?sioruk?tab??u&bim?san?????h&c&ia!.&a&dnah?m&a!h&akat?im??yuni??ihs&ibot?ust???r&a&hat?tihs??ik?u&ihsagih?kawi???t&ihc?o&k?yot???wa&koyot?zani??yi&monihci?rak???e&inak?k&aoyot?usa??manokot?noyot??i&a&gusak?kot?sia??eot?h&asairawo?cugo?s&ahoyot?oyim???k&a&mok?zako??ihssi??motay?rogamag??n&an&ikeh?ok??ihssin??o&got?ihsin?jna?rihsnihs?suf?tes??u&bo?raho?s&oyik?takihs??yrihc?zah????ok!.&a&dusay?kadih?mayotom?r&ah&im?usuy??umakan??sot!ihsin??wa&g&atik?odoyin??k&as?o????i&esieg?hco!k??jamu?k&a!sus??usto??ma&gak?k??rahan??o&mukus?n&i?ust!ihsagih???torum?yot!o???u&koknan?zimihsasot????ugamay!.&a&m&ayukot?ihso??toyot??e&bu?subat??i&gah?kesonomihs?nukawi?rakih??nanuhs?otagan?u&ba?foh?otim?stamaduk?uy?????sanamay!.&a&dihsoyijuf?mayabat?r&ahoneu?ustakihsin??w&a&k&ayah?ijuf??suran??ohs???egusok?i&ak?h&cimakan?s&anamay?od???k&asarin?u&feuf?sto????o&k&akanamay?ihcugawakijuf??nihso?t&asimawakihci?ukoh??uhc??spla-imanim?u&b&nan?onim??fok?hsok?rust?????ka&rabi!.&a&bukust?gok?kan!ihcatih??m&a&sak?timo?wi??ihsak?ustomihs??ni?r&a&hihcu?way??u&agimusak?ihcust???t&ag&amay?eman??oihcatih??w&ag&arukas?o??os??yi&moihcatih?rom???e&bomot?dirot?not?tadomihs??i&a&k&as?ot??rao??esukihc?gahakat?h&asa?catih??k&a&rabi?saguyr??ihsani?uy??ma?rukustamat??o&dnab?giad?him?kati?rihsijuf?soj?t&asorihs?im??yihcay??u&fius?kihsu?simak????sagan!.&a&m&abo?ihsust??natawak?r&abamihs?u&mo?ustam???wijihc?yahasi??i&akias?hies?k&asagan?i??masah??neznu?o&besas?darih?t&eso?og!imaknihs????ust&igot?onihcuk?uf????zayim!.&a&biihs?guyh?k&oebon?ustorom??mihsuk?r&emihsin?uatik??ta&katik?mim??wag&atik?odak??ya??e&banakat?sakog??i&hsayabok?kaza&kat?yim??m&animawak?ot&inuk?nihs????nanihcin?o&j&ik?onokayim??n&ibe?ust??tias??urahakat????ro&moa!.&a&dawot?turust?wasim??e&hon&ihc&ah?ihs??nas?og?ukor??sario??i&anarih?ganayati?hsioruk?jehon?kasorih?makihsah?nawo?r&amodakan?omoa???o&gnihs?kkat??u&ragust?stum????ttot!.&a&r&ahawak?uotok??sa&kaw?sim???egok?irottot?nanihcin?o&ganoy?nih?tanimiakas??u&bnan?z&ay?ihc??????ukuf!.&a&deki?gurust?ma&bo?h&akat?im??yustak??sakaw??eabas?i&akas?ho?jiehie?ukuf??nezihce!imanim??ono????k&26rtl8--nx?4&3qtr5--nx?ytjd--nx??522tin--nx?797ti4--nx??l33ussp--nx?m&11tqqq--nx?41s3c--nx??n&30sql1--nx?65zqhe--nx?n7p7qrt0--nx??o&131rot--nx?7qrbk--nx?c?diakkoh!.&a&deki?gakihset?hcebihs?k&adih?u&fib?narihs???m&ayiruk?hot?ihs&orihatik?ukuf??oras?usta??r&ib&a!ka??o?uruf??ozo?u&gakihsagih?oyot???sakim?ta&gikust?mun??w&a&ga&k&an?uf??nus!imak???k&aru?i&h&asa?sagih??kat?mak??omihs?um??zimawi??ine?oyk??yot??e&a&mustam?nan??b&a&kihs?yak??o&noroh?to???ian?k&ihsam?ufoto??nakami?ppoko!ihsin??sotihc?tad!okah??uonikat??i&a&bib?mokamot?n&a&k&kaw?oroh??wi??eomak?ihsatu?okik?usta&moruk?sakan????eib?h&c&ioy?u&bmek?irihs???s&ase?ekka?oknar?uesom???jufirihsir?k&amamihs?i&at?n???m&atik?otoyot??oa&kihs?rihs??r&a&hs?kihsi?mot??ihs&aba?ir??otarib???n&a&hctuk?rorum?se?tokahs??uber??o&kayot?m&ire?ukay??naruf!ima&k?nim???orih?r&ih&ibo?suk??o&bah?h&i&b?hsimak??sa??pnan?yan??umen??t&asoyik?eko?ukoh???u&bassa?kotnihs?m&assaw?uo??pp&akiin?en&ioto?nuk??ip??rato?s&akat?t&eb&e?i&a?hs!a??robon??m&e?o&m?takan???no&h?tamah??o&mik?s?t??u&kir?ppihc?st???onihsnihs?ufuras??uaru??yru!koh??zimihs!ok?????g!oyh!.&a&bmat?dnas?gusak?k&at?o&oyot?y??uzarakat??m&ayasas?irah??wa&g&ani?okak??k&i&hci?mak??oy???yi&hsa?monihsin???i&asak?hs&aka?i&at?nawak???j&awa!imanim??emih??k&a&goa?s&agama?ukuf??wihsin??i&hsog?m???mati?oia?rogimak??n&annas?esnonihs??o&gasa!kat??ka?n&ikat?o?ustat??rihsay?sihs?tomus?yas??u&bay?gnihs?????nagan!.&a&bukah?d&a&w?yim??e&ki?u??ii??k&a&s&ay?uki??zus??ihsoo?ousay??m&ay&akat?ii??i&hsukufosik?jii??ukihc??n&i!hsetat??uzii??r&ah?ugot??saim?t&agamay?oyim??w&a&g&a&kan?n??o??kustam?ziurak??onim!imanim??u&koo?s!omihs????ya&ko?rih???e&akas?nagamok?subo??i&gakat?h&asa?c&a!mo!nanihs???uonamay??sukagot??k&a&kas?mimanim?to??ia&atik?imanim??oa?uzihcom??m&akawak?ijuf?o!t???r&ato?ijoihs?omakat???n&ana?esnoawazon??o&hukas?n&a&gan?kan??i&hc?muza??ustat??romok?si&gan?k??tomustam??u&k&as?ohukihc??stamega????to&mamuk!.&a&gamay?rahihsin?sukama!imak??tamanim??enufim?i&hcukik?k&ihsam?u??nugo!imanim??romakat??o&ara?rihsustay?sa?t&amay?om&amuk?us??u!koyg???yohc??u&sagan?zo????yk!.&a&bmatoyk?k&ies?oemak?uzaw??mayi&h&cukuf?sagih??muk??nihsamay?rawatiju?t&away?ik???e&ba&nat!oyk??ya??di?ni??i&ju?kazamayo?manim??natnan?o&gnatoyk?kum?mak?rihsamayimanim?y&gakan?ka&koagan?s??oj???u&ruziam?z&ayim?ik??????wtc1--nx?ykot!.&a&d&i&hcam?mus??oyihc??k&atim?ihsustak??m&a&t!uko??yarumihsa&gih?sum???i&hs&agoa?ika?o!t??uzuok??ren???r&a&honih?wasago??iadok?umah??ssuf?t&ik?o??wa&g&anihs?ode??k&ara?ihcat???y&agates?ubihs???e&amok?donih?m&o?urukihsagih??soyik??i&enagok?gani?h&ca&da?tinuk??sabati??j&nubukok?oihcah??manigus??o&huzim?jihcah?n&akan?ih!sasum??urika??rugem?t&a&mayihsagih?nim??iat?ok??uhc?yknub??u&fohc?hcuf?kujnihs?????r&2xro6--nx?g?o??s&9nvfe--nx?xvp4--nx??t&netnocresu,opsgolb,?u&4rvp8--nx?fig!.&a&d&eki?ih??kimot?m&ayakat?ihsah??ne?raha&gi&kes?makak??sak??taga&may?tik??wa&g&ibi?ustakan??karihs!ihsagih????e&katim?uawak??i&gohakas?hc&apna?uonaw??k&ago?es?ot??m&anuzim?ijat??nak?urat??nanig?o&dog?jug?makonim?nim?roy?sihcih??u&fig?s&otom?t&amasak?oay???????x5ytlk--nx?yu6d27srjd--nx?z72thr--nx?井福?京東?分大?取鳥?口山?城&宮?茨??媛愛?山&富?岡?歌和??岡&福?静??島&児鹿?広?徳?福??崎&宮?長??川&奈神?石?香??庫兵?形山?手岩?木栃?本熊?根島?梨山?森青?潟新?玉埼?田秋?知&愛?高??縄沖?良奈?葉千?賀&佐?滋??道海北?都京?重三?野長?阜岐?阪大?馬群???k!.&art?gro?moc?per?ude?vog???l&eh?l??m!ac?j??nd?o&g?h&pih?s!.ysrab,??lnud?oc?t!.&lldtn,snd-won,???pa!.&arusah,enilnigol,nur:.a,,t&ibelet,xenw,?yfilten,??ra&a?hs??u&ekam?llag?org!.esruocsid,cts?kouk?nayalo???vsr?xece4ibgm--nx??q&a!3a9y--nx??g?i!.&gro?lim?moc?ten?ude?vog???m?se??r&a!.&acisum?bog?gro?lim?moc!.topsgolb,?rut?t&en?ni??ude?vog??4d5a4prebgm--nx?b?c?eydoog?los?t&at?s!uen???ugaj??b!.&21g?a&b&a&coros?iuc??itiruc??cnogoas?dicerapa?gniram?i&naiog?ramatnas??n&erom?irdnol??op?p&acam?irolf?ma&j?s???rief?tsivaob??b!aj?mi?sb??c&ba?er?js?sp?t!e???d&em?mb?n&f?i??rt??e&dnarganipmac?ficer?ht?llivnioj?rdnaotnas??f&dj?ed?gg?ni??g&el!.&a&b,m,p,?bp,c&a,s,?e&c,p,s,?fd,gm,ip,jr,la,ma,nr,o&g,r,t,?p&a,s,?r&p,r,?s&e,m,r,?tm,??l&s?z??n&c?e?o??ol&b?f?v??pp?ro??hvp?i&du?kiw?nana?oretin?r&c?eurab??sp?te?xat??l&at&an?rof??el?im?sq??m&a?da?e&gatnoc?leb??f?ic?oc!.topsgolb,??nce?o&ariebir?c&e?narboir?saso??d&o?ranreboas??et?i&b?dar?ecam?r??rp?t&a?erpoir???p&m!e?t??ooc?se??qra?r&af?ga?o&davlas?j??tn?ut??s&a&ixac?mlap?nipmac??u&anam?j?m???t&am?e&n?v??nc?o&f?n??ra?sf??u&caug9?de?ja?rg??v&da?og!.&a&b?m?p??bp?c&a?s??e&c?p?s??fd?gm?ip?jr?la?ma?nr?o&g?r?t??p&a?s??r&p?r??s&e?m?r??tm???rs?t??xiv?z&hb?ls?of????c!.&as?ca?de?if?o&c?g??ro???e&bew?ccos?dnik?e&b?n&igne?oip??rac??gni&arg?rheob??h&cor?sok?t&aew?orb???itnorf?k&col?o&p?rb???l&aed?ffeahcs??mal?nes?pinuj?t&a&eht?rebsnegömrev??law?nec?s&acnal?nom?ubkcolb??upmoc??v&o&c&sid?tfiws??rdnal??resbo??wulksretlow?ywal?zifp??f!.&aterg?bew-no,drp?e&c&itsuj-reissiuh?narf-ne-setsitned-sneigrurihc,?rianiretev??i&cc?rgabmahc??m&o&c?n??t??n&eicamrahp?icedem??ossa?s&e&lbatpmoc-strepxe?riaton?tsitned-sneigrurihc?uova??o&-x&bf,obeerf,?x&bf,obeerf,???t&acova?o&or-ne,psgolb,?r&epxe-ertemoeg?op!orea????vuog??avc7ylqbgm--nx?s??g!.&gro?m&oc?yn,?t&en?opsgolb,?ude?vog???h!.&e&erf,man??mo&c?rf??topsgolb,zi??ur??i!.&a&61f4a3abgm--nx?rf4a3abgm--nx??ca?di?gro?hcs?oc?ten?vog?نار&يا?یا???a&h?per??ew?lf??k!.&c&a?s??e&n?p?r??gk?iggnoeyg?kub&gn&oeyg?uhc??noej??l&im?uoes??man&gn&oeyg?uhc??noej??n&as&lu?ub??o&e&hcni?jead??wgnag???o&c?g??ro?s&e?h?m??topsgolb,u&gead?j&ej?gnawg????cilf??l!.&gro?moc?ten?ude?vog???m!.&topsgolb,vog???n!.&gro?moc?ofni?ten?ude?vog?zib???o&cs?htua?odtnorf?t&c&a?od??laer???p!.&alsi?ca?eman?forp?gro?moc?o&fni?rp??t&en?se??ude?vog?zib???s?t!.&21k?bew?cn!.vog??eman?gro?kst?l&e&b?t??im?op??moc!.topsgolb,?neg?ofni?pek?rd?sbb?ten?ude?v&a?og?t??zib??f?m??ubad?vd??s&8sqif--nx?9zqif--nx?a!.vog?birappnb?gev?lliv?mtsirhc?s??b!.&ew,gro?moc?ten?ude?vog??c?oj?s?u??c&i&hparg?p?t&sigolyrrek?ylana???od??d&a?d?l?n&iwriaf?omaid??oogemoh?rac??e!.&bog?gro?mo&c!.topsgolb,?n??ude??civres!.enilnigol,?d&d2bgm--nx?oc??h&ctaw?guh??i&lppus?rtsudni?treporp!yrrek???jaiv?l&aw?cycrotom?etoh?gnis?pats??m&ag?oh?reh??nut?ohs?picer?r&it?ut&cip!.7331,?nev???s!i&rpretne?urc??ruoc??taicossa?vig??g!nidloh??h5c822qif--nx?i!.&ekacpuc,gro?moc?t&en?ni?opsgolb,?ude?vog??a09--nx?nnet?rap?targ??k&c&or!.&ecapsbew,snddym,ytic-amil,??us??hxda08--nx?row??l!.&c&a?s??gro?o&c?fni??ten?ude?vog?zib??a&ed?tner??e&ssurb?toh!yrrek???lahsram?m?oot??m!.&bal,gro?moc?ten?ude?vog??b?etsys!.tniopthgink,?ialc??n&a&f?gorf?ol??egassap?i&a&grab?mod??giro??o&it&acav?cudorp?ulos??puoc???o&dnoc?geuj?leuv?ppaz?t&ohp?ua???p!.&ces?gro?moc?olp?ten?ude?vog??i&hsralohcs?lihp?t??u??r!.&au,ca?gro?mon,ni?oc?topsgolb,ude?vog?xo,?a&c?p?tiug??c?e&dliub?erac?gor?levart?mraf?n&niw?trap??wolf??ot&cartnoc?omatat??pj?uot??s!.&gro?moc?ten?ude?vog?zib??alg?e&n&isub!.oc,?tif??rp!xe!nacirema???xnal??iws??t&a&e&b?ytic??ob??ek&cit?ram??fig?h&cay?gilf??n&atnuocca?e&mt&rapa?sevni??ve!.oc,???rap??u!.&a&c!.&21k?bil?cc???g!.&21k?bil?cc???i!.&21k?bil?cc???l!.&21k?bil?cc???m!.&21k!.&hcorap?rthc?tvp???bil?cc???p!.&21k?bil?cc???si?v!.&21k?bil?cc???w!.&21k?bil?cc????c&d!.&21k?bil?cc???n!.&21k?bil?cc???s!.&21k?bil?cc????d&ef?i!.&21k?bil?cc???m!.&21k?bil?cc???n!.&bil?cc???s!.&bil?cc???urd,?e&d!.&21k?bil,cc???las-4-&dnal,ffuts,?m!.&21k?bil?cc???n!.&21k?bil?cc????h&n!.&21k?bil?cc???o!.&21k?bil?cc????i&h!.&bil?cc???m!.&21k?bil?c&c?et??goc?n&eg?otae??robra-nna?sum?tsd?wanethsaw???nd?r!.&bil?cc???v!.&21k?bil?cc???w!.&21k?bil?cc????jn!.&21k?bil?cc???k&a!.&21k?bil?cc???o!.&21k?bil?cc????l&a!.&21k?bil?cc???f!.&21k?bil?cc???i!.&21k?bil?cc????mn!.&21k?bil?cc???n&afflog,i!.&21k?bil?cc???m!.&21k?bil?cc???sn?t!.&21k?bil?cc????o&c!.&21k?bil?cc???m!.&21k?bil?cc???ttniop,?p&ion,rettalp,?r&a!.&21k?bil?cc???o!.&21k?bil?cc???p!.&21k?bil?cc????s&a!.&21k?bil?cc???dik?k!.&21k?bil?cc???m!.&21k?bil?cc???nd&deerf,uolc,??t&c!.&21k?bil?cc???m!.&21k?bil?cc???u!.&21k?bil?cc???v!.&21k?bil?cc????ug!.&21k?bil?cc???v&n!.&21k?bil?cc???w!.cc???x&ohparg,t!.&21k?bil?cc????y&b-si,k!.&21k?bil?cc???n!.&21k?bil?cc???w!.&21k?bil?cc????za!.&21k?bil?cc????ah!uab??bria?col?e!.ytrap.resu,?ineserf?lp?xe&l?n???vt?w!.&66duolc,gro?moc?s&ndnyd,tepym,?ten?ude?vog??a?e&iver?n??odniw??y&alcrab?cam?ot???t&0srzc--nx?a!.&amil4,ca!.hts??gni&liamerutuf,tsoherutuf,?o&c!.topsgolb,?fni,?ph21,ro?v&g?irp,?xi2,ytic-amil,zib,?c?e!s??hc?if?l!asite??mami?rcomed??b!.&gro?moc?ten?ude?vog??b?gl??c&atnoc?e&les?rid!.lenaptsaf,txen????dimhcs?e!.&eman?gro?moc?ofni?ten?ude?vog?zib??b?em?grat?id?k&circ?ram??n!.&5inu,6vnyd,7&7ndc.r,erauqs,?a&l&-morf,moob,?minifed,remacytirucesym,tadsyawla,z,?b&boi,g,lyltsaf:.pam,,?c&inagro-gnitae,paidemym,?d&ecalpb,nab-eht-ni,uolc&meaeboda,xednay:.e&garots,tisbew,?,??e&cnarusnihtlaehezitavirp,ht-no-eciffo,l&acsnoom,ibom-eruza,?m&ecnuob,ohtanyd,tcerider,?nozdop,rehurht,s,tis-repparcs,zamkcar,?f&aeletis,crs.&cos,resu,?ehc-a-si,?g&ni&reesnes,tsohnnylf,?olbevres,?k&eeg-a&-si,si,?u,?l&acolottad,iamwt,s&d-ni,s-77ndc,??m&ac&asac,ih,?urofniem,?n&a&f&agp,lhn,?ibed,?dcduabkcalb,i,pv-ni,?o&c-morf,jodsnd,rp-ytinummoc,ttadym,?p&i&-&etsef,on,?emoh,fles,nwo,?j,mac-dnab-ta,o&-oidar-mah,hbew,?paduolc,tfe&moh,vres,?usnd,?r&e&tsulcyduolc,vres-xnk,?vdslennahc:.u,,?s&a&ila&nyd,snd,?nymsd,?bbevres,dylimaf,e&suohsyub,t&isbeweruza,ys,??kekokohcs,n&d&-won,d,golb,npv,?oitcnufduolc,?s&a-skcik,ecca&-citats,duolc,???t&ceffeym,e&nretnifodne,smem,?farcenimevres,i-&ekorb,s&eod,lles,teg,??n&essidym,orfduolc,?r0p3l3t,s&ixetnod,ohgnik,??u&h,nyd,r,?x&inuemoh,spym,unilemoh,?y&awetag-llawerif,ltsaf.&dorp.&a,labolg,?lss.&a,b,labolg,?pam,slteerf,?n&-morf,ofipi,?srab,tieduolc,?z&a-morf,tirfym,???p?tcip?v??f&ig?o&l?sorcim???g!.&bog?dni?gro?lim?mo&c?n,?ten?ude???h!.&dem?gro?l&er?op??m&oc?rif??o&fni?rp?s&rep?sa???po&hs?oc??t&en?luda?ra??ude?vuog???i!.&a&2n-loritds--nx?7e-etsoaellav--nx?8&c-aneseclrof--nx?i-lrofanesec--nx??at?b?c!cul??dv?i&blo&-oipmet?oipmet??cserb?drabmol?g&gof?urep??l&gup?i&cis?me&-oigger?oigger???uig&-&aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf???aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf????n&a&brev?cul?pmac?tac??idras?obrac&-saiselgi?saiselgi??resi??otsip?r&b&alac!-oigger?oigger??mu??dna&-&attelrab-inart?inart-attelrab??attelrabinart?inartattelrab?ssela??epmi?ugil??tnelav&-obiv?obiv??vap?z&e&nev?ps&-al?al???irog???l&iuqa!l??leib??m&or?rap??n!acsot?e&dom?is?sec&-&ilrof?ìlrof??ilrof?ìlrof???g&amor&-ailime?ailime??edras?olob??i&ssem?tal??ne!var??o&cna?merc?rev?vas???oneg?p?r!a&csep?rr&ac&-assam?assam??ef??von??etam?tsailgo!-lled?lled???s!ip?sam&-ararrac?ararrac??u&caris?gar???t!a&cilisab?recam??resac?soa!-&d&-&ellav?lav??ellav?lav??ellav??d&-&ellav?lav??ellav?lav??ellav??te&lrab&-&airdna-inart?inart-airdna??airdnainart?inartairdna??ssinatlac???udap?v!o&dap?neg?tnam???zn&airb&-a&lled-e-aznom?znom??a&lledeaznom?znom??eaznom??e&c&aip?iv??soc?top??om???b&-&23,46,61,?3c-lorit-ds-onitnert--nx?be-etsoa&-ellav--nx?dellav--nx??c!f-anesec-lrof--nx?m-lrof-anesec--nx??he-etsoa-d-ellav--nx?m!u??o2-loritds-nezob--nx?sn-loritds&-nasl&ab--nx?ub--nx??nitnert--nx??v!6-lorit-dsnitnert--nx?7-loritds&-nitnert--nx?onitnert--nx???z&r-lorit-ds&-nitnert--nx?onitnert--nx??s-loritds-onitnert--nx???c&f?is?l?m?p?r?v??d&p?u!olcnys,??e&c!cel?inev?nerolf??f?g!ida&-&a&-onitnert?onitnert??otla!-onitnert?onitnert???a&-onitnert?onitnert??otla!-on&azlob?itnert??onitnert????hcram?l?m!or??n&idu?o&n&edrop?isorf??torc???p?r?s&erav?ilom??t!nomeip?s&eirt?oa!-&d-e&ellav?éllav??e&ellav?éllav???de&ellav?éllav??e&ellav?éllav?????v?znerif??g&a?b?f?il?o?p?r?up?vf??hc?i&b?c?dol?f?l!lecrev?opan?rof&-anesec?anesec???m?n&a&part?rt&-attelrab-airdna?attelrabairdna???imir?ret??p?r!a&b?ilgac?ssas???s!idnirb??t&ei&hc?r??sa??v??l&a!c??b?c?o&m?rit&-&d&eus&-&nitnert?onitnert??nitnert?onitnert??us&-&nitnert?onitnert??nitnert?onitnert??üs&-&nitnert?onitnert??nitnert?onitnert???s&-onitnert?onitnert???d&eus!-&n&asl&ab?ub??ezob?itnert??onitnert??nitnert?onitnert??us&-&n&asl&ab?ub??ezob?itnert??onitnert??nitnert?onitnert??üs!-&n&asl&ab?ub??ezob?itnert??onitnert??nitnert?onitnert???s&-onitnert?onitnert?????m&ac?f?i?ol?r??n&a!lim?sl&ab?ub???b?c?e!v?zob??irut?m!p??p?r?t??o&a!v??b!retiv??c!cel??enuc?g!ivor??i&dem&-onadipmac?onadipmac??pmet&-aiblo?aiblo??rdnos?zal??l?m!a&greb?ret??oc?re&f?lap???n!a&dipmac&-oidem?oidem??lim?tsiro?zlob??ecip&-ilocsa?ilocsa??i&bru&-orasep?orasep??lleva?rot?tnert??r&elas?ovil??ulleb??p?r!a&sep&-onibru?onibru??znatac??oun??s!ivert?sabopmac??t!arp?e&nev?ssorg??n&arat?e&girga?rt?veneb????zz&era?urba???p&a?s?t??qa?r&a!m?s??b!a??c?f?g?k?me?o?p?s?t?v??s&a&b?iselgi&-ainobrac?ainobrac???b?c?elpan?i?m?ot?s?t?v??t&a?b?c?l?m?nomdeip?o!psgolb,?p?v??u&de?l?n?p??v&a?og?p?s?t?v??y&drabmol?ellav&-atsoa?atsoa??licis?nacsut??z&al?b?c?p??ìlrof&-anesec?anesec???derc?er?f!.sulptp,?m!r??utni??je3a3abgm--nx?kh?l!.&myn,topsgolb,vog??uda??m!.&gro?moc!.topsgolb,?ten?ude???n&a&morockivdnas?ruatser?tnuocca??e&g?m&eganam!.retuor,?piuqe??r??i!.ue?m?opdlog??opud?uocsid??o&b?cs!.vog,?d?g?h?j?oferab?p&edemoh?s???p!.&emon?gro?lbup?m&oc?yn,?t&en?ni?opsgolb,?ude?vog???r&a!m&law?s???epxe?op&er?pus!.ysrab,?s???s!.&adaxiabme?e&motoas?picnirp?rots??gro?lim?mo&c?n,?o&c?dalusnoc?hon,?ten?ude?vog??a&cmoc?f??e&b?padub?r?uq??i!rolf?tned??o&h!.&duolcp,etiseerf,flah,s&pvtsaf,seccaduolc,?tsafym,??p!sua???urt??t!.&eman?gro?ibom?levart?m&oc?uesum??o&c?fni?r&ea?p???pooc?sboj?t&en?ni??ude?vog?zib??ayh?n?o!bba?irram???uognah?xen?y?ztej??u&2&5te9--nx?yssp--nx??a!.&a&s?w??civ?d&i?lq??fnoc?gro?moc!.topsgolb,?nsa?ofni?sat?t&ca?en?n??ude!.&a&s?w??ci&lohtac?v??dlq?sat!.noitacude??t&ca?n??wsn!.sloohcs????vog!.&a&s?w??civ?dlq?sat???wsn?zo??ti??c!.&fni?gro?moc?ten?ude?vog??i??d&e!.tir.segap-tig,?iab??e!.&dcym,enozgniebllew,noitatsksid,snd&ps,uolc,?ysrab,??g!.&bew?gro?m&aug?oc??ofni?ten?ude?vog???h!.&0002?a&citore?idem?kitore??edszot?gro?ilus?letoh?m&alker?lif?t?urof??naltagni?o&c?ediv?fni?levynok?nisac??pohs?rarga?s&a&kal?zatu??emag?wen??t&lob?opsgolb,rops??virp?xe&s?zs??ytic?zsagoj??os?sut??l!.&myn,topsgolb,??m!.&ca?gro?moc?oc?ro?ten?vog???n!.&duolcesirpretne,eni&esrem,m,?mon,tenkcahs,?em!.ysrab,??o&ggnaw?y!c???r!.&a&i&kymlak,rikhsab,vodrom,?yegyda,?bps,ca,eniram,g&bc,ro,?ianatsuk,k&ihclan,s&m,rogitayp,??li&amdlc.bh,m,?moc,natsegad,onijym,pp,ri&b,midalv,?s&ar,itym,?t&en,ni,opsgolb,set,?ude,vo&g,n,?ynzorg,zakvakidalv,?myc?p?ug??s!.&a&d&golov,nagarak,?gulak,i&groeg,kymlak,lerak,nemra,rikhsab,ssakahk,vodrom,zahkba,?lut,rahkub,vut,yegyda,znep,?bps,da&baghsa,rgonilest,?gunel,i&anatsuk,hcos,ovan,ttailgot,?k&alhsygnam,ihclan,s&legnahkra,m,n&a&mrum,yrb,?i&buytka,nbo,??tiort,vorkop,??l&ocarak,ybmaj,?myn,na&gruk,jiabreza,ts&egad,hkazak-&htron,tsae,???ovonavi,r&adonsark,imidalv,?t&enxe,nek&hsat,mihc,??vo&hsalab,n,?ynzorg,z&akvakidalv,emret,??t&amok?i&juf?masih????v!.&gro?moc?ten?ude???ykuyr??v&b?c!.topsgolb,?ed!.&enilnigol,ppa-rettalp,srekrow,vr&esi,uc,???ih?l!.&di?fnoc?gro?lim?mo&c?n,?nsa?ten?ude?vog???m!.&eman?gro?lim?m&oc?uesum??o&fni?r&ea?p???pooc?t&en?ni??ude?vog?zib???o&g?m??rt?s!.&bog?der?gro?moc?ude???t!.&bew-eht-no,naht-&esrow,retteb,?sndnyd,?d?gh?i?won??uqhv--nx??w&a!.moc?hs?l??b!.&gro?oc???c!.&gro?moc?ten?ude??cp??e&iver!.oby,?n?s??g?k!.&bme?dni?gro?moc?ten?ude?vog???m!.&ca?gro?m&oc?uesum??oc?pooc?t&en?ni??ude?vog?zib??b??o&csom?h!s??n?w??p!.&344x,de?en?mon,o&c?g??ro?snduolc,ualeb???r!.&ca?gro?lim?oc?pooc?ten?vog??n??t!.&a46oa0fz--nx?b&82wrzc--nx?ulc??emag?gro?l&im?ru,?m&oc!.reliamym,?yn,?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??zibe?業商?織組?路網???z!.&ca?gro?lim?oc?vog????x&a!t??c!.&hta,ofni,vog???e&d&ef?nay??ma!nab??rof?s??ilften?jt?m!.&bog?gro?m&oc?yn,?t&en?opsgolb,?ude??g?ma2ibgy--nx??o&b!x??f?rex!ijuf???rbgn--nx?s!.&myn,vog???x&am&jt?kt??x???y&4punu--nx?7rr03--nx?a&d!i&loh?rfkcalb??ot??g?lp?p!ila??rot?ssin?wdaorb??b!.&fo?lim?m&oc!.topsgolb,?yn,?vog??ab?gur??c!.&ca?dtl?eman?gro?m&oc!.topsgolb,?t??orp?s&egolke?serp??t&en?nemailrap??vog?zib??amrahp?nega??d&dadog?uts??e&kcoh?ltneb?n&dys?om?rotta??snikcm??g!.&gro?m&oc?yn,?oc?ten?ude?vog??olonhcet!.oc,?rene??hpargotohp?id?k!.&gro?moc?ten?ude?vog??s??l!.&clp?d&em?i??gro?hcs?moc?ten?ude?vog??f?imaf!nacirema??l&a?il??ppus??m!.&eman?gro?lim?moc?t&en?opsgolb,?ude?vog??edaca!.laiciffo,?ra??n&a&ffit?pmoc!ylimafa???os??o&j?s??p!.&gro?lim?moc?pooc?ten?ude?vog???r&e&corg?grus?llag?viled??lewej?otcerid?tnuoc?uxul??s!.&gro?lim?moc?ten?ude?vog??pil??t&efas?i&c!.gn,?ledif?n&ifx?ummoc!.&bdnevar,murofym,???r&ahc?uces??srevinu??laer?r&ap!.oby,?eporp??uaeb??u!.&bug?gro?lim?mo&c!.topsgolb,?n,?ten?ude??b!tseb???van!dlo??xes??z&a!.&eman?gro?lim?moc?o&fni?rp??pp?t&en?ni??ude?vog?zib???b!.&az,gro?m&o&c?n,?yn,?ten?ude?vog???c!.&4e,inum.duolc.&rsu,tlf,?m&laer,urtnecatem.&duolc,motsuc,??oc,topsgolb,??d!.&gro?lop?moc?ossa?t&en?ra??ude?vog???ib!.&duolcsd,e&ht-rof,mos-rof,rom-rof,?lpb,nafamm,p&i&-on,fles,?ohbew,tfym,?retteb-rof,snd&nyd,uolc,?xro,?g??k!.&gro?lim?m&oc?yn,?ten?ude?vog???m!.&ca?gro?lim?oc?ten?ude?v&da?og????n!.&asq-irom--nx?ca?gro?htlaeh?i&r&c?o&am?ām???wi!k???keeg?l&im?oohcs??myn,neg?oc!.topsgolb,?t&en?nemailrap?vog???a!niflla???rawhcs?s!.&ca?gro?oc???t!.&c&a?s??e&m?n??ibom?l&etoh?im??o&c?fni?g??ro?vt???u!.&gro?moc?oc?ten??rwon??yx!.&etisgolb,gnitfarc,otpaz,ppahf,??zub??λε?υε?авксом?брс!.&гро?до?ка?р&бо?п!у?????г&б?ро??дкм?зақ?итед?килотак?леб?мок?н&йално?ом??рку?сур?тйас?фр?юе?յահ?םוק?اي&روس?سيلم?ناتيروم??بر&ع?غملا??ة&كبش?ي&دوعسلا?روس??یدوعسلا??ت&ا&راما?لاصتا??را&ب?ڀ?ھب???ر&ئازجلا?ازاب?صم?طق??سنوت?عقوم?قارع?ك&تيب?يلوثاك??موك?ن&ا&تس&كاپ?کاپ??دوس?ر&يا?یا??مع?يلعلا??درالا?ميلا?ي&رحبلا?طسلف???ه&ارمه?يدوعسلا??وكمارا?يبظوبا?ۃیدوعسلا?टेन?त&राभ?ोराभ??नठगंस?मॉक?्मतराभ?ত&রাভ?ৰাভ??ালংাব?ਤਰਾਭ?તરાભ?ତରାଭ?ாயித்நஇ?ைக்ஙலஇ?்ரூப்பக்ஙிச?్తరాభ?ತರಾಭ?ംതരാഭ?ාකංල?มอค?ยทไ!.&จิกรุธ?ต็นเ?ร&ก์คงอ?าหท??ลาบฐัร?าษกึศ???ວາລ?ეგ?なんみ?アトス?トンイポ?ドウラク?ムコ?ル&グーグ?ーセ??ン&ゾマア?ョシッァフ??业企?东广?乐娱?亚基诺?你爱我?信中?务政?动移?博微?卦八?厅餐?司公?品食?善慈?团集?国中?國中?址网?坡加新?城商?宝珠?尚时?山佛?店&商?网?酒大里嘉??府政?康健?息信?戏游?拉里格香?拿大?教主天?机手?构机!织组??标商?歌谷?浦利飞?港香!.&人個?司公?府政?絡網?織組?育教???湾台?灣&台?臺??物购?界世?益公?看点?科盈訊電?站网?籍書?线在?络网?网文中?聘招?表手?販通?车汽众大?逊马亚?通联?里嘉?锡马淡?門澳?门澳?闻新?電家?국한?넷닷?성삼?컴닷??"); /** - * If a hostname is not a key in the EXCLUDE map, and if removing its - * leftmost component results in a name which is a key in this map, it is a - * public suffix. + * If a hostname is not a key in the EXCLUDE map, and if removing its leftmost component results + * in a name which is a key in this map, it is a public suffix. */ public static final ImmutableMap UNDER = - TrieParser.parseTrie("ac.vedwa,d&b?uolc.&etiso&isnes,tnegam,?rehcnar-no,scitats,??e&b.lrusnart,d.ecapsrebu,noz.notirt,t&atse.etupmoc,is.hsmroftalp,?y??gp?h&k?s.mroftalp,trae.sppad:.zzb,,?k&c?f?nil.bewd,rowten.secla,u.hcs??ln.lrusnart,m&j?m?oc.&duolcmeaeboda.ved,ico-remotsuc:.&ico,pco,sco,?,mme0,s&tnemelepiuq,wanozama.&1-etupmoc,ble,etupmoc,??t&neyoj.snc,opsppa.r,???nc.moc.swanozama.&ble,etupmoc,?o&c.pato,i.&elacsnoom,oir-no,reniatnoceruza,s&3k-no,olots,?xcq.sys,y5s,??p&j.&a&mahokoy?yogan??ebok?i&adnes?kasawak??oroppas?uhsuykatik??n??r&b.mon?e??sw.rosivda,t&a.&ofnistro.&nednuk,xe,?smcerutuf:.&ni,xe,?,?en.cimonotpyrc,?u&e.lrusnart,r.onijym.&gni&dnal,tsoh,?murtceps,spv,??ved.&erahbew,gts,lcl,?zyx.tibelet,?"); + TrieParser.parseTrie( + "ac.vedwa,d&b?uolc.&etiso&isnes,tnegam,?rehcnar-no,scitats,??e&b.lrusnart,d.ecapsrebu,noz.notirt,t&atse.etupmoc,is.hsmroftalp,?y??gp?h&k?s.mroftalp,trae.sppad:.zzb,,?k&c?f?nil.bewd,rowten.secla,u.hcs??ln.lrusnart,m&j?m?oc.&duolcmeaeboda.ved,ico-remotsuc:.&ico,pco,sco,?,mme0,s&tnemelepiuq,wanozama.&1-etupmoc,ble,etupmoc,??t&neyoj.snc,opsppa.r,???nc.moc.swanozama.&ble,etupmoc,?o&c.pato,i.&elacsnoom,oir-no,reniatnoceruza,s&3k-no,olots,?xcq.sys,y5s,??p&j.&a&mahokoy?yogan??ebok?i&adnes?kasawak??oroppas?uhsuykatik??n??r&b.mon?e??sw.rosivda,t&a.&ofnistro.&nednuk,xe,?smcerutuf:.&ni,xe,?,?en.cimonotpyrc,?u&e.lrusnart,r.onijym.&gni&dnal,tsoh,?murtceps,spv,??ved.&erahbew,gts,lcl,?zyx.tibelet,?"); /** - * The elements in this map would pass the UNDER test, but are known not to - * be public suffixes and are thus excluded from consideration. Since it - * refers to elements in UNDER of the same type, the type is actually not - * important here. The map is simply used for consistency reasons. + * The elements in this map would pass the UNDER test, but are known not to be public suffixes and + * are thus excluded from consideration. Since it refers to elements in UNDER of the same type, + * the type is actually not important here. The map is simply used for consistency reasons. */ public static final ImmutableMap EXCLUDED = - TrieParser.parseTrie("kc.www?pj.&a&mahokoy.ytic?yogan.ytic??ebok.ytic?i&adnes.ytic?kasawak.ytic??oroppas.ytic?uhsuykatik.ytic???"); + TrieParser.parseTrie( + "kc.www?pj.&a&mahokoy.ytic?yogan.ytic??ebok.ytic?i&adnes.ytic?kasawak.ytic??oroppas.ytic?uhsuykatik.ytic???"); } diff --git a/pom.xml b/pom.xml index 031be683610a..6aa2edeea41d 100644 --- a/pom.xml +++ b/pom.xml @@ -248,7 +248,7 @@ org.checkerframework checker-qual - 2.11.1 + 3.0.1 com.google.errorprone