[cost] Introduce cost issue types for functions on UI Thread

Summary:
Let's introduce a set of new cost analysis issue types that are raised when the function is statically determined to run on the UI thread. For this, we rely on the existing `runs_on_ui_thread` check that is developed for RacerD. We also update the cost summary and `jsonbug.cost_item` to include whether a method is on the ui thread  so that we don't repeatedly compute this at diff time for complexity increase issues.

Note that `*_UI_THREAD` cost issues are assumed to be more strict than `*_COLD_START` reports at the moment. Next, we can also consider adding a new issue type that combines both such as `*_UI_THREAD_AND_COLD_START` (i.e. for methods that are both on cold start and run on ui thread).

Reviewed By: ngorogiannis

Differential Revision: D18428408

fbshipit-source-id: f18805716
master
Ezgi Çiçek 5 years ago committed by Facebook Github Bot
parent e66a23a04c
commit 94f4ded9b4

@ -337,6 +337,7 @@ OPTIONS
ALLOCATION_COMPLEXITY_INCREASE (enabled by default),
ALLOCATION_COMPLEXITY_INCREASE_COLD_START (enabled by default),
ALLOCATION_COMPLEXITY_INCREASE_UI_THREAD (enabled by default),
ANALYSIS_STOPS (disabled by default),
ARRAY_OUT_OF_BOUNDS_L1 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L2 (disabled by default),
@ -400,11 +401,15 @@ OPTIONS
ERADICATE_RETURN_OVER_ANNOTATED (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by
default),
EXECUTION_TIME_COMPLEXITY_INCREASE_UI_THREAD (enabled by
default),
EXPENSIVE_ALLOCATION (disabled by default),
EXPENSIVE_ALLOCATION_COLD_START (disabled by default),
EXPENSIVE_ALLOCATION_UI_THREAD (disabled by default),
EXPENSIVE_EXECUTION_TIME (disabled by default),
EXPENSIVE_EXECUTION_TIME_COLD_START (disabled by default),
EXPENSIVE_EXECUTION_TIME_UI_THREAD (disabled by default),
EXPENSIVE_LOOP_INVARIANT_CALL (enabled by default),
EXPOSED_INSECURE_INTENT_HANDLING (enabled by default),
Failure_exe (enabled by default),

@ -79,6 +79,7 @@ OPTIONS
ALLOCATION_COMPLEXITY_INCREASE (enabled by default),
ALLOCATION_COMPLEXITY_INCREASE_COLD_START (enabled by default),
ALLOCATION_COMPLEXITY_INCREASE_UI_THREAD (enabled by default),
ANALYSIS_STOPS (disabled by default),
ARRAY_OUT_OF_BOUNDS_L1 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L2 (disabled by default),
@ -142,11 +143,15 @@ OPTIONS
ERADICATE_RETURN_OVER_ANNOTATED (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by
default),
EXECUTION_TIME_COMPLEXITY_INCREASE_UI_THREAD (enabled by
default),
EXPENSIVE_ALLOCATION (disabled by default),
EXPENSIVE_ALLOCATION_COLD_START (disabled by default),
EXPENSIVE_ALLOCATION_UI_THREAD (disabled by default),
EXPENSIVE_EXECUTION_TIME (disabled by default),
EXPENSIVE_EXECUTION_TIME_COLD_START (disabled by default),
EXPENSIVE_EXECUTION_TIME_UI_THREAD (disabled by default),
EXPENSIVE_LOOP_INVARIANT_CALL (enabled by default),
EXPOSED_INSECURE_INTENT_HANDLING (enabled by default),
Failure_exe (enabled by default),

@ -337,6 +337,7 @@ OPTIONS
ALLOCATION_COMPLEXITY_INCREASE (enabled by default),
ALLOCATION_COMPLEXITY_INCREASE_COLD_START (enabled by default),
ALLOCATION_COMPLEXITY_INCREASE_UI_THREAD (enabled by default),
ANALYSIS_STOPS (disabled by default),
ARRAY_OUT_OF_BOUNDS_L1 (disabled by default),
ARRAY_OUT_OF_BOUNDS_L2 (disabled by default),
@ -400,11 +401,15 @@ OPTIONS
ERADICATE_RETURN_OVER_ANNOTATED (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE (enabled by default),
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START (enabled by
default),
EXECUTION_TIME_COMPLEXITY_INCREASE_UI_THREAD (enabled by
default),
EXPENSIVE_ALLOCATION (disabled by default),
EXPENSIVE_ALLOCATION_COLD_START (disabled by default),
EXPENSIVE_ALLOCATION_UI_THREAD (disabled by default),
EXPENSIVE_EXECUTION_TIME (disabled by default),
EXPENSIVE_EXECUTION_TIME_COLD_START (disabled by default),
EXPENSIVE_EXECUTION_TIME_UI_THREAD (disabled by default),
EXPENSIVE_LOOP_INVARIANT_CALL (enabled by default),
EXPOSED_INSECURE_INTENT_HANDLING (enabled by default),
Failure_exe (enabled by default),

@ -75,6 +75,7 @@ type cost_item = {
loc : loc;
procedure_name : string;
procedure_id : string;
is_on_ui_thread : bool;
alloc_cost : cost_info;
exec_cost : cost_info;
}

@ -212,6 +212,7 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
curr_item ) =
let file = cost_info.Jsonbug_t.loc.file in
let method_name = cost_info.Jsonbug_t.procedure_name in
let is_on_ui_thread = cost_info.Jsonbug_t.is_on_ui_thread in
let class_name =
match Str.split (Str.regexp_string ("." ^ method_name)) cost_info.Jsonbug_t.procedure_id with
| [class_name; _] ->
@ -228,7 +229,7 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
else if CostItem.is_zero curr_item then zero_issue
else
let is_on_cold_start = ExternalPerfData.in_profiler_data_map procname in
complexity_increase_issue ~is_on_cold_start
complexity_increase_issue ~is_on_cold_start ~is_on_ui_thread
in
if (not Config.filtering) || issue_type.IssueType.enabled then
let qualifier =

@ -323,7 +323,7 @@ module JsonCostsPrinter = MakeJsonListPrinter (struct
let to_string {loc; proc_name; cost_opt} =
match cost_opt with
| Some {post} when not (Typ.Procname.is_java_access_method proc_name) ->
| Some {post; is_on_ui_thread} when not (Typ.Procname.is_java_access_method proc_name) ->
let hum cost =
let degree_with_term = CostDomain.BasicCost.get_degree_with_term cost in
{ Jsonbug_t.hum_polynomial= Format.asprintf "%a" CostDomain.BasicCost.pp_hum cost
@ -349,6 +349,7 @@ module JsonCostsPrinter = MakeJsonListPrinter (struct
; loc= {file; lnum= loc.Location.line; cnum= loc.Location.col; enum= -1}
; procedure_name= Typ.Procname.get_method proc_name
; procedure_id= procedure_id_of_procname proc_name
; is_on_ui_thread
; exec_cost= cost_info (CostDomain.get_cost_kind CostKind.OperationCost post)
; alloc_cost= cost_info (CostDomain.get_cost_kind CostKind.AllocationCost post) }
in

@ -10,8 +10,8 @@ type issue_spec =
{ extract_cost_f: Jsonbug_t.cost_item -> Jsonbug_t.cost_info
; name: string
; threshold: int option
; complexity_increase_issue: is_on_cold_start:bool -> IssueType.t
; expensive_issue: is_on_cold_start:bool -> IssueType.t
; complexity_increase_issue: is_on_cold_start:bool -> is_on_ui_thread:bool -> IssueType.t
; expensive_issue: is_on_cold_start:bool -> is_on_ui_thread:bool -> IssueType.t
; zero_issue: IssueType.t
; infinite_issue: IssueType.t
; top_and_bottom: bool }
@ -40,9 +40,11 @@ let enabled_cost_map =
; threshold= (if Config.use_cost_threshold then CostKind.to_threshold kind else None)
; extract_cost_f= (fun c -> CostKind.to_json_cost_info c kind)
; complexity_increase_issue=
(fun ~is_on_cold_start -> IssueType.complexity_increase ~kind ~is_on_cold_start)
(fun ~is_on_cold_start ~is_on_ui_thread ->
IssueType.complexity_increase ~kind ~is_on_cold_start ~is_on_ui_thread )
; expensive_issue=
(fun ~is_on_cold_start -> IssueType.expensive_cost_call ~kind ~is_on_cold_start)
(fun ~is_on_cold_start ~is_on_ui_thread ->
IssueType.expensive_cost_call ~kind ~is_on_cold_start ~is_on_ui_thread )
; zero_issue= IssueType.zero_cost_call ~kind
; infinite_issue= IssueType.infinite_cost_call ~kind
; top_and_bottom }

@ -11,8 +11,8 @@ type issue_spec =
{ extract_cost_f: Jsonbug_t.cost_item -> Jsonbug_t.cost_info
; name: string
; threshold: int option
; complexity_increase_issue: is_on_cold_start:bool -> IssueType.t
; expensive_issue: is_on_cold_start:bool -> IssueType.t
; complexity_increase_issue: is_on_cold_start:bool -> is_on_ui_thread:bool -> IssueType.t
; expensive_issue: is_on_cold_start:bool -> is_on_ui_thread:bool -> IssueType.t
; zero_issue: IssueType.t
; infinite_issue: IssueType.t
; top_and_bottom: bool }

@ -25,6 +25,7 @@ module Unsafe : sig
val register_from_cost_string :
?enabled:bool
-> ?is_on_cold_start:bool
-> ?is_on_ui_thread:bool
-> kind:CostKind.t
-> (string -> string, Format.formatter, unit, string) format4
-> t
@ -86,11 +87,13 @@ end = struct
(** cost issues are already registered below.*)
let register_from_cost_string ?(enabled = true) ?(is_on_cold_start = false) ~(kind : CostKind.t)
s =
let register_from_cost_string ?(enabled = true) ?(is_on_cold_start = false)
?(is_on_ui_thread = false) ~(kind : CostKind.t) s =
let issue_type_base = Format.asprintf s (CostKind.to_issue_string kind) in
let issue_type =
if is_on_cold_start then issue_type_base ^ "_COLD_START" else issue_type_base
if is_on_ui_thread then issue_type_base ^ "_UI_THREAD"
else if is_on_cold_start then issue_type_base ^ "_COLD_START"
else issue_type_base
in
register_from_string ~enabled issue_type
@ -266,8 +269,8 @@ let eradicate_return_over_annotated =
register_from_string "ERADICATE_RETURN_OVER_ANNOTATED" ~hum:"Return Over Annotated"
let expensive_cost_call ~kind ~is_on_cold_start =
register_from_cost_string ~enabled:false ~kind ~is_on_cold_start "EXPENSIVE_%s"
let expensive_cost_call ~kind ~is_on_cold_start ~is_on_ui_thread =
register_from_cost_string ~enabled:false ~kind ~is_on_cold_start ~is_on_ui_thread "EXPENSIVE_%s"
let exposed_insecure_intent_handling = register_from_string "EXPOSED_INSECURE_INTENT_HANDLING"
@ -423,8 +426,8 @@ let tainted_memory_allocation = register_from_string "TAINTED_MEMORY_ALLOCATION"
let thread_safety_violation = register_from_string "THREAD_SAFETY_VIOLATION"
let complexity_increase ~kind ~is_on_cold_start =
register_from_cost_string ~kind ~is_on_cold_start "%s_COMPLEXITY_INCREASE"
let complexity_increase ~kind ~is_on_cold_start ~is_on_ui_thread =
register_from_cost_string ~kind ~is_on_cold_start ~is_on_ui_thread "%s_COMPLEXITY_INCREASE"
let topl_error = register_from_string "TOPL_ERROR"
@ -483,8 +486,9 @@ let zero_cost_call ~kind = register_from_cost_string ~enabled:false ~kind "ZERO_
let () =
List.iter CostKind.enabled_cost_kinds ~f:(fun CostKind.{kind} ->
List.iter [true; false] ~f:(fun is_on_cold_start ->
let _ = zero_cost_call ~kind in
let _ = expensive_cost_call ~kind ~is_on_cold_start in
let _ = infinite_cost_call ~kind in
let _ = complexity_increase ~kind ~is_on_cold_start in
() ) )
List.iter [true; false] ~f:(fun is_on_ui_thread ->
let _ = zero_cost_call ~kind in
let _ = expensive_cost_call ~kind ~is_on_cold_start ~is_on_ui_thread in
let _ = infinite_cost_call ~kind in
let _ = complexity_increase ~kind ~is_on_cold_start ~is_on_ui_thread in
() ) ) )

@ -101,7 +101,7 @@ val codequery : t
val comparing_floats_for_equality : t
val complexity_increase : kind:CostKind.t -> is_on_cold_start:bool -> t
val complexity_increase : kind:CostKind.t -> is_on_cold_start:bool -> is_on_ui_thread:bool -> t
val component_factory_function : t
@ -162,7 +162,7 @@ val eradicate_return_not_nullable : t
val eradicate_return_over_annotated : t
val expensive_cost_call : kind:CostKind.t -> is_on_cold_start:bool -> t
val expensive_cost_call : kind:CostKind.t -> is_on_cold_start:bool -> is_on_ui_thread:bool -> t
val exposed_insecure_intent_handling : t

@ -10,6 +10,8 @@ module F = Format
module L = Logging
module BasicCost = CostDomain.BasicCost
let attrs_of_pname = Summary.OnDisk.proc_resolve_attributes
module Payload = SummaryPayload.Make (struct
type t = CostDomain.summary
@ -711,15 +713,15 @@ end
module Check = struct
let report_threshold proc_desc summary ~name ~location ~cost CostIssues.{expensive_issue}
~threshold =
~threshold ~is_on_ui_thread =
let pname = Procdesc.get_proc_name proc_desc in
let report_issue_type =
L.(debug Analysis Medium)
"@\n\n++++++ Checking error type for %a **** @\n" Typ.Procname.pp
(Procdesc.get_proc_name proc_desc) ;
"@\n\n++++++ Checking error type for %a **** @\n" Typ.Procname.pp pname ;
let is_on_cold_start =
ExternalPerfData.in_profiler_data_map (Procdesc.get_proc_name proc_desc)
in
expensive_issue ~is_on_cold_start
expensive_issue ~is_on_cold_start ~is_on_ui_thread
in
let bigO_str =
Format.asprintf ", %a"
@ -760,7 +762,7 @@ module Check = struct
else if BasicCost.is_zero cost then report zero_issue "is zero"
let check_and_report WorstCaseCost.{costs; reports} proc_desc summary =
let check_and_report ~is_on_ui_thread WorstCaseCost.{costs; reports} proc_desc summary =
let pname = Procdesc.get_proc_name proc_desc in
if not (Typ.Procname.is_java_access_method pname) then (
CostIssues.CostKindMap.iter2 CostIssues.enabled_cost_map reports
@ -769,7 +771,7 @@ module Check = struct
()
| ThresholdReports.ReportOn {location; cost} ->
report_threshold proc_desc summary ~name ~location ~cost kind_spec
~threshold:(Option.value_exn threshold) ) ;
~threshold:(Option.value_exn threshold) ~is_on_ui_thread ) ;
CostIssues.CostKindMap.iter2 CostIssues.enabled_cost_map costs
~f:(fun _kind (CostIssues.{name; top_and_bottom} as issue_spec) cost ->
if top_and_bottom then report_top_and_bottom proc_desc summary ~name ~cost issue_spec ) )
@ -811,9 +813,13 @@ let compute_worst_case_cost tenv integer_type_widths get_callee_summary_and_form
WorstCaseCost.compute tenv extras instr_cfg_wto
let get_cost_summary astate = CostDomain.{post= astate.WorstCaseCost.costs}
let get_cost_summary ~is_on_ui_thread astate =
CostDomain.{post= astate.WorstCaseCost.costs; is_on_ui_thread}
let report_errors ~is_on_ui_thread proc_desc astate summary =
Check.check_and_report ~is_on_ui_thread astate proc_desc summary
let report_errors proc_desc astate summary = Check.check_and_report astate proc_desc summary
let checker {Callbacks.exe_env; summary} : Summary.t =
let proc_name = Summary.get_proc_name summary in
@ -846,6 +852,7 @@ let checker {Callbacks.exe_env; summary} : Summary.t =
let bound_map =
compute_bound_map node_cfg inferbo_invariant_map control_dep_invariant_map loop_inv_map
in
let is_on_ui_thread = ConcurrencyModels.runs_on_ui_thread ~attrs_of_pname tenv proc_name in
let get_node_nb_exec = compute_get_node_nb_exec node_cfg bound_map in
let astate =
let get_callee_summary_and_formals callee_pname =
@ -867,5 +874,5 @@ let checker {Callbacks.exe_env; summary} : Summary.t =
(Container.length ~fold:NodeCFG.fold_nodes node_cfg)
CostDomain.VariantCostMap.pp exit_cost_record
in
report_errors proc_desc astate summary ;
Payload.update_summary (get_cost_summary astate) summary
report_errors ~is_on_ui_thread proc_desc astate summary ;
Payload.update_summary (get_cost_summary ~is_on_ui_thread astate) summary

@ -40,7 +40,7 @@ end
type t = VariantCostMap.t
type summary = {post: t}
type summary = {post: t; is_on_ui_thread: bool}
let pp_summary fmt {post} = F.fprintf fmt "@\n Post: %a @\n" VariantCostMap.pp post

@ -6,9 +6,10 @@
# E2E test for differential of costs
TESTS_DIR = ../..
SOURCES = src/DiffExample.java.current src/DiffExample.java.previous src/DiffExampleColdStart.java.current src/DiffExampleColdStart.java.previous
SOURCES = src/DiffExample.java.current src/DiffExample.java.previous src/DiffExampleColdStart.java.current src/DiffExampleColdStart.java.previous src/DiffExampleUIThread.java.current src/DiffExampleUIThread.java.previous
CLEAN_EXTRA = src/Diff*.java *.class
include $(TESTS_DIR)/differential.make
include $(TESTS_DIR)/java.make
INFERPRINT_ISSUES_FIELDS = \
"bug_type,bucket,file,procedure,line_offset,bug_trace"
@ -17,11 +18,13 @@ $(CURRENT_REPORT) $(PREVIOUS_REPORT): $(JAVA_DEPS)
$(CURRENT_REPORT):
$(QUIET)$(COPY) src/DiffExample.java.current src/DiffExample.java
$(QUIET)$(COPY) src/DiffExampleColdStart.java.current src/DiffExampleColdStart.java
$(QUIET)$(COPY) src/DiffExampleUIThread.java.current src/DiffExampleUIThread.java
$(QUIET)$(call silent_on_success,Testing Cost Differential: current,\
$(INFER_BIN) --enable-issue-type INFINITE_EXECUTION_TIME --cost-only -o $(CURRENT_DIR) -- $(JAVAC) src/*.java)
$(INFER_BIN) --enable-issue-type INFINITE_EXECUTION_TIME --cost-only -o $(CURRENT_DIR) -- $(JAVAC) -cp $(CLASSPATH) src/*.java)
$(PREVIOUS_REPORT):
$(QUIET)$(COPY) src/DiffExample.java.previous src/DiffExample.java
$(QUIET)$(COPY) src/DiffExampleColdStart.java.previous src/DiffExampleColdStart.java
$(QUIET)$(COPY) src/DiffExampleUIThread.java.previous src/DiffExampleUIThread.java
$(QUIET)$(call silent_on_success,Testing Cost Differential: previous,\
$(INFER_BIN) --debug --enable-issue-type INFINITE_EXECUTION_TIME --cost-only -o $(PREVIOUS_DIR) -- $(JAVAC) src/*.java)
$(INFER_BIN) --debug --enable-issue-type INFINITE_EXECUTION_TIME --cost-only -o $(PREVIOUS_DIR) -- $(JAVAC) -cp $(CLASSPATH) src/*.java)

@ -1 +1 @@
{"top":{"current":4,"previous":2},"zero":{"current":17,"previous":15},"degrees":[{"degree":0,"current":8,"previous":7},{"degree":100,"current":3,"previous":4},{"degree":101,"current":4,"previous":0},{"degree":200,"current":2,"previous":4}]}
{"top":{"current":4,"previous":2},"zero":{"current":21,"previous":19},"degrees":[{"degree":0,"current":11,"previous":10},{"degree":100,"current":4,"previous":5},{"degree":101,"current":4,"previous":0},{"degree":200,"current":2,"previous":4}]}

@ -1,2 +1,3 @@
EXECUTION_TIME_COMPLEXITY_INCREASE, no_bucket, src/DiffExample.java, DiffExample.f6(java.util.ArrayList):void, 0, [Updated Cost is 5 + list.length × log(list.length) (degree is 1 + 1⋅log),{list.length},call to void DiffExample.f5(ArrayList),Modeled call to Collections.sort,{list.length},call to void DiffExample.f5(ArrayList),Modeled call to Collections.sort]
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START, no_bucket, src/DiffExampleColdStart.java, DiffExampleColdStart.f6(java.util.ArrayList):void, 0, [Updated Cost is 5 + list.length × log(list.length) (degree is 1 + 1⋅log),{list.length},call to void DiffExampleColdStart.f5(ArrayList),Modeled call to Collections.sort,{list.length},call to void DiffExampleColdStart.f5(ArrayList),Modeled call to Collections.sort]
EXECUTION_TIME_COMPLEXITY_INCREASE_UI_THREAD, no_bucket, src/DiffExampleUIThread.java, DiffExampleUIThread.f1(int):void, 0, [Updated Cost is 3 (degree is 0)]

@ -6,3 +6,4 @@ INFINITE_EXECUTION_TIME, no_bucket, src/DiffExampleColdStart.java, DiffExampleCo
ALLOCATION_COMPLEXITY_INCREASE_COLD_START, no_bucket, src/DiffExampleColdStart.java, DiffExampleColdStart.f4(int):int, 0, [Updated Cost is k (degree is 1),{k},Loop at line 45]
EXECUTION_TIME_COMPLEXITY_INCREASE_COLD_START, no_bucket, src/DiffExampleColdStart.java, DiffExampleColdStart.f4(int):int, 0, [Updated Cost is 6 + 7 ⋅ k (degree is 1),{k},Loop at line 45]
EXECUTION_TIME_COMPLEXITY_INCREASE, no_bucket, src/DiffExampleColdStart.java, DiffExampleColdStart.f5(java.util.ArrayList):void, 0, [Updated Cost is 2 + list.length × log(list.length) (degree is 1 + 1⋅log),{list.length},Modeled call to Collections.sort,{list.length},Modeled call to Collections.sort]
EXECUTION_TIME_COMPLEXITY_INCREASE_UI_THREAD, no_bucket, src/DiffExampleUIThread.java, DiffExampleUIThread.f2(int):void, 0, [Updated Cost is 5 + 5 ⋅ x (degree is 1),{x},Loop at line 27]

@ -0,0 +1,36 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import android.support.annotation.UiThread;
// This class has the following costs:
// 3 constant, 1 linear
// constructor: constant
// f1: constant
// f2: linear
// f3: constant
public class DiffExampleUIThread {
@UiThread
public void f1(int x) {
x++;
}
@UiThread
public void f2(int x) {
for (int i = 0; i < x; i++) {}
}
@UiThread
public void f3(int x) {
f1(x);
}
}

@ -0,0 +1,36 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import android.support.annotation.UiThread;
// This class has the following costs:
// 3 constant, 1 linear
// constructor: constant
// f1: linear
// f2: constant
// f3: constant
public class DiffExampleUIThread {
@UiThread
public void f1(int x) {
for (int i = 0; i < x; i++) {}
}
@UiThread
public int f2(int x) {
return x+1;
}
@UiThread
public int f3(int x) {
return f2(x);
}
}

@ -0,0 +1,98 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
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 OnBind {}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
@interface OnEvent {}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
@interface OnMount {}
@UiThread
class AllMethodsOnUiThread {
int f;
void foo_UIThread_constant() {
f = 0;
}
int bar_UIThread_linear() {
for (int i = 0; i < f; i++) {
foo_UIThread_constant();
}
return f;
}
}
class ExtendsClassOnUiThread extends AllMethodsOnUiThread {
@Override
void foo_UIThread_constant() {
f = 9;
}
@Override
int bar_UIThread_linear() {
return super.bar_UIThread_linear();
}
}
class UIAnnotationTest {
// NOT All annotations that start with "On" are on the main thread
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
@interface OnXYZ {}
class WeirdAnnotation {
int f;
@OnXYZ
void foo_linear() {
for (int i = 0; i < f; i++) {}
}
}
class Annotations {
@UiThread
public void loop_UIThread_linear(int x) {
for (int i = 0; i < x; i++) {}
}
public void constant() {
// not on UI thread
}
public void loop_linear(int x) {
for (int i = 0; i < x; i++) {}
}
// anything annotated with OnEvent is modeled as running on the UIThread
@OnEvent
public void onClick_linear(int x) {
for (int i = 0; i < x; i++) {}
}
@OnBind
public void onBindMethod_linear(int x) {
loop_linear(x);
}
}
}

@ -194,6 +194,13 @@ codetoanalyze/java/performance/StringTest.java, StringTest.indexof_quadratic(jav
codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switch.test_switch():int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switch.test_switch():int, 3, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 798, O(1), degree = 0]
codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switch.vanilla_switch(int):void, 2, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.AllMethodsOnUiThread.bar_UIThread_linear():int, 1, EXPENSIVE_EXECUTION_TIME_UI_THREAD, no_bucket, ERROR, [with estimated cost 2 + 10 ⋅ (max(0, this.f)), O(this.f), degree = 1,{max(0, this.f)},Loop at line 37]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.ExtendsClassOnUiThread.bar_UIThread_linear():int, 0, EXPENSIVE_EXECUTION_TIME_UI_THREAD, no_bucket, ERROR, [with estimated cost 11 + 10 ⋅ (max(0, this.f)), O(this.f), degree = 1,{max(0, this.f)},call to int AllMethodsOnUiThread.bar_UIThread_linear(),Loop at line 37]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.UIAnnotationTest$Annotations.loop_UIThread_linear(int):void, 1, EXPENSIVE_EXECUTION_TIME_UI_THREAD, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ x, O(x), degree = 1,{x},Loop at line 76]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.UIAnnotationTest$Annotations.loop_linear(int):void, 1, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ x, O(x), degree = 1,{x},Loop at line 84]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.UIAnnotationTest$Annotations.onBindMethod_linear(int):void, 1, EXPENSIVE_EXECUTION_TIME_UI_THREAD, no_bucket, ERROR, [with estimated cost 8 + 5 ⋅ x, O(x), degree = 1,{x},call to void UIAnnotationTest$Annotations.loop_linear(int),Loop at line 84]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.UIAnnotationTest$Annotations.onClick_linear(int):void, 1, EXPENSIVE_EXECUTION_TIME_UI_THREAD, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ x, O(x), degree = 1,{x},Loop at line 90]
codetoanalyze/java/performance/UIAnnotationTest.java, codetoanalyze.java.checkers.UIAnnotationTest$WeirdAnnotation.foo_linear():void, 1, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 2 + 6 ⋅ this.f, O(this.f), degree = 1,{this.f},Loop at line 68]
codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.call_concrete_func_linear(UnknownCallsTest$AbstractC):void, 2, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 5 + 6 ⋅ UnknownCallsTest$AbstractC.abstract_func().length.ub, O(UnknownCallsTest$AbstractC.abstract_func().length.ub), degree = 1,{UnknownCallsTest$AbstractC.abstract_func().length.ub},Loop at line 94]
codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.call_loop_over_charArray(java.lang.StringBuilder,java.lang.String):void, 1, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 14 + 12 ⋅ String.toCharArray().length.ub, O(String.toCharArray().length.ub), degree = 1,{String.toCharArray().length.ub},call to void UnknownCallsTest.loop_over_charArray(StringBuilder,String),Loop at line 51]
codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.call_may_throw_exception_constant():void, 1, EXPENSIVE_ALLOCATION, no_bucket, ERROR, [with estimated cost 11, O(1), degree = 0]

Loading…
Cancel
Save