diff --git a/infer/src/base/IssueType.ml b/infer/src/base/IssueType.ml index a4632222f..1f32e2f5c 100644 --- a/infer/src/base/IssueType.ml +++ b/infer/src/base/IssueType.ml @@ -319,7 +319,7 @@ let lock_consistency_violation = from_string "LOCK_CONSISTENCY_VIOLATION" let logging_private_data = from_string "LOGGING_PRIVATE_DATA" -let loop_invariant_call = from_string "LOOP_INVARIANT_CALL" +let expensive_loop_invariant_call = from_string "EXPENSIVE_LOOP_INVARIANT_CALL" let memory_leak = from_string "MEMORY_LEAK" diff --git a/infer/src/base/IssueType.mli b/infer/src/base/IssueType.mli index 3225f0190..43661fa6a 100644 --- a/infer/src/base/IssueType.mli +++ b/infer/src/base/IssueType.mli @@ -223,7 +223,7 @@ val lock_consistency_violation : t val logging_private_data : t -val loop_invariant_call : t +val expensive_loop_invariant_call : t val memory_leak : t diff --git a/infer/src/checkers/hoisting.ml b/infer/src/checkers/hoisting.ml index a010bc2bc..cdd8995c3 100644 --- a/infer/src/checkers/hoisting.ml +++ b/infer/src/checkers/hoisting.ml @@ -80,10 +80,6 @@ let do_report summary Call.{pname; loc} ~issue loop_head_loc = Reporting.log_error summary ~loc ~ltr issue message -let model_satisfies ~f tenv pname = - InvariantModels.ProcName.dispatch tenv pname |> Option.exists ~f - - let is_call_expensive tenv integer_type_widths get_callee_cost_summary_and_formals inferbo_invariant_map (Call.{pname; node; ret; params} as call) = let last_node = InstrCFG.last_of_underlying_node node in @@ -114,21 +110,13 @@ let is_call_expensive tenv integer_type_widths get_callee_cost_summary_and_forma false -let is_call_variant_for_hoisting tenv call = - (* If a function is modeled as variant for hoisting (like List.size or __cast ), we don't want to report it *) - model_satisfies ~f:InvariantModels.is_variant_for_hoisting tenv call.Call.pname - - -let get_issue_to_report tenv should_report_invariant (Call.{pname} as call) = - if should_report_invariant call then - if model_satisfies ~f:InvariantModels.is_invariant tenv pname then - Some IssueType.loop_invariant_call - else Some IssueType.invariant_call - else None +let get_issue_to_report should_report_expensive_invariant call = + if should_report_expensive_invariant call then Some IssueType.expensive_loop_invariant_call + else Some IssueType.invariant_call let report_errors proc_desc tenv get_callee_purity reaching_defs_invariant_map - loop_head_to_source_nodes should_report_invariant summary = + loop_head_to_source_nodes should_report_expensive_invariant summary = (* get dominators *) let idom = Dominators.get_idoms proc_desc in (* get a map, loop head -> instrs that can be hoisted out of the loop *) @@ -144,7 +132,7 @@ let report_errors proc_desc tenv get_callee_purity reaching_defs_invariant_map let loop_head_loc = Procdesc.Node.get_loc loop_head in HoistCalls.iter (fun call -> - get_issue_to_report tenv should_report_invariant call + get_issue_to_report should_report_expensive_invariant call |> Option.iter ~f:(fun issue -> do_report summary call ~issue loop_head_loc) ) inv_instrs ) loop_head_to_inv_instrs @@ -155,7 +143,7 @@ let checker Callbacks.{tenv; summary; proc_desc; integer_type_widths} : Summary. (* computes reaching defs: node -> (var -> node set) *) let reaching_defs_invariant_map = ReachingDefs.compute_invariant_map proc_desc tenv in let loop_head_to_source_nodes = Loop_control.get_loop_head_to_source_nodes cfg in - let should_report_invariant = + let should_report_expensive_invariant = if Config.hoisting_report_only_expensive then let inferbo_invariant_map = BufferOverrunAnalysis.cached_compute_invariant_map proc_desc tenv integer_type_widths @@ -185,7 +173,7 @@ let checker Callbacks.{tenv; summary; proc_desc; integer_type_widths} : Summary. in is_call_expensive tenv integer_type_widths get_callee_cost_summary_and_formals inferbo_invariant_map - else fun call -> not (is_call_variant_for_hoisting tenv call) + else fun _ -> false in let get_callee_purity callee_pname = match Ondemand.analyze_proc_name ~caller_pdesc:proc_desc callee_pname with @@ -195,5 +183,5 @@ let checker Callbacks.{tenv; summary; proc_desc; integer_type_widths} : Summary. None in report_errors proc_desc tenv get_callee_purity reaching_defs_invariant_map - loop_head_to_source_nodes should_report_invariant summary ; + loop_head_to_source_nodes should_report_expensive_invariant summary ; summary diff --git a/infer/src/checkers/invariantModels.ml b/infer/src/checkers/invariantModels.ml index 46fbd3a83..6d42bd9b1 100644 --- a/infer/src/checkers/invariantModels.ml +++ b/infer/src/checkers/invariantModels.ml @@ -8,11 +8,9 @@ open! IStd module BuiltinInvariantSet = Caml.Set.Make (String) -type model = Invariant | Variant | VariantForHoisting +type model = Invariant | Variant -let is_invariant = function Invariant -> true | VariantForHoisting -> true | Variant -> false - -let is_variant_for_hoisting = function VariantForHoisting -> true | _ -> false +let is_invariant = function Invariant -> true | Variant -> false let invariants = BuiltinInvariantSet.of_list @@ -38,39 +36,37 @@ module ProcName = struct let dispatch : (Tenv.t, model) ProcnameDispatcher.ProcName.dispatcher = let open ProcnameDispatcher.ProcName in make_dispatcher - [ +invariant_builtins <>--> VariantForHoisting + [ +invariant_builtins <>--> Invariant + ; -"__variable_initialization" <>--> Invariant ; +(fun _ name -> BuiltinDecl.is_declared (Typ.Procname.from_string_c_fun name)) <>--> Variant - ; +PatternMatch.implements_android "text.TextUtils" &:: "isEmpty" <>--> VariantForHoisting - ; +PatternMatch.implements_android "view.ViewGroup" &:: "getChildAt" <>--> VariantForHoisting - ; +PatternMatch.implements_android "view.View" &::+ startsWith "get" <>--> VariantForHoisting - ; +PatternMatch.implements_android "view.View" - &::+ startsWith "findViewById" <>--> VariantForHoisting - ; +PatternMatch.implements_android "view.ViewGroup" - &:: "getChildCount" <>--> VariantForHoisting - ; +PatternMatch.implements_android "content.Context" - &::+ startsWith "get" <>--> VariantForHoisting + ; +PatternMatch.implements_android "text.TextUtils" &:: "isEmpty" <>--> Invariant + ; +PatternMatch.implements_android "view.ViewGroup" &:: "getChildAt" <>--> Invariant + ; +PatternMatch.implements_android "view.View" &::+ startsWith "get" <>--> Invariant + ; +PatternMatch.implements_android "view.View" &::+ startsWith "findViewById" <>--> Invariant + ; +PatternMatch.implements_android "view.ViewGroup" &:: "getChildCount" <>--> Invariant + ; +PatternMatch.implements_android "content.Context" &::+ startsWith "get" <>--> Invariant ; +PatternMatch.implements_android "content.res.Resources" - &::+ startsWith "get" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Iterable" &:: "iterator" <>--> VariantForHoisting - ; +PatternMatch.implements_collection &:: "iterator" <>--> VariantForHoisting - ; +PatternMatch.implements_iterator &:: "hasNext" <>--> VariantForHoisting + &::+ startsWith "get" <>--> Invariant + ; +PatternMatch.implements_lang "Iterable" &:: "iterator" <>--> Invariant + ; +PatternMatch.implements_collection &:: "iterator" <>--> Invariant + ; +PatternMatch.implements_iterator &:: "hasNext" <>--> Invariant ; +PatternMatch.implements_iterator &:: "next" <>--> Variant ; +PatternMatch.implements_iterator &:: "remove" <>--> Variant - ; +PatternMatch.implements_collection &:: "size" <>--> VariantForHoisting + ; +PatternMatch.implements_collection &:: "size" <>--> Invariant ; +PatternMatch.implements_collection &:: "add" <>--> Variant ; +PatternMatch.implements_collection &:: "addAll" <>--> Variant ; +PatternMatch.implements_collection &:: "remove" <>--> Variant - ; +PatternMatch.implements_collection &:: "isEmpty" <>--> VariantForHoisting - ; +PatternMatch.implements_collection &:: "get" <>--> VariantForHoisting + ; +PatternMatch.implements_collection &:: "isEmpty" <>--> Invariant + ; +PatternMatch.implements_collection &:: "get" <>--> Invariant ; +PatternMatch.implements_collection &:: "set" <>--> Variant (* Unlike Set.contains, List.contains is linear *) ; +PatternMatch.implements_list &:: "contains" <>--> Invariant - ; +PatternMatch.implements_collection &:: "contains" <>--> VariantForHoisting - ; +PatternMatch.implements_enumeration &:: "hasMoreElements" <>--> VariantForHoisting + ; +PatternMatch.implements_collection &:: "contains" <>--> Invariant + ; +PatternMatch.implements_enumeration &:: "hasMoreElements" <>--> Invariant ; +PatternMatch.implements_enumeration &:: "nextElement" <>--> Variant ; +PatternMatch.implements_google "common.base.Preconditions" - &::+ startsWith "check" <>--> VariantForHoisting + &::+ startsWith "check" <>--> Invariant ; +PatternMatch.implements_inject "Provider" &:: "get" <>--> Invariant ; +PatternMatch.implements_io "OutputStream" &:: "write" <>--> Variant ; +PatternMatch.implements_io "InputStream" &:: "read" <>--> Variant @@ -82,52 +78,48 @@ module ProcName = struct ; +PatternMatch.implements_jackson "databind.JsonDeserializer" &:: "deserialize" <>--> Invariant ; +PatternMatch.implements_jackson "core.JsonParser" &:: "nextToken" <>--> Variant - ; +PatternMatch.implements_jackson "core.JsonParser" - &:: "getCurrentName" <>--> VariantForHoisting - ; +PatternMatch.implements_jackson "core.JsonParser" - &::+ getStarValue <>--> VariantForHoisting - ; +PatternMatch.implements_jackson "core.JsonParser" - &::+ startsWith "get" <>--> VariantForHoisting - ; +PatternMatch.implements_pseudo_collection &:: "size" <>--> VariantForHoisting - ; +PatternMatch.implements_pseudo_collection &:: "get" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Math" &::.*--> VariantForHoisting - (* for (int|short|byte...)Value*) - ; +PatternMatch.implements_lang "Number" &::+ endsWith "Value" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Boolean" &:: "valueOf" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Boolean" &:: "parseBoolean" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Boolean" &::+ endsWith "Value" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Number" &:: "valueOf" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "String" &:: "length" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "String" &:: "charAt" <>--> VariantForHoisting + ; +PatternMatch.implements_jackson "core.JsonParser" &:: "getCurrentName" <>--> Invariant + ; +PatternMatch.implements_jackson "core.JsonParser" &::+ getStarValue <>--> Invariant + ; +PatternMatch.implements_jackson "core.JsonParser" &::+ startsWith "get" <>--> Invariant + ; +PatternMatch.implements_pseudo_collection &:: "size" <>--> Invariant + ; +PatternMatch.implements_pseudo_collection &:: "get" <>--> Invariant + ; +PatternMatch.implements_lang "Math" &::.*--> Invariant (* for (int|short|byte...)Value*) + ; +PatternMatch.implements_lang "Number" &::+ endsWith "Value" <>--> Invariant + ; +PatternMatch.implements_lang "Boolean" &:: "valueOf" <>--> Invariant + ; +PatternMatch.implements_lang "Boolean" &:: "parseBoolean" <>--> Invariant + ; +PatternMatch.implements_lang "Boolean" &::+ endsWith "Value" <>--> Invariant + ; +PatternMatch.implements_lang "Number" &:: "valueOf" <>--> Invariant + ; +PatternMatch.implements_lang "String" &:: "length" <>--> Invariant + ; +PatternMatch.implements_lang "String" &:: "charAt" <>--> Invariant (* substring in Java >= 1.7 has linear complexity *) ; +PatternMatch.implements_lang "String" &:: "substring" <>--> Invariant - ; +PatternMatch.implements_lang "CharSequence" &:: "charAt" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "String" &:: "equals" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "String" &:: "startsWith" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "String" &:: "valueOf" <>--> VariantForHoisting + ; +PatternMatch.implements_lang "CharSequence" &:: "charAt" <>--> Invariant + ; +PatternMatch.implements_lang "String" &:: "equals" <>--> Invariant + ; +PatternMatch.implements_lang "String" &:: "startsWith" <>--> Invariant + ; +PatternMatch.implements_lang "String" &:: "valueOf" <>--> Invariant ; +PatternMatch.implements_lang "String" &:: "replace" <>--> Variant - ; +PatternMatch.implements_lang "String" &:: "format" <>--> VariantForHoisting + ; +PatternMatch.implements_lang "String" &:: "format" <>--> Invariant (* String.hashCode is deterministic whereas Object's might not be *) - ; +PatternMatch.implements_lang "String" &:: "hashCode" <>--> VariantForHoisting + ; +PatternMatch.implements_lang "String" &:: "hashCode" <>--> Invariant ; +PatternMatch.implements_lang "StringBuilder" &:: "" <>--> Variant ; +PatternMatch.implements_lang "StringBuilder" &:: "append" <>--> Variant - ; +PatternMatch.implements_lang "StringBuilder" &:: "length" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Object" &:: "equals" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Object" &:: "toString" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Object" &:: "getClass" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Class" &:: "getSimpleName" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Class" &::+ startsWith "get" <>--> VariantForHoisting + ; +PatternMatch.implements_lang "StringBuilder" &:: "length" <>--> Invariant + ; +PatternMatch.implements_lang "Object" &:: "equals" <>--> Invariant + ; +PatternMatch.implements_lang "Object" &:: "toString" <>--> Invariant + ; +PatternMatch.implements_lang "Object" &:: "getClass" <>--> Invariant + ; +PatternMatch.implements_lang "Class" &:: "getSimpleName" <>--> Invariant + ; +PatternMatch.implements_lang "Class" &::+ startsWith "get" <>--> Invariant ; +PatternMatch.implements_lang "System" &:: "arraycopy" <>--> Variant - ; +PatternMatch.implements_lang "Enum" &:: "valueOf" <>--> VariantForHoisting - ; +PatternMatch.implements_lang "Enum" &:: "ordinal" <>--> VariantForHoisting - ; +PatternMatch.implements_map &:: "isEmpty" <>--> VariantForHoisting - ; +PatternMatch.implements_map &:: "get" <>--> VariantForHoisting + ; +PatternMatch.implements_lang "Enum" &:: "valueOf" <>--> Invariant + ; +PatternMatch.implements_lang "Enum" &:: "ordinal" <>--> Invariant + ; +PatternMatch.implements_map &:: "isEmpty" <>--> Invariant + ; +PatternMatch.implements_map &:: "get" <>--> Invariant ; +PatternMatch.implements_map &:: "put" <>--> Variant - ; +PatternMatch.implements_map &:: "containsKey" <>--> VariantForHoisting - ; +PatternMatch.implements_map_entry &:: "getKey" <>--> VariantForHoisting - ; +PatternMatch.implements_map_entry &:: "getValue" <>--> VariantForHoisting + ; +PatternMatch.implements_map &:: "containsKey" <>--> Invariant + ; +PatternMatch.implements_map_entry &:: "getKey" <>--> Invariant + ; +PatternMatch.implements_map_entry &:: "getValue" <>--> Invariant ; +PatternMatch.implements_queue &:: "poll" <>--> Variant ; +PatternMatch.implements_queue &:: "add" <>--> Variant ; +PatternMatch.implements_queue &:: "remove" <>--> Variant - ; +PatternMatch.implements_queue &:: "peek" <>--> VariantForHoisting ] + ; +PatternMatch.implements_queue &:: "peek" <>--> Invariant ] end diff --git a/infer/tests/codetoanalyze/java/hoisting/issues.exp b/infer/tests/codetoanalyze/java/hoisting/issues.exp index 22574bb99..0c6fa528b 100644 --- a/infer/tests/codetoanalyze/java/hoisting/issues.exp +++ b/infer/tests/codetoanalyze/java/hoisting/issues.exp @@ -7,7 +7,9 @@ codetoanalyze/java/hoisting/Hoist.java, Hoist.dep_not_invariant_dont_hoist(int,i codetoanalyze/java/hoisting/Hoist.java, Hoist.dumb_foo():void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void Hoist.dumb_foo()] codetoanalyze/java/hoisting/Hoist.java, Hoist.foo(int,int):int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int Hoist.foo(int,int)] codetoanalyze/java/hoisting/Hoist.java, Hoist.get_array_length_dont_hoist(int[]):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void Hoist.get_array_length_dont_hoist(int[])] +codetoanalyze/java/hoisting/Hoist.java, Hoist.get_array_length_dont_hoist(int[]):void, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to __get_array_length at line 157 is loop-invariant] codetoanalyze/java/hoisting/Hoist.java, Hoist.instanceof_dont_hoist(Hoist$EmptyFoo):boolean, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function boolean Hoist.instanceof_dont_hoist(Hoist$EmptyFoo)] +codetoanalyze/java/hoisting/Hoist.java, Hoist.instanceof_dont_hoist(Hoist$EmptyFoo):boolean, 4, INVARIANT_CALL, no_bucket, ERROR, [The call to __instanceof at line 171 is loop-invariant] codetoanalyze/java/hoisting/Hoist.java, Hoist.legit_hoist(int,int[]):void, 5, INVARIANT_CALL, no_bucket, ERROR, [The call to int Hoist.foo(int,int) at line 73 is loop-invariant] codetoanalyze/java/hoisting/Hoist.java, Hoist.loop_guard_hoist(int,int[]):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void Hoist.loop_guard_hoist(int,int[])] codetoanalyze/java/hoisting/Hoist.java, Hoist.loop_guard_hoist(int,int[]):void, 4, INVARIANT_CALL, no_bucket, ERROR, [The call to int Hoist.foo(int,int) at line 65 is loop-invariant] @@ -27,6 +29,7 @@ codetoanalyze/java/hoisting/Hoist.java, Hoist.void_hoist(int):void, 2, INVARIANT codetoanalyze/java/hoisting/Hoist.java, Hoist.x_not_invariant_dont_hoist(int,int,int):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void Hoist.x_not_invariant_dont_hoist(int,int,int)] codetoanalyze/java/hoisting/HoistGlobal.java, HoistGlobal$Foo.read_global():int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistGlobal$Foo.read_global()] codetoanalyze/java/hoisting/HoistGlobal.java, HoistGlobal$Foo.return_zero():int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistGlobal$Foo.return_zero()] +codetoanalyze/java/hoisting/HoistGlobal.java, HoistGlobal.global_modification_hoist_FN(java.util.ArrayList):int, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to int ArrayList.size() at line 49 is loop-invariant] codetoanalyze/java/hoisting/HoistGlobal.java, HoistGlobal.read_global():int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistGlobal.read_global()] codetoanalyze/java/hoisting/HoistGlobal.java, HoistGlobal.return_one():int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistGlobal.return_one()] codetoanalyze/java/hoisting/HoistIndirect.java, HoistIndirect$Test.deep_modification_dont_hoist(int):int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistIndirect$Test.deep_modification_dont_hoist(int)] @@ -53,10 +56,10 @@ codetoanalyze/java/hoisting/HoistInvalidate.java, HoistInvalidate.get_length(int codetoanalyze/java/hoisting/HoistInvalidate.java, HoistInvalidate.get_x(int[]):int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistInvalidate.get_x(int[])] codetoanalyze/java/hoisting/HoistInvalidate.java, HoistInvalidate.loop_indirect_hoist(java.util.ArrayList,int,int[]):void, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to int HoistInvalidate.get_length(int[]) at line 52 is loop-invariant] codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.deserialize_hoist(com.fasterxml.jackson.databind.JsonDeserializer,com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.deserialize_hoist(JsonDeserializer,JsonParser,DeserializationContext)] -codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.deserialize_hoist(com.fasterxml.jackson.databind.JsonDeserializer,com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext):void, 8, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to Object JsonDeserializer.deserialize(JsonParser,DeserializationContext) at line 33 is loop-invariant] +codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.deserialize_hoist(com.fasterxml.jackson.databind.JsonDeserializer,com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext):void, 8, INVARIANT_CALL, no_bucket, ERROR, [The call to Object JsonDeserializer.deserialize(JsonParser,DeserializationContext) at line 33 is loop-invariant] codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.list_contains_hoist(java.util.List,java.lang.String):int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistModeled.list_contains_hoist(List,String)] -codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.list_contains_hoist(java.util.List,java.lang.String):int, 3, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int,int) at line 18 is loop-invariant] -codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.list_contains_hoist(java.util.List,java.lang.String):int, 3, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to boolean List.contains(Object) at line 18 is loop-invariant] +codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.list_contains_hoist(java.util.List,java.lang.String):int, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to boolean List.contains(Object) at line 18 is loop-invariant] +codetoanalyze/java/hoisting/HoistModeled.java, HoistModeled.list_contains_hoist(java.util.List,java.lang.String):int, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int,int) at line 18 is loop-invariant] codetoanalyze/java/hoisting/HoistNoIndirectMod.java, HoistNoIndirectMod.avg(java.util.ArrayList):int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistNoIndirectMod.avg(ArrayList)] codetoanalyze/java/hoisting/HoistNoIndirectMod.java, HoistNoIndirectMod.calcNext():int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistNoIndirectMod.calcNext()] codetoanalyze/java/hoisting/HoistNoIndirectMod.java, HoistNoIndirectMod.calcSame():int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistNoIndirectMod.calcSame()] diff --git a/infer/tests/codetoanalyze/java/hoistingExpensive/issues.exp b/infer/tests/codetoanalyze/java/hoistingExpensive/issues.exp index 0a7971376..c27aba3a8 100644 --- a/infer/tests/codetoanalyze/java/hoistingExpensive/issues.exp +++ b/infer/tests/codetoanalyze/java/hoistingExpensive/issues.exp @@ -1,21 +1,26 @@ codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.cheap_dont_hoist(int):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistExpensive.cheap_dont_hoist(int)] +codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.cheap_dont_hoist(int):void, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to int HoistExpensive.incr(int) at line 19 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.cheap_iterator_dont_hoist(java.util.ArrayList):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistExpensive.cheap_iterator_dont_hoist(ArrayList)] +codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.cheap_iterator_dont_hoist(java.util.ArrayList):void, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to int HoistExpensive.incr(int) at line 41 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.incr(int):int, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function int HoistExpensive.incr(int)] codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.instantiated_cheap_hoist(int):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistExpensive.instantiated_cheap_hoist(int)] +codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.instantiated_cheap_hoist(int):void, 2, INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistExpensive.cheap_dont_hoist(int) at line 33 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.symbolic_expensive_hoist(int):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistExpensive.symbolic_expensive_hoist(int)] -codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.symbolic_expensive_hoist(int):void, 2, INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistExpensive.cheap_dont_hoist(int) at line 26 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.symbolic_expensive_hoist(int):void, 2, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistExpensive.cheap_dont_hoist(int) at line 26 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.symbolic_expensive_iterator_hoist(int,java.util.ArrayList):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistExpensive.symbolic_expensive_iterator_hoist(int,ArrayList)] -codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.symbolic_expensive_iterator_hoist(int,java.util.ArrayList):void, 2, INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistExpensive.cheap_iterator_dont_hoist(ArrayList) at line 48 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistExpensive.java, HoistExpensive.symbolic_expensive_iterator_hoist(int,java.util.ArrayList):void, 2, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistExpensive.cheap_iterator_dont_hoist(ArrayList) at line 48 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.call_expensive_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.call_expensive_hoist(String,ArrayList,Integer)] -codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.call_expensive_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 2, INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistModeled.expensive_get_hoist(int) at line 58 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.call_expensive_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 2, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistModeled.expensive_get_hoist(int) at line 58 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.constant_contains_dont_hoist(java.lang.Integer):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.constant_contains_dont_hoist(Integer)] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.constant_contains_dont_hoist(java.lang.Integer):void, 5, INVARIANT_CALL, no_bucket, ERROR, [The call to boolean ArrayList.contains(Object) at line 34 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.constant_substring_dont_hoist(java.lang.String):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.constant_substring_dont_hoist(String)] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.constant_substring_dont_hoist(java.lang.String):void, 3, INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int,int) at line 41 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.expensive_get_hoist(int):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.expensive_get_hoist(int)] -codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.expensive_get_hoist(int):void, 2, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to Object Provider.get() at line 16 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.expensive_get_hoist(int):void, 2, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to Object Provider.get() at line 16 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.expensive_get_hoist_hoist_me(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.expensive_get_hoist_hoist_me(String,ArrayList,Integer)] -codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.expensive_get_hoist_hoist_me(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 4, INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistModeled.call_expensive_hoist(String,ArrayList,Integer) at line 66 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.expensive_get_hoist_hoist_me(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 4, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to void HoistModeled.call_expensive_hoist(String,ArrayList,Integer) at line 66 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_contains_hoist(java.util.ArrayList,java.lang.Integer):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.linear_contains_hoist(ArrayList,Integer)] -codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_contains_hoist(java.util.ArrayList,java.lang.Integer):void, 3, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to boolean ArrayList.contains(Object) at line 23 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_contains_hoist(java.util.ArrayList,java.lang.Integer):void, 3, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to boolean ArrayList.contains(Object) at line 23 is loop-invariant] codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_substring_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 0, PURE_FUNCTION, no_bucket, ERROR, [Side-effect free function void HoistModeled.linear_substring_hoist(String,ArrayList,Integer)] -codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_substring_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 4, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int,int) at line 49 is loop-invariant] -codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_substring_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 7, LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int) at line 52 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_substring_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 4, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int,int) at line 49 is loop-invariant] +codetoanalyze/java/hoistingExpensive/HoistModeled.java, HoistModeled.linear_substring_hoist(java.lang.String,java.util.ArrayList,java.lang.Integer):void, 7, EXPENSIVE_LOOP_INVARIANT_CALL, no_bucket, ERROR, [The call to String String.substring(int) at line 52 is loop-invariant]