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 {}