Skip to content

Commit

Permalink
Use JSpecify annotations in the public release.
Browse files Browse the repository at this point in the history
We've been using these internally for over a year. With JSpecify 1.0 not far off and wider adoption to gradually follow, now seems like the time to expand our public usage of the annotations. We've already been using them in a few projects, but Truth may become the mostly widely used project that users actually link against to use them. At the same time, it's a library that's used only in testing code, so the stakes remain relatively low.

Most users will see no effect from this change, since most users don't use nullness checking and since we already used some nullness annotations in our public release. The main effect users are likely to see is if they pass nullable values for parameters that are now recognized as non-nullable. Under Kotlin, the effect should normally be a warning, not an error, at least until [Kotlin 2.1 or so](https://youtrack.jetbrains.com/issue/KT-55586/Handle-nullability-from-jspecify-annotations-properly#focus=Comments-27-8368666.0-0). Please still [report any problems](https://github.com/google/truth/issues/new).

(progress toward JSpecify adoption in our projects in general, including google/guava#2960)

RELNOTES=Added more nullness information to our APIs (in the form of [JSpecify](https://jspecify.dev/) annotations). This could lead to additional warnings (or even errors) for users of Kotlin and other nullness checkers. Please [report any problems](https://github.com/google/truth/issues/new).
PiperOrigin-RevId: 646988261
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed Jun 26, 2024
1 parent d39e722 commit 6a96d17
Show file tree
Hide file tree
Showing 92 changed files with 198 additions and 88 deletions.
4 changes: 2 additions & 2 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import static com.google.common.truth.Fact.simpleFact;

import java.lang.reflect.Array;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* A common supertype for Array subjects, abstracting some common display and error infrastructure.
*
* @author Christian Gruber (cgruber@israfil.net)
*/
@NullMarked
abstract class AbstractArraySubject extends Subject {
private final @Nullable Object actual;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Map.Entry;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Handle;
Expand Down Expand Up @@ -69,6 +70,7 @@
*/
@GwtIncompatible
@J2ktIncompatible
@NullMarked
final class ActualValueInference {
/** <b>Call {@link Platform#inferDescription} rather than calling this directly.</b> */
static @Nullable String describeActualValue(String className, String methodName, int lineNumber) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
import static com.google.common.truth.Fact.makeMessage;

import com.google.common.collect.ImmutableList;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* An {@link AssertionError} composed of structured {@link Fact} instances and other string
* messages.
*/
@SuppressWarnings("OverrideThrowableToString") // We intentionally hide the class name.
@NullMarked
final class AssertionErrorWithFacts extends AssertionError implements ErrorWithFacts {
private final ImmutableList<Fact> facts;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import static com.google.common.truth.Fact.simpleFact;

import java.math.BigDecimal;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for {@link BigDecimal} typed subjects.
*
* @author Kurt Alfred Kluever
*/
@NullMarked
public final class BigDecimalSubject extends ComparableSubject<BigDecimal> {
private final @Nullable BigDecimal actual;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@

import static com.google.common.truth.Fact.simpleFact;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for boolean subjects.
*
* @author Christian Gruber (cgruber@israfil.net)
*/
@NullMarked
public final class BooleanSubject extends Subject {
private final @Nullable Boolean actual;

Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/com/google/common/truth/ClassSubject.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.GwtIncompatible;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for {@link Class} subjects.
*
* @author Kurt Alfred Kluever
*/
@NullMarked
@GwtIncompatible("reflection")
@J2ktIncompatible
public final class ClassSubject extends Subject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.Range;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for {@link Comparable} typed subjects.
*
* @author Kurt Alfred Kluever
* @param <T> the type of the object being tested by this {@code ComparableSubject}
*/
@NullMarked
// TODO(b/136040841): Consider further tightening this to the proper `extends Comparable<? super T>`
public abstract class ComparableSubject<T extends Comparable<?>> extends Subject {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@

import com.google.common.collect.ImmutableList;
import com.google.common.truth.Platform.PlatformComparisonFailure;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* An {@link AssertionError} (usually a JUnit {@code ComparisonFailure}, but not under GWT) composed
* of structured {@link Fact} instances and other string messages.
*/
@NullMarked
final class ComparisonFailureWithFacts extends PlatformComparisonFailure implements ErrorWithFacts {
private final ImmutableList<Fact> facts;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Contains part of the code responsible for creating a JUnit {@code ComparisonFailure} (if
Expand All @@ -42,6 +43,7 @@
* different implementation under GWT/j2cl, where {@code ComparisonFailure} is also unavailable but
* we can't just recover from that at runtime.
*/
@NullMarked
final class ComparisonFailures {
static ImmutableList<Fact> makeComparisonFailureFacts(
ImmutableList<Fact> headFacts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Determines whether an instance of type {@code A} corresponds in some way to an instance of type
Expand Down Expand Up @@ -65,6 +66,7 @@
*
* @author Pete Gillin
*/
@NullMarked
public abstract class Correspondence<A extends @Nullable Object, E extends @Nullable Object> {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import static com.google.common.base.Preconditions.checkNotNull;

import org.jspecify.annotations.NullMarked;

/**
* In a fluent assertion chain, exposes one or more "custom" {@code that} methods, which accept a
Expand All @@ -35,6 +36,7 @@
* extensions</a>. It explains the cases in which {@code CustomSubjectBuilder} is necessary, and it
* links to further instructions.
*/
@NullMarked
public abstract class CustomSubjectBuilder {
/**
* In a fluent assertion chain, the argument to the "custom" overload of {@link
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/com/google/common/truth/DiffUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.NullMarked;

/**
* A custom implementation of the diff algorithm based on the solution described at
* https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
*
* @author Yun Peng (pcloudy@google.com)
*/
@NullMarked
final class DiffUtils {
// A list of unique strings appeared in compared texts.
// The index of each string is its incremental Id.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
import static java.lang.Double.NaN;
import static java.lang.Double.doubleToLongBits;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for {@link Double} subjects.
*
* @author Kurt Alfred Kluever
*/
@NullMarked
public final class DoubleSubject extends ComparableSubject<Double> {
private static final long NEG_ZERO_BITS = doubleToLongBits(-0.0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
package com.google.common.truth;

import com.google.common.collect.ImmutableList;
import org.jspecify.annotations.NullMarked;

/**
* Supertype of Truth's {@link AssertionError} subclasses that are created from a list of {@link
* Fact} instances.
*/
@NullMarked
interface ErrorWithFacts {
ImmutableList<Fact> facts();
}
4 changes: 3 additions & 1 deletion core/src/main/java/com/google/common/truth/Expect.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
import com.google.errorprone.annotations.concurrent.GuardedBy;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import org.junit.internal.AssumptionViolatedException;
import org.junit.rules.ErrorCollector;
import org.junit.rules.TestRule;
Expand Down Expand Up @@ -83,6 +84,7 @@
*/
@GwtIncompatible("JUnit4")
@J2ktIncompatible
@NullMarked
public final class Expect extends StandardSubjectBuilder implements TestRule {

private static final class ExpectationGatherer implements FailureStrategy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
import com.google.common.annotations.GwtIncompatible;
import com.google.common.truth.Truth.SimpleAssertionError;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

Expand Down Expand Up @@ -66,6 +67,7 @@
* also checks that the assertion you're testing uses the supplied {@link FailureStrategy} and calls
* {@link FailureStrategy#fail} only once.
*/
@NullMarked
public final class ExpectFailure implements Platform.JUnitTestRule {
private boolean inRuleContext = false;
private boolean failureExpected = false;
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/com/google/common/truth/Fact.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

import com.google.common.collect.ImmutableList;
import java.io.Serializable;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* A string key-value pair in a failure message, such as "expected: abc" or "but was: xyz."
Expand All @@ -34,6 +35,7 @@
* <p>If you are writing a custom {@code Subject}, see <a
* href="https://truth.dev/failure_messages">our tips on writing failure messages</a>.
*/
@NullMarked
public final class Fact implements Serializable {
/**
* Creates a fact with the given key and value, which will be printed in a format like "key:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* An opaque, immutable object containing state from the previous calls in the fluent assertion
Expand All @@ -51,6 +52,7 @@
* using their {@link CustomSubjectBuilder#metadata()} method to get an instance to pass to the
* constructor.)
*/
@NullMarked
public final class FailureMetadata {
static FailureMetadata forFailureStrategy(FailureStrategy failureStrategy) {
return new FailureMetadata(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.google.common.truth;

import org.jspecify.annotations.NullMarked;

/**
* Defines what to do when a check fails.
Expand Down Expand Up @@ -53,6 +54,7 @@
* StandardSubjectBuilder#forCustomFailureStrategy
* StandardSubjectBuilder.forCustomFailureStrategy(STRATEGY)}.
*/
@NullMarked
public interface FailureStrategy {
/**
* Handles a failure. The parameter is an {@code AssertionError} or subclass thereof, and it
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/com/google/common/truth/FloatSubject.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
import static java.lang.Float.NaN;
import static java.lang.Float.floatToIntBits;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for {@link Float} subjects.
*
* @author Kurt Alfred Kluever
*/
@NullMarked
public final class FloatSubject extends ComparableSubject<Float> {
private static final int NEG_ZERO_BITS = floatToIntBits(-0.0f);

Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/com/google/common/truth/GraphMatching.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import org.jspecify.annotations.NullMarked;

/**
* Helper routines related to <a href="https://en.wikipedia.org/wiki/Matching_(graph_theory)">graph
* matchings</a>.
*
* @author Pete Gillin
*/
@NullMarked
final class GraphMatching {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import static com.google.common.truth.Fact.simpleFact;

import com.google.common.base.Optional;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* Propositions for Guava {@link Optional} subjects.
Expand All @@ -28,6 +29,7 @@
*
* @author Christian Gruber
*/
@NullMarked
public final class GuavaOptionalSubject extends Subject {
@SuppressWarnings("NullableOptional") // Truth always accepts nulls, no matter the type
private final @Nullable Optional<?> actual;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Target;
import org.jspecify.annotations.NullMarked;

/**
* Disables Animal Sniffer's checking of compatibility with older versions of Java/Android.
*/
@Target({METHOD, CONSTRUCTOR, TYPE})
@NullMarked
@interface IgnoreJRERequirement {}
Loading

0 comments on commit 6a96d17

Please sign in to comment.