001// From the Checker Framework, but replace uses of "org.checkerframework.checker.nullness" by
002// "daikon.tools.nullness" and comment out nullness annotations and their import statement.
003package daikon.tools.nullness;
004
005import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
006import org.checkerframework.checker.nullness.qual.NonNull;
007import org.checkerframework.checker.nullness.qual.Nullable;
008
009/**
010 * Utility class for the Nullness Checker.
011 *
012 * <p>To avoid the need to write the NullnessUtil class name, do:
013 *
014 * <pre>import static daikon.tools.nullness.NullnessUtil.castNonNull;</pre>
015 *
016 * or
017 *
018 * <pre>import static daikon.tools.nullness.NullnessUtil.*;</pre>
019 *
020 * <p><b>Run-time Dependency</b>
021 *
022 * <p>Please note that using this class introduces a run-time dependency. This means that you need
023 * to distribute (or link to) Daikon, along with your binaries.
024 *
025 * <p>To eliminate this dependency, you can simply copy this class into your own project.
026 */
027@SuppressWarnings({
028  "nullness", // Nullness utilities are trusted regarding nullness.
029  "cast" // Casts look redundant if Nullness Checker is not run.
030})
031public final class NullnessUtil {
032
033  private NullnessUtil() {
034    throw new AssertionError("shouldn't be instantiated");
035  }
036
037  /**
038   * A method that suppresses warnings from the Nullness Checker.
039   *
040   * <p>The method takes a possibly-null reference, unsafely casts it to have the @NonNull type
041   * qualifier, and returns it. The Nullness Checker considers both the return value, and also the
042   * argument, to be non-null after the method call. Therefore, the {@code castNonNull} method can
043   * be used either as a cast expression or as a statement. The Nullness Checker issues no warnings
044   * in any of the following code:
045   *
046   * <pre>{@code
047   *  // one way to use as a cast:
048   * {@literal @}NonNull String s = castNonNull(possiblyNull1);
049   *
050   *  // another way to use as a cast:
051   *  castNonNull(possiblyNull2).toString();
052   *
053   *  // one way to use as a statement:
054   *  castNonNull(possiblyNull3);
055   *  possiblyNull3.toString();`
056   * }</pre>
057   *
058   * The {@code castNonNull} method is intended to be used in situations where the programmer
059   * definitively knows that a given reference is not null, but the type system is unable to make
060   * this deduction. It is not intended for defensive programming, in which a programmer cannot
061   * prove that the value is not null but wishes to have an earlier indication if it is. See the
062   * Checker Framework Manual for further discussion.
063   *
064   * <p>The method throws {@link AssertionError} if Java assertions are enabled and the argument is
065   * {@code null}. If the exception is ever thrown, then that indicates that the programmer misused
066   * the method by using it in a circumstance where its argument can be null.
067   *
068   * @param ref a reference of @Nullable type
069   * @return the argument, casted to have the type qualifier @NonNull
070   */
071  public static @EnsuresNonNull("#1") <T extends @Nullable Object> @NonNull T castNonNull(T ref) {
072    assert ref != null : "Misuse of castNonNull: called with a null argument";
073    return (@NonNull T) ref;
074  }
075
076  /**
077   * Like castNonNull, but whereas that method only checks and casts the reference itself, this
078   * traverses all levels of the argument array. The array is recursively checked to ensure that all
079   * elements at every array level are non-null.
080   *
081   * @param <T> the type of array elements
082   * @param arr an array that contains no null elements at any level
083   * @return the argument, with each array level casted to {@code @NonNull}
084   * @see #castNonNull(Object)
085   */
086  public static @EnsuresNonNull("#1") <T extends @Nullable Object>
087      @NonNull T @NonNull [] castNonNullDeep(T @Nullable [] arr) {
088    return (@NonNull T[]) castNonNullDeepArray(arr);
089  }
090
091  /**
092   * Like castNonNull, but whereas that method only checks and casts the reference itself, this
093   * traverses all levels of the argument array. The array is recursively checked to ensure that all
094   * elements at every array level are non-null.
095   *
096   * @param <T> the type of array elements
097   * @param arr an array that contains no null elements at any level
098   * @return the argument, with each array level casted to {@code @NonNull}
099   * @see #castNonNull(Object)
100   */
101  public static <T extends @Nullable Object> @NonNull T @NonNull [][] castNonNullDeep(
102      T @Nullable [] @Nullable [] arr) {
103    return (@NonNull T[][]) castNonNullDeepArray(arr);
104  }
105
106  /**
107   * Like castNonNull, but whereas that method only checks and casts the reference itself, this
108   * traverses all levels of the argument array. The array is recursively checked to ensure that all
109   * elements at every array level are non-null.
110   *
111   * @param <T> the type of array elements
112   * @param arr an array that contains no null elements at any level
113   * @return the argument, with each array level casted to {@code @NonNull}
114   * @see #castNonNull(Object)
115   */
116  public static <T extends @Nullable Object> @NonNull T @NonNull [][][] castNonNullDeep(
117      T @Nullable [] @Nullable [] @Nullable [] arr) {
118    return (@NonNull T[][][]) castNonNullDeepArray(arr);
119  }
120
121  /**
122   * Like castNonNull, but whereas that method only checks and casts the reference itself, this
123   * traverses all levels of the argument array. The array is recursively checked to ensure that all
124   * elements at every array level are non-null.
125   *
126   * @param <T> the type of array elements
127   * @param arr an array that contains no null elements at any level
128   * @return the argument, with each array level casted to {@code @NonNull}
129   * @see #castNonNull(Object)
130   */
131  public static @EnsuresNonNull("#1") <T extends @Nullable Object>
132      @NonNull T @NonNull [][][][] castNonNullDeep(
133          T @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr) {
134    return (@NonNull T[][][][]) castNonNullDeepArray(arr);
135  }
136
137  /**
138   * Like castNonNull, but whereas that method only checks and casts the reference itself, this
139   * traverses all levels of the argument array. The array is recursively checked to ensure that all
140   * elements at every array level are non-null.
141   *
142   * @param <T> the type of array elements
143   * @param arr an array that contains no null elements at any level
144   * @return the argument, with each array level casted to {@code @NonNull}
145   * @see #castNonNull(Object)
146   */
147  public static @EnsuresNonNull("#1") <T extends @Nullable Object>
148      @NonNull T @NonNull [][][][][] castNonNullDeep(
149          T @Nullable [] @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr) {
150    return (@NonNull T[][][][][]) castNonNullDeepArray(arr);
151  }
152
153  /**
154   * Does the work for the {@code castNonNullDeep} family of overloads. Throws an exception if any
155   * level of the array contains a null element.
156   *
157   * @param <T> the type of array elements
158   * @param arr an array that contains no null elements at any level
159   * @return the argument, with each array level casted to {@code @NonNull}
160   */
161  private static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullDeepArray(
162      T @Nullable [] arr) {
163    assert arr != null : "Misuse of castNonNullDeepArray: called with a null array argument";
164    for (int i = 0; i < arr.length; ++i) {
165      assert arr[i] != null : "Misuse of castNonNull: called with a null array element";
166      castNonNullDeepIfArray(arr[i]);
167    }
168    return (@NonNull T[]) arr;
169  }
170
171  /**
172   * If the argument is an array, calls {@link #castNonNullDeepArray}.
173   *
174   * @param ref a value that might be an array, and if so should be null at all levels
175   */
176  private static void castNonNullDeepIfArray(Object ref) {
177    assert ref != null : "Misuse of castNonNullIfArray: called with a null argument";
178    Class<?> comp = ref.getClass().getComponentType();
179    if (comp != null) {
180      // comp is non-null for arrays, otherwise null.
181      if (comp.isPrimitive()) {
182        // Nothing to do for arrays of primitive type: primitives are
183        // never null.
184      } else {
185        castNonNullDeepArray((Object[]) ref);
186      }
187    }
188  }
189}