diff --git a/infer/src/checkers/ThreadSafety.ml b/infer/src/checkers/ThreadSafety.ml index e79be8f5b..d7c1e14f8 100644 --- a/infer/src/checkers/ThreadSafety.ml +++ b/infer/src/checkers/ThreadSafety.ml @@ -426,10 +426,16 @@ let is_thread_confined_method tenv pdesc = (* we don't want to warn on methods that run on the UI thread because they should always be single-threaded *) let runs_on_ui_thread proc_desc = - (* assume that methods annotated with @UiThread or @OnEvent(SomeEvent.class) always run on the UI - thread *) + (* assume that methods annotated with @UiThread, @OnEvent, @OnBind, @OnMount, @OnUnbind, + @OnUnmount always run on the UI thread *) is_annotated - (fun annot -> Annotations.ia_is_ui_thread annot || Annotations.ia_is_on_event annot) + (fun annot -> Annotations.ia_is_ui_thread annot || + Annotations.ia_is_on_bind annot || + Annotations.ia_is_on_event annot || + Annotations.ia_is_on_mount annot || + Annotations.ia_is_on_unbind annot || + Annotations.ia_is_on_unmount annot) + proc_desc let is_assumed_thread_safe pdesc = diff --git a/infer/src/checkers/annotations.ml b/infer/src/checkers/annotations.ml index 5b40f29d2..4a75cfd89 100644 --- a/infer/src/checkers/annotations.ml +++ b/infer/src/checkers/annotations.ml @@ -103,6 +103,9 @@ let nullable = "Nullable" let nonnull = "Nonnull" let on_bind = "OnBind" let on_event = "OnEvent" +let on_mount = "OnMount" +let on_unbind = "OnUnbind" +let on_unmount = "OnUnmount" let camel_nonnull = "NonNull" let notnull = "NotNull" let present = "Present" @@ -224,6 +227,18 @@ let ia_is_suppress_lint ia = let ia_is_on_event ia = ia_ends_with ia on_event +let ia_is_on_bind ia = + ia_ends_with ia on_bind + +let ia_is_on_mount ia = + ia_ends_with ia on_mount + +let ia_is_on_unbind ia = + ia_ends_with ia on_unbind + +let ia_is_on_unmount ia = + ia_ends_with ia on_unmount + let ia_is_privacy_source ia = ia_ends_with ia privacy_source diff --git a/infer/src/checkers/annotations.mli b/infer/src/checkers/annotations.mli index 261bc2e8a..727a6e525 100644 --- a/infer/src/checkers/annotations.mli +++ b/infer/src/checkers/annotations.mli @@ -94,6 +94,10 @@ val ia_is_no_allocation : Annot.Item.t -> bool val ia_is_ignore_allocations : Annot.Item.t -> bool val ia_is_suppress_lint : Annot.Item.t -> bool val ia_is_on_event : Annot.Item.t -> bool +val ia_is_on_bind : Annot.Item.t -> bool +val ia_is_on_mount : Annot.Item.t -> bool +val ia_is_on_unbind : Annot.Item.t -> bool +val ia_is_on_unmount : Annot.Item.t -> bool val ia_is_privacy_source : Annot.Item.t -> bool val ia_is_privacy_sink : Annot.Item.t -> bool val ia_is_integrity_source : Annot.Item.t -> bool diff --git a/infer/tests/codetoanalyze/java/threadsafety/Annotations.java b/infer/tests/codetoanalyze/java/threadsafety/Annotations.java index c34526b3d..ebd54f59f 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/Annotations.java +++ b/infer/tests/codetoanalyze/java/threadsafety/Annotations.java @@ -23,11 +23,31 @@ import com.facebook.infer.annotation.ThreadConfined; /** tests for classes and method annotations that are meaningful w.r.t thread-safety */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +@interface OnBind { +} + @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) @interface OnEvent { } +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +@interface OnMount { +} + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +@interface OnUnbind { +} + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +@interface OnUnmount { +} + @ThreadSafe class Annotations { Object f; @@ -89,6 +109,26 @@ class Annotations { this.f = new Object(); } + @OnBind + public void onBindMethodOk() { + this.f = new Object(); + } + + @OnMount + public void onMountMethodOk() { + this.f = new Object(); + } + + @OnUnmount + public void onUnmountMethodOk() { + this.f = new Object(); + } + + @OnUnbind + public void onUnbindMethodOk() { + this.f = new Object(); + } + @AssumeThreadSafe(because = "it's a test") public void assumeThreadSafeOk() { this.f = new Object();