diff --git a/infer/src/checkers/performanceCritical.ml b/infer/src/checkers/performanceCritical.ml index 1c42376e3..beb78a226 100644 --- a/infer/src/checkers/performanceCritical.ml +++ b/infer/src/checkers/performanceCritical.ml @@ -125,13 +125,23 @@ let method_calls_expensive tenv pname = || calls_expensive () -let method_allocates pname = +let is_allocator tenv pname = + let is_exception () = + let class_name = + Typename.Java.from_string (Procname.java_get_class pname) in + AndroidFramework.is_exception tenv class_name in + Procname.is_constructor pname + && not (SymExec.function_is_builtin pname) + && not (is_exception ()) + + +let method_allocates tenv pname = let allocates () = match lookup_call_summary pname with | Some { Specs.allocations } -> allocations <> [] | None -> false in - Procname.is_constructor pname + is_allocator tenv pname || allocates () @@ -154,7 +164,7 @@ let collect_calls tenv caller_pdesc checked_pnames call_summary (pname, _) = else call_summary.Specs.expensive_calls in let updated_allocations = - if method_allocates pname then + if method_allocates tenv pname then (pname, call_loc) :: call_summary.Specs.allocations else call_summary.Specs.allocations in @@ -179,6 +189,7 @@ let update_summary call_summary pname = let string_of_pname = Procname.to_simplified_string ~withclass:true + let update_trace trace loc = if Location.equal loc Location.dummy then trace else diff --git a/infer/src/harness/androidFramework.ml b/infer/src/harness/androidFramework.ml index 813638bd8..7b5006dae 100644 --- a/infer/src/harness/androidFramework.ml +++ b/infer/src/harness/androidFramework.ml @@ -373,15 +373,26 @@ let get_lifecycle_for_framework_typ_opt lifecycle_typ lifecycle_proc_strs tenv = let get_lifecycles = android_lifecycles -(** Checks if the exception is an uncheched exception *) -let is_runtime_exception tenv exn = +let is_subclass tenv cn1 cn2 = let lookup = Sil.tenv_lookup tenv in + match lookup cn1, lookup cn2 with + | Some typ1, Some typ2 -> + is_subtype typ1 typ2 tenv + | _ -> false + + +(** Checks if the exception is an uncheched exception *) +let is_runtime_exception tenv typename = let runtime_exception_typename = Typename.Java.from_string "java.lang.RuntimeException" in - match lookup runtime_exception_typename, lookup exn with - | Some runtime_exception_type, Some exn_type -> - is_subtype exn_type runtime_exception_type tenv - | _ -> false + is_subclass tenv typename runtime_exception_typename + + +(** Checks if the class name is a Java exception *) +let is_exception tenv typename = + let exception_typename = + Typename.Java.from_string "java.lang.Exception" in + is_subclass tenv typename exception_typename let non_stub_android_jar () = diff --git a/infer/src/harness/androidFramework.mli b/infer/src/harness/androidFramework.mli index 0efeef0d4..827764d13 100644 --- a/infer/src/harness/androidFramework.mli +++ b/infer/src/harness/androidFramework.mli @@ -52,5 +52,8 @@ val is_android_lib_class : Typename.t -> bool (** Path to the android.jar file containing real code, not just the method stubs as in the SDK *) val non_stub_android_jar : unit -> string +(** [is_exception tenv class_name] checks if class_name is a Java exception *) +val is_exception : Sil.tenv -> Typename.t -> bool + (** [is_runtime_exception tenv exn] checks if exn is an unchecked exception *) val is_runtime_exception : Sil.tenv -> Typename.t -> bool diff --git a/infer/tests/codetoanalyze/java/checkers/NoAllocationExample.java b/infer/tests/codetoanalyze/java/checkers/NoAllocationExample.java index d8b131184..1d31ca1ac 100644 --- a/infer/tests/codetoanalyze/java/checkers/NoAllocationExample.java +++ b/infer/tests/codetoanalyze/java/checkers/NoAllocationExample.java @@ -40,4 +40,14 @@ public class NoAllocationExample { new Object(); } + @NoAllocation + void throwsException() { + throw new RuntimeException(); + } + + @NoAllocation + void creatingExceptionIsFine() { + throwsException(); + } + }