diff --git a/infer/src/checkers/annotationReachability.ml b/infer/src/checkers/annotationReachability.ml index 7ae068f19..80084d626 100644 --- a/infer/src/checkers/annotationReachability.ml +++ b/infer/src/checkers/annotationReachability.ml @@ -26,6 +26,8 @@ let src_snk_pairs () = [ ([Annotations.performance_critical], Annotations.expensive); ([Annotations.no_allocation; Annotations.on_bind], dummy_constructor_annot); + ([Annotations.any_thread; Annotations.for_non_ui_thread], Annotations.ui_thread); + ([Annotations.ui_thread; Annotations.for_ui_thread], Annotations.for_non_ui_thread); ] in IList.map (fun (src_annot_str_list, snk_annot_str) -> diff --git a/infer/src/checkers/annotations.ml b/infer/src/checkers/annotations.ml index d534b862d..33459d387 100644 --- a/infer/src/checkers/annotations.ml +++ b/infer/src/checkers/annotations.ml @@ -116,6 +116,9 @@ let guarded_by = "GuardedBy" let thread_safe = "ThreadSafe" let not_thread_safe = "NotThreadSafe" let ui_thread = "UiThread" +let any_thread = "AnyThread" +let for_ui_thread = "ForUiThread" +let for_non_ui_thread = "ForNonUiThread" let thread_confined = "ThreadConfined" let ia_is_not_thread_safe ia = diff --git a/infer/src/checkers/annotations.mli b/infer/src/checkers/annotations.mli index 74c3f7cea..d72bf243a 100644 --- a/infer/src/checkers/annotations.mli +++ b/infer/src/checkers/annotations.mli @@ -17,6 +17,10 @@ val expensive : string val performance_critical : string val no_allocation : string val on_bind : string +val ui_thread : string +val any_thread : string +val for_ui_thread : string +val for_non_ui_thread : string type annotation = | Nullable diff --git a/infer/tests/codetoanalyze/java/checkers/UiThreads.java b/infer/tests/codetoanalyze/java/checkers/UiThreads.java new file mode 100644 index 000000000..009fe0b8c --- /dev/null +++ b/infer/tests/codetoanalyze/java/checkers/UiThreads.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package codetoanalyze.java.checkers; + +import android.support.annotation.UiThread; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.CLASS) +@interface AnyThread { +} + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.CLASS) +@interface ForUiThread { +} + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.CLASS) +@interface ForNonUiThread { +} + +public class UiThreads { + + @UiThread + void uiThread() {} + + @AnyThread + void anyThread() {} + + @ForUiThread + void forUiThread() {} + + @ForNonUiThread + void forNonUiThread() {} + + @ForUiThread + void callForNonUiThreadBad1() { + forNonUiThread(); + } + + @UiThread + void callForNonUiThreadBad2() { + forNonUiThread(); + } + + @AnyThread + void callUiThreadBad1() { + uiThread(); + } + + @ForNonUiThread + void callUiThreadBad2() { + uiThread(); + } + + @ForUiThread + void callUiThreadOk() { + uiThread(); + } + + @UiThread + void callForUiThreadOk() { + forUiThread(); + } + + @ForNonUiThread + void callAnyThreadOk1() { + anyThread(); + } + + @ForUiThread + void callAnyThreadOk2() { + anyThread(); + } + + @UiThread + void callAnyThreadOk3() { + anyThread(); + } + + @AnyThread + void callForNonUiThreadOk() { + forNonUiThread(); + } + +} diff --git a/infer/tests/codetoanalyze/java/checkers/issues.exp b/infer/tests/codetoanalyze/java/checkers/issues.exp index 87e2c6016..adc5e1354 100644 --- a/infer/tests/codetoanalyze/java/checkers/issues.exp +++ b/infer/tests/codetoanalyze/java/checkers/issues.exp @@ -33,3 +33,7 @@ codetoanalyze/java/checkers/PrintfArgsChecker.java, void PrintfArgsChecker.strin codetoanalyze/java/checkers/PrintfArgsChecker.java, void PrintfArgsChecker.wrongNumberOfArguments(PrintStream), 1, CHECKERS_PRINTF_ARGS, [format string arguments don't mach provided arguments in printf(...) at line 44] codetoanalyze/java/checkers/TwoCheckersExample.java, List TwoCheckersExample.shouldRaiseImmutableCastError(), 0, CHECKERS_IMMUTABLE_CAST, [Method shouldRaiseImmutableCastError() returns class com.google.common.collect.ImmutableList but the return type is class java.util.List. Make sure that users of this method do not try to modify the collection.] codetoanalyze/java/checkers/TwoCheckersExample.java, List TwoCheckersExample.shouldRaisePerformanceCriticalError(), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] +codetoanalyze/java/checkers/UiThreads.java, void UiThreads.callForNonUiThreadBad1(), 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, [] +codetoanalyze/java/checkers/UiThreads.java, void UiThreads.callForNonUiThreadBad2(), 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, [] +codetoanalyze/java/checkers/UiThreads.java, void UiThreads.callUiThreadBad1(), 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, [] +codetoanalyze/java/checkers/UiThreads.java, void UiThreads.callUiThreadBad2(), 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, []