diff --git a/infer/annotations/src/main/java/com/facebook/infer/annotation/FalseOnNull.java b/infer/annotations/src/main/java/com/facebook/infer/annotation/FalseOnNull.java index f8cf958c1..96217230b 100644 --- a/infer/annotations/src/main/java/com/facebook/infer/annotation/FalseOnNull.java +++ b/infer/annotations/src/main/java/com/facebook/infer/annotation/FalseOnNull.java @@ -12,7 +12,36 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Annotation for a boolean function returning false when the argument is null. */ +/** + * Annotation specifying method's contract. @FalseOnNull declares that a boolean method will always + * return {@code false} when any of its arguments is {@code null}. + * + *
Calls to @FalseOnNull-annotated methods are treated by Nullsafe typechecker accordingly. This + * allows the caller's code become more elegant without need of extra assertions. + * + *
In the following example, annotating a method with @FalseOnNull simplifies its usage. + * + *
+ * @FalseOnNull
+ * public static hasNotification(@Nullable MyObject object) {
+ * if (object == null) {
+ * return false;
+ * }
+ * // ... actual logic
+ * }
+ *
+ * void exampleOfUsage(@Nullable MyObject obj) {
+ * if (hasNotification(obj)) {
+ * // Nullsafe knows obj can not be null at this point, so it can be safely dereferenced.
+ * // If hasNotification() was not annotated as @FalseOnNull, assertNotNull(obj)
+ * // would be required.
+ * obj.doSomething();
+ * }
+ * }
+ *
+ *
+ *
See also @TrueOnNull and @PropagatesNullable annotations. + */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.METHOD}) public @interface FalseOnNull {} diff --git a/infer/annotations/src/main/java/com/facebook/infer/annotation/Initializer.java b/infer/annotations/src/main/java/com/facebook/infer/annotation/Initializer.java index 3aa714af3..efcd12597 100644 --- a/infer/annotations/src/main/java/com/facebook/infer/annotation/Initializer.java +++ b/infer/annotations/src/main/java/com/facebook/infer/annotation/Initializer.java @@ -46,6 +46,8 @@ import java.lang.annotation.Target; * } * } * + * + *
See also: @Cleanup annotation. */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD}) diff --git a/infer/annotations/src/main/java/com/facebook/infer/annotation/PropagatesNullable.java b/infer/annotations/src/main/java/com/facebook/infer/annotation/PropagatesNullable.java index 6bacbf9e4..889bb0205 100644 --- a/infer/annotations/src/main/java/com/facebook/infer/annotation/PropagatesNullable.java +++ b/infer/annotations/src/main/java/com/facebook/infer/annotation/PropagatesNullable.java @@ -12,7 +12,39 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Annotation to indicate that when the parameter is null, the result is also null. */ +/** + * Annotation specifying method's contract. If a method's param is annotated + * with @PropagaresNullable, it declares that the method will return {@code null} if and only if + * this param is {@code null}. + * + *
Calls to @PropagatesNullable-annotated methods are treated by Nullsafe typechecker + * accordingly. If param is non-nullable in the callsite, Nullsafe will assume the method result is + * not null either, and hence no assertion or check will be needed. + * + *
In the following example, annotating the param with @PropagatesNullable allows to simplify + * usage of the method. + * + *
+ * public static String capitalize(@PropagatesNullable String input) {
+ * if (input == null) {
+ * return null;
+ * }
+ * return input.toUpperCase();
+ * }
+ *
+ * void exampleOfUsage(@Nullable String nullable, String nonnull) {
+ * capitalize(nullable).contains("A"); // <-- BAD: need a check
+ * // if capitalize() was not annotated as @PropagatesNullable,
+ * // assertNotNull(capitalize(nonnull)) would be required.
+ * capitalize(nonnull).contains("A"); // <-- OK: safe to dereference
+ * }
+ *
+ *
+ *
If several params are annotated as @PropagatesNullable, the method should return {@code null} + * if and only if any of those params is {@code null}. + * + *
See also @TrueOnNull and @FalseOnNull annotations. + */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.PARAMETER}) public @interface PropagatesNullable {} diff --git a/infer/annotations/src/main/java/com/facebook/infer/annotation/TrueOnNull.java b/infer/annotations/src/main/java/com/facebook/infer/annotation/TrueOnNull.java index 69d4eb713..463a0fa69 100644 --- a/infer/annotations/src/main/java/com/facebook/infer/annotation/TrueOnNull.java +++ b/infer/annotations/src/main/java/com/facebook/infer/annotation/TrueOnNull.java @@ -12,7 +12,33 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Annotation for a boolean function returning true when the argument is null. */ +/** + * Annotation specifying method's contract. @TrueOnNull declares that a boolean method will always + * return {@code true} when any of its arguments is {@code null}. + * + *
Calls to @TrueOnNull-annotated methods are treated by Nullsafe typechecker accordingly. This + * allows the caller's code become more elegant without need of extra assertions. + * + *
In the following example, annotating a method with @TrueOnNull simplifies its usage. + * + *
+ * @TrueOnNull
+ * public static boolean isStringEmpty(@Nullable String str) {
+ * return str == null || str.length() == 0;
+ * }
+ *
+ * void exampleOfUsage(@Nullable String myString) {
+ * if (!isStringEmpty(myString)) {
+ * // Nullsafe knows myString can not be null at this point, so it can be safely dereferenced.
+ * // If isStringEmpty() was not annotated as @TrueOnNull, assertNotNull(myString)
+ * // would be required.
+ * myString.toUpperCase();
+ * }
+ * }
+ *
+ *
+ *
See also @FalseOnNull and @PropagatesNullable annotations. + */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.METHOD}) public @interface TrueOnNull {}