From feefda3e59e67ecea81f7047e2139ad6cafd8b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezgi=20=C3=87i=C3=A7ek?= Date: Wed, 29 Jul 2020 23:21:54 -0700 Subject: [PATCH] Wrap Java's PatternMatch into its own module Summary: This diff refactors Java specific `PatternMatch` functions into its own module. When `PatternMatch.ml` was originally created, it was mainly for Java but now it also supports ObjC. Let's refactor it to reflect the Java/ObjC separation: move all functions that operate on Java procnames into Java submodule. Reviewed By: jvillard Differential Revision: D22816504 fbshipit-source-id: ff6b64b29 --- infer/src/absint/ConcurrencyModels.ml | 2 +- infer/src/absint/NoReturnModels.ml | 4 +- infer/src/absint/PatternMatch.ml | 436 +++++++++--------- infer/src/absint/PatternMatch.mli | 168 +++---- .../bufferoverrun/bufferOverrunAnalysis.ml | 2 +- .../src/bufferoverrun/bufferOverrunModels.ml | 210 +++++---- .../bufferoverrun/bufferOverrunTypModels.ml | 8 +- infer/src/checkers/annotationReachability.ml | 4 +- .../src/checkers/inefficientKeysetIterator.ml | 6 +- infer/src/checkers/purityModels.ml | 189 ++++---- infer/src/concurrency/RacerDModels.ml | 2 +- infer/src/cost/costModels.ml | 71 +-- infer/src/nullsafe/AnnotatedField.ml | 2 +- infer/src/nullsafe/Initializers.ml | 2 +- infer/src/nullsafe/eradicate.ml | 2 +- infer/src/nullsafe/models.ml | 4 +- infer/src/pulse/PulseModels.ml | 59 +-- 17 files changed, 604 insertions(+), 567 deletions(-) diff --git a/infer/src/absint/ConcurrencyModels.ml b/infer/src/absint/ConcurrencyModels.ml index 360cbadfd..1bd92c358 100644 --- a/infer/src/absint/ConcurrencyModels.ml +++ b/infer/src/absint/ConcurrencyModels.ml @@ -300,7 +300,7 @@ let get_current_class_and_annotated_superclasses is_annot tenv pname = | Procname.Java java_pname -> let current_class = Procname.Java.get_class_type_name java_pname in let annotated_classes = - PatternMatch.find_superclasses_with_attributes is_annot tenv current_class + PatternMatch.Java.find_superclasses_with_attributes is_annot tenv current_class in Some (current_class, annotated_classes) | _ -> diff --git a/infer/src/absint/NoReturnModels.ml b/infer/src/absint/NoReturnModels.ml index a7b2ed920..7db455911 100644 --- a/infer/src/absint/NoReturnModels.ml +++ b/infer/src/absint/NoReturnModels.ml @@ -12,5 +12,5 @@ let no_return = true let dispatch : (Tenv.t, bool, unit) ProcnameDispatcher.ProcName.dispatcher = let open ProcnameDispatcher.ProcName in make_dispatcher - [ +PatternMatch.implements_lang "System" &:: "exit" <>--> no_return - ; +PatternMatch.implements_lang "Runtime" &:: "exit" <>--> no_return ] + [ +PatternMatch.Java.implements_lang "System" &:: "exit" <>--> no_return + ; +PatternMatch.Java.implements_lang "Runtime" &:: "exit" <>--> no_return ] diff --git a/infer/src/absint/PatternMatch.ml b/infer/src/absint/PatternMatch.ml index b0f434516..ce0e2d2f4 100644 --- a/infer/src/absint/PatternMatch.ml +++ b/infer/src/absint/PatternMatch.ml @@ -41,86 +41,6 @@ let is_subtype_of_str tenv cn1 classname_str = is_subtype tenv cn1 typename -let implements interface tenv typename = - let is_interface s _ = String.equal interface (Typ.Name.name s) in - supertype_exists tenv is_interface (Typ.Name.Java.from_string typename) - - -let implements_arrays = implements "java.util.Arrays" - -let implements_iterator = implements "java.util.Iterator" - -let implements_collection = implements "java.util.Collection" - -let implements_collections = implements "java.util.Collections" - -let implements_list = implements "java.util.List" - -let implements_xmob_utils class_name = implements ("com.moblica.common.xmob.utils." ^ class_name) - -let implements_pseudo_collection = - let androidx_class_names = - List.map - ~f:(fun class_name -> "androidx.collection." ^ class_name) - [ "ArrayMap" - ; "ArraySet" - ; "CircularArray" - ; "LongSparseArray" - ; "LruCache" - ; "SimpleArrayMap" - ; "SparseArrayCompat" ] - in - fun t s -> - implements "android.util.SparseArray" t s - || implements "android.util.SparseIntArray" t s - || implements_xmob_utils "IntArrayList" t s - || List.exists ~f:(fun class_name -> implements class_name t s) androidx_class_names - - -let implements_enumeration = implements "java.util.Enumeration" - -let implements_inject class_name = implements ("javax.inject." ^ class_name) - -let implements_io class_name = implements ("java.io." ^ class_name) - -let implements_nio class_name = implements ("java.nio." ^ class_name) - -let implements_map = implements "java.util.Map" - -let implements_androidx_map = implements "androidx.collection.SimpleArrayMap" - -let implements_set = implements "java.util.Set" - -let implements_map_entry = implements "java.util.Map$Entry" - -let implements_queue = implements "java.util.Queue" - -let implements_lang class_name = implements ("java.lang." ^ class_name) - -let implements_google class_name = implements ("com.google." ^ class_name) - -let implements_android class_name = implements ("android." ^ class_name) - -let implements_infer_annotation class_name = - implements ("com.facebook.infer.annotation." ^ class_name) - - -let implements_jackson class_name = implements ("com.fasterxml.jackson." ^ class_name) - -let implements_org_json class_name = implements ("org.json." ^ class_name) - -let implements_app_activity = implements "android.app.Activity" - -let implements_app_fragment = implements "androidx.fragment.app.Fragment" - -let implements_graphql_story = implements "com.facebook.graphql.model.GraphQLStory" - -let implements_psi_element = implements "com.intellij.psi.PsiElement" - -let implements_view_group = implements "android.view.ViewGroup" - -let implements_view_parent = implements "android.view.ViewParent" - (** The type the method is invoked on *) let get_this_type_nonstatic_methods_only proc_attributes = match proc_attributes.ProcAttributes.formals with (_, t) :: _ -> Some t | _ -> None @@ -174,18 +94,225 @@ let get_field_type_name tenv (typ : Typ.t) (fieldname : Fieldname.t) : string op None -let java_get_const_type_name (const : Const.t) : string = - match const with - | Const.Cstr _ -> - "java.lang.String" - | Const.Cint _ -> - "java.lang.Integer" - | Const.Cfloat _ -> - "java.lang.Double" - | _ -> - "_" +module Java = struct + let implements interface tenv typename = + let is_interface s _ = String.equal interface (Typ.Name.name s) in + supertype_exists tenv is_interface (Typ.Name.Java.from_string typename) + + + let implements_arrays = implements "java.util.Arrays" + + let implements_iterator = implements "java.util.Iterator" + + let implements_collection = implements "java.util.Collection" + + let implements_collections = implements "java.util.Collections" + + let implements_list = implements "java.util.List" + + let implements_xmob_utils class_name = implements ("com.moblica.common.xmob.utils." ^ class_name) + + let implements_pseudo_collection = + let androidx_class_names = + List.map + ~f:(fun class_name -> "androidx.collection." ^ class_name) + [ "ArrayMap" + ; "ArraySet" + ; "CircularArray" + ; "LongSparseArray" + ; "LruCache" + ; "SimpleArrayMap" + ; "SparseArrayCompat" ] + in + fun t s -> + implements "android.util.SparseArray" t s + || implements "android.util.SparseIntArray" t s + || implements_xmob_utils "IntArrayList" t s + || List.exists ~f:(fun class_name -> implements class_name t s) androidx_class_names + + + let implements_enumeration = implements "java.util.Enumeration" + + let implements_inject class_name = implements ("javax.inject." ^ class_name) + + let implements_io class_name = implements ("java.io." ^ class_name) + + let implements_nio class_name = implements ("java.nio." ^ class_name) + + let implements_map = implements "java.util.Map" + + let implements_androidx_map = implements "androidx.collection.SimpleArrayMap" + + let implements_set = implements "java.util.Set" + + let implements_map_entry = implements "java.util.Map$Entry" + + let implements_queue = implements "java.util.Queue" + + let implements_lang class_name = implements ("java.lang." ^ class_name) + + let implements_google class_name = implements ("com.google." ^ class_name) + + let implements_android class_name = implements ("android." ^ class_name) + + let implements_infer_annotation class_name = + implements ("com.facebook.infer.annotation." ^ class_name) + + + let implements_jackson class_name = implements ("com.fasterxml.jackson." ^ class_name) + + let implements_org_json class_name = implements ("org.json." ^ class_name) + + let implements_app_activity = implements "android.app.Activity" + + let implements_app_fragment = implements "androidx.fragment.app.Fragment" + + let implements_graphql_story = implements "com.facebook.graphql.model.GraphQLStory" + + let implements_psi_element = implements "com.intellij.psi.PsiElement" + + let implements_view_group = implements "android.view.ViewGroup" + + let implements_view_parent = implements "android.view.ViewParent" + + let initializer_classes = + List.map ~f:Typ.Name.Java.from_string + [ "android.app.Activity" + ; "android.app.Application" + ; "android.app.Fragment" + ; "android.app.Service" + ; "android.support.v4.app.Fragment" + ; "androidx.fragment.app.Fragment" + ; "junit.framework.TestCase" ] + + + let initializer_methods = ["onActivityCreated"; "onAttach"; "onCreate"; "onCreateView"; "setUp"] + + (** Check if the type has in its supertypes from the initializer_classes list. *) + let type_has_initializer (tenv : Tenv.t) (t : Typ.t) : bool = + let is_initializer_class typename _ = + List.mem ~equal:Typ.Name.equal initializer_classes typename + in + match t.desc with + | Typ.Tstruct name | Tptr ({desc= Tstruct name}, _) -> + supertype_exists tenv is_initializer_class name + | _ -> + false + + + (** Check if the method is one of the known initializer methods. *) + let method_is_initializer (tenv : Tenv.t) (proc_attributes : ProcAttributes.t) : bool = + match get_this_type_nonstatic_methods_only proc_attributes with + | Some this_type -> + if type_has_initializer tenv this_type then + match proc_attributes.ProcAttributes.proc_name with + | Procname.Java pname_java -> + let mname = Procname.Java.get_method pname_java in + List.exists ~f:(String.equal mname) initializer_methods + | _ -> + false + else false + | None -> + false + + + let get_const_type_name (const : Const.t) : string = + match const with + | Const.Cstr _ -> + "java.lang.String" + | Const.Cint _ -> + "java.lang.Integer" + | Const.Cfloat _ -> + "java.lang.Double" + | _ -> + "" + + + (** Checks if the class name is a Java exception *) + let is_throwable tenv typename = is_subtype_of_str tenv typename "java.lang.Throwable" + + let is_enum tenv typename = is_subtype_of_str tenv typename "java.lang.Enum" + + (** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, + including for supertypes*) + let check_class_attributes check tenv = function + | Procname.Java java_pname -> + let check_class_annots _ {Struct.annots} = check annots in + supertype_exists tenv check_class_annots (Procname.Java.get_class_type_name java_pname) + | _ -> + false + + + (** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, for the + current class only*) + let check_current_class_attributes check tenv = function + | Procname.Java java_pname -> ( + match Tenv.lookup tenv (Procname.Java.get_class_type_name java_pname) with + | Some struct_typ -> + check struct_typ.annots + | _ -> + false ) + | _ -> + false + + + (** find superclasss with attributes (e.g., [@ThreadSafe]), including current class*) + let rec find_superclasses_with_attributes check tenv tname = + match Tenv.lookup tenv tname with + | Some struct_typ -> + let result_from_supers = + List.concat (List.map ~f:(find_superclasses_with_attributes check tenv) struct_typ.supers) + in + if check struct_typ.annots then tname :: result_from_supers else result_from_supers + | _ -> + [] + + + let is_override_of_lang_object_equals curr_pname = + let is_only_param_of_object_type = function + | [Procname.Parameter.JavaParameter param_type] + when JavaSplitName.equal param_type JavaSplitName.java_lang_object -> + true + | _ -> + false + in + String.equal (Procname.get_method curr_pname) "equals" + && is_only_param_of_object_type (Procname.get_parameters curr_pname) +end + +module ObjectiveC = struct + let is_core_graphics_create_or_copy _ procname = + String.is_prefix ~prefix:"CG" procname + && ( String.is_substring ~substring:"Create" procname + || String.is_substring ~substring:"Copy" procname ) + + + let is_core_foundation_create_or_copy _ procname = + String.is_prefix ~prefix:"CF" procname + && ( String.is_substring ~substring:"Create" procname + || String.is_substring ~substring:"Copy" procname ) + let is_core_graphics_release _ procname = + String.is_prefix ~prefix:"CG" procname && String.is_suffix ~suffix:"Release" procname + + + let is_modelled_as_alloc _ procname = + match Config.pulse_model_alloc_pattern with + | Some regex -> + Str.string_match regex procname 0 + | None -> + false + + + let is_modelled_as_release _ procname = + match Config.pulse_model_release_pattern with + | Some regex -> + Str.string_match regex procname 0 + | None -> + false +end + let get_vararg_type_names tenv (call_node : Procdesc.Node.t) (ivar : Pvar.t) : string list = (* Is this the node creating ivar? *) let initializes_array instrs = @@ -225,7 +352,7 @@ let get_vararg_type_names tenv (call_node : Procdesc.Node.t) (ivar : Pvar.t) : s Some (nvar_type_name nvar) | Sil.Store {e1= Exp.Lindex (Exp.Var iv, _); e2= Exp.Const c} when Ident.equal iv array_nvar -> - Some (Some (java_get_const_type_name c)) + Some (Some (Java.get_const_type_name c)) | _ -> None ) |> Option.join @@ -271,47 +398,6 @@ let type_is_class typ = false -let initializer_classes = - List.map ~f:Typ.Name.Java.from_string - [ "android.app.Activity" - ; "android.app.Application" - ; "android.app.Fragment" - ; "android.app.Service" - ; "android.support.v4.app.Fragment" - ; "androidx.fragment.app.Fragment" - ; "junit.framework.TestCase" ] - - -let initializer_methods = ["onActivityCreated"; "onAttach"; "onCreate"; "onCreateView"; "setUp"] - -(** Check if the type has in its supertypes from the initializer_classes list. *) -let type_has_initializer (tenv : Tenv.t) (t : Typ.t) : bool = - let is_initializer_class typename _ = - List.mem ~equal:Typ.Name.equal initializer_classes typename - in - match t.desc with - | Typ.Tstruct name | Tptr ({desc= Tstruct name}, _) -> - supertype_exists tenv is_initializer_class name - | _ -> - false - - -(** Check if the method is one of the known initializer methods. *) -let method_is_initializer (tenv : Tenv.t) (proc_attributes : ProcAttributes.t) : bool = - match get_this_type_nonstatic_methods_only proc_attributes with - | Some this_type -> - if type_has_initializer tenv this_type then - match proc_attributes.ProcAttributes.proc_name with - | Procname.Java pname_java -> - let mname = Procname.Java.get_method pname_java in - List.exists ~f:(String.equal mname) initializer_methods - | _ -> - false - else false - | None -> - false - - let proc_calls resolve_attributes pdesc filter : (Procname.t * ProcAttributes.t) list = let res = ref [] in let do_instruction _ instr = @@ -422,89 +508,3 @@ let get_fields_nullified procdesc = ~init:(Fieldname.Set.empty, Ident.Set.empty) in nullified_flds - - -(** Checks if the class name is a Java exception *) -let is_throwable tenv typename = is_subtype_of_str tenv typename "java.lang.Throwable" - -let is_java_enum tenv typename = is_subtype_of_str tenv typename "java.lang.Enum" - -(** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, including - for supertypes*) -let check_class_attributes check tenv = function - | Procname.Java java_pname -> - let check_class_annots _ {Struct.annots} = check annots in - supertype_exists tenv check_class_annots (Procname.Java.get_class_type_name java_pname) - | _ -> - false - - -(** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, for the - current class only*) -let check_current_class_attributes check tenv = function - | Procname.Java java_pname -> ( - match Tenv.lookup tenv (Procname.Java.get_class_type_name java_pname) with - | Some struct_typ -> - check struct_typ.annots - | _ -> - false ) - | _ -> - false - - -(** find superclasss with attributes (e.g., [@ThreadSafe]), including current class*) -let rec find_superclasses_with_attributes check tenv tname = - match Tenv.lookup tenv tname with - | Some struct_typ -> - let result_from_supers = - List.concat (List.map ~f:(find_superclasses_with_attributes check tenv) struct_typ.supers) - in - if check struct_typ.annots then tname :: result_from_supers else result_from_supers - | _ -> - [] - - -let is_override_of_java_lang_object_equals curr_pname = - let is_only_param_of_object_type = function - | [Procname.Parameter.JavaParameter param_type] - when JavaSplitName.equal param_type JavaSplitName.java_lang_object -> - true - | _ -> - false - in - String.equal (Procname.get_method curr_pname) "equals" - && is_only_param_of_object_type (Procname.get_parameters curr_pname) - - -module ObjectiveC = struct - let is_core_graphics_create_or_copy _ procname = - String.is_prefix ~prefix:"CG" procname - && ( String.is_substring ~substring:"Create" procname - || String.is_substring ~substring:"Copy" procname ) - - - let is_core_foundation_create_or_copy _ procname = - String.is_prefix ~prefix:"CF" procname - && ( String.is_substring ~substring:"Create" procname - || String.is_substring ~substring:"Copy" procname ) - - - let is_core_graphics_release _ procname = - String.is_prefix ~prefix:"CG" procname && String.is_suffix ~suffix:"Release" procname - - - let is_modelled_as_alloc _ procname = - match Config.pulse_model_alloc_pattern with - | Some regex -> - Str.string_match regex procname 0 - | None -> - false - - - let is_modelled_as_release _ procname = - match Config.pulse_model_release_pattern with - | Some regex -> - Str.string_match regex procname 0 - | None -> - false -end diff --git a/infer/src/absint/PatternMatch.mli b/infer/src/absint/PatternMatch.mli index 74d8af40b..b41a72651 100644 --- a/infer/src/absint/PatternMatch.mli +++ b/infer/src/absint/PatternMatch.mli @@ -19,101 +19,125 @@ val get_type_name : Typ.t -> string val get_vararg_type_names : Tenv.t -> Procdesc.Node.t -> Pvar.t -> string list (** Get the type names of a variable argument *) -val method_is_initializer : Tenv.t -> ProcAttributes.t -> bool -(** Check if the method is one of the known initializer methods. *) - val is_subtype : Tenv.t -> Typ.Name.t -> Typ.Name.t -> bool (** Is the type a transitive subtype of the typename? *) val is_subtype_of_str : Tenv.t -> Typ.Name.t -> string -> bool (** Resolve [typ_str] in [tenv], then check [typ] <: [typ_str] *) -val implements : string -> Tenv.t -> string -> bool -(** Check whether class implements a given class *) +module Java : sig + val implements : string -> Tenv.t -> string -> bool + (** Check whether class implements a given Java class *) + + val implements_arrays : Tenv.t -> string -> bool + (** Check whether class implements Java's Arrays *) + + val implements_iterator : Tenv.t -> string -> bool + (** Check whether class implements Java's Iterator *) + + val implements_collection : Tenv.t -> string -> bool + (** Check whether class implements a Java's Collection *) -val implements_arrays : Tenv.t -> string -> bool -(** Check whether class implements Java's Arrays *) + val implements_collections : Tenv.t -> string -> bool + (** Check whether class implements a Java's Collections *) -val implements_iterator : Tenv.t -> string -> bool -(** Check whether class implements Java's Iterator *) + val implements_pseudo_collection : Tenv.t -> string -> bool + (** Check whether class implements a pseudo Collection with support for get() and size() methods *) -val implements_collection : Tenv.t -> string -> bool -(** Check whether class implements a Java's Collection *) + val implements_enumeration : Tenv.t -> string -> bool + (** Check whether class implements a Java's Enumeration *) -val implements_collections : Tenv.t -> string -> bool -(** Check whether class implements a Java's Collections *) + val implements_jackson : string -> Tenv.t -> string -> bool + (** Check whether class implements a class from Jackson *) -val implements_pseudo_collection : Tenv.t -> string -> bool -(** Check whether class implements a pseudo Collection with support for get() and size() methods *) + val implements_org_json : string -> Tenv.t -> string -> bool + (** Check whether class implements a class from Json *) -val implements_enumeration : Tenv.t -> string -> bool -(** Check whether class implements a Java's Enumeration *) + val implements_inject : string -> Tenv.t -> string -> bool + (** Check whether class implements a Javax Inject *) -val implements_jackson : string -> Tenv.t -> string -> bool -(** Check whether class implements a class from Jackson *) + val implements_io : string -> Tenv.t -> string -> bool + (** Check whether class implements a Java IO *) -val implements_org_json : string -> Tenv.t -> string -> bool -(** Check whether class implements a class from Json *) + val implements_nio : string -> Tenv.t -> string -> bool + (** Check whether class implements a Java nio *) -val implements_inject : string -> Tenv.t -> string -> bool -(** Check whether class implements a Javax Inject *) + val implements_map : Tenv.t -> string -> bool + (** Check whether class implements a Java's Map *) -val implements_io : string -> Tenv.t -> string -> bool -(** Check whether class implements a Java IO *) + val implements_androidx_map : Tenv.t -> string -> bool + (** Check whether class implements a AndroidX's Map *) -val implements_nio : string -> Tenv.t -> string -> bool -(** Check whether class implements a Java nio *) + val implements_set : Tenv.t -> string -> bool + (** Check whether class implements a Java's Set *) -val implements_map : Tenv.t -> string -> bool -(** Check whether class implements a Java's Map *) + val implements_map_entry : Tenv.t -> string -> bool + (** Check whether class implements a Java's Map$Entry *) -val implements_androidx_map : Tenv.t -> string -> bool -(** Check whether class implements a AndroidX's Map *) + val implements_queue : Tenv.t -> string -> bool + (** Check whether class implements a Java's Queue *) -val implements_set : Tenv.t -> string -> bool -(** Check whether class implements a Java's Set *) + val implements_lang : string -> Tenv.t -> string -> bool + (** Check whether class implements a Java's lang *) -val implements_map_entry : Tenv.t -> string -> bool -(** Check whether class implements a Java's Map$Entry *) + val implements_list : Tenv.t -> string -> bool + (** Check whether class implements a Java's list *) -val implements_queue : Tenv.t -> string -> bool -(** Check whether class implements a Java's Queue *) + val implements_google : string -> Tenv.t -> string -> bool + (** Check whether class implements a class of Google *) -val implements_lang : string -> Tenv.t -> string -> bool -(** Check whether class implements a Java's lang *) + val implements_android : string -> Tenv.t -> string -> bool + (** Check whether class implements a class of Android *) -val implements_list : Tenv.t -> string -> bool -(** Check whether class implements a Java's list *) + val implements_infer_annotation : string -> Tenv.t -> string -> bool + (** Check whether class implements a class of Infer annotation *) -val implements_google : string -> Tenv.t -> string -> bool -(** Check whether class implements a class of Google *) + val implements_app_activity : Tenv.t -> string -> bool + (** Check whether class implements a class of [android.app.Activity] *) -val implements_android : string -> Tenv.t -> string -> bool -(** Check whether class implements a class of Android *) + val implements_app_fragment : Tenv.t -> string -> bool + (** Check whether class implements a class of [androidx.fragment.app.Fragment] *) -val implements_infer_annotation : string -> Tenv.t -> string -> bool -(** Check whether class implements a class of Infer annotation *) + val implements_graphql_story : Tenv.t -> string -> bool + (** Check whether class implements a class of [com.facebook.graphql.model.GraphQLStory] *) -val implements_app_activity : Tenv.t -> string -> bool -(** Check whether class implements a class of [android.app.Activity] *) + val implements_psi_element : Tenv.t -> string -> bool + (** Check whether class implements a class of [com.intellij.psi.PsiElement] *) -val implements_app_fragment : Tenv.t -> string -> bool -(** Check whether class implements a class of [androidx.fragment.app.Fragment] *) + val implements_view_group : Tenv.t -> string -> bool + (** Check whether class implements a class of [android.view.ViewGroup] *) -val implements_graphql_story : Tenv.t -> string -> bool -(** Check whether class implements a class of [com.facebook.graphql.model.GraphQLStory] *) + val implements_view_parent : Tenv.t -> string -> bool + (** Check whether class implements a class of [android.view.ViewParent] *) -val implements_psi_element : Tenv.t -> string -> bool -(** Check whether class implements a class of [com.intellij.psi.PsiElement] *) + val implements_xmob_utils : string -> Tenv.t -> string -> bool + (** Check whether class implements a class of xmod.utils *) -val implements_view_group : Tenv.t -> string -> bool -(** Check whether class implements a class of [android.view.ViewGroup] *) + val is_throwable : Tenv.t -> Typ.Name.t -> bool + (** [is_throwable tenv class_name] checks if class_name is of type java.lang.Throwable *) -val implements_view_parent : Tenv.t -> string -> bool -(** Check whether class implements a class of [android.view.ViewParent] *) + val is_enum : Tenv.t -> Typ.Name.t -> bool + (** Checks if the type is Java enum (extends java.lang.Enum) *) -val implements_xmob_utils : string -> Tenv.t -> string -> bool -(** Check whether class implements a class of xmod.utils *) + val check_class_attributes : (Annot.Item.t -> bool) -> Tenv.t -> Procname.t -> bool + (** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, + including supertypes*) + + val check_current_class_attributes : (Annot.Item.t -> bool) -> Tenv.t -> Procname.t -> bool + (** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, for + current class only*) + + val find_superclasses_with_attributes : + (Annot.Item.t -> bool) -> Tenv.t -> Typ.Name.t -> Typ.Name.t list + (** find superclasss with attributes (e.g., [@ThreadSafe]), including current class*) + + val is_override_of_lang_object_equals : Procname.t -> bool + (** Whether the method is an override of `java.lang.Object.equals(Object)` or + `java.lang.Object.equals(Object)` itself *) + + val method_is_initializer : Tenv.t -> ProcAttributes.t -> bool + (** Check if the method is one of the known initializer methods. *) +end val supertype_exists : Tenv.t -> (Typ.Name.t -> Struct.t -> bool) -> Typ.Name.t -> bool (** Holds iff the predicate holds on a supertype of the named type, including the type itself *) @@ -153,32 +177,10 @@ val type_is_class : Typ.t -> bool val get_fields_nullified : Procdesc.t -> Fieldname.Set.t (** return the set of instance fields that are assigned to a null literal in [procdesc] *) -val is_throwable : Tenv.t -> Typ.Name.t -> bool -(** [is_throwable tenv class_name] checks if class_name is of type java.lang.Throwable *) - -val is_java_enum : Tenv.t -> Typ.Name.t -> bool -(** Checks if the type is Java enum (extends java.lang.Enum) *) - -val check_class_attributes : (Annot.Item.t -> bool) -> Tenv.t -> Procname.t -> bool -(** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, including - supertypes*) - -val check_current_class_attributes : (Annot.Item.t -> bool) -> Tenv.t -> Procname.t -> bool -(** tests whether any class attributes (e.g., [@ThreadSafe]) pass check of first argument, for - current class only*) - -val find_superclasses_with_attributes : - (Annot.Item.t -> bool) -> Tenv.t -> Typ.Name.t -> Typ.Name.t list -(** find superclasss with attributes (e.g., [@ThreadSafe]), including current class*) - val has_same_signature : Procname.t -> (Procname.t -> bool) Staged.t (** For a given [procname] checks if the method has the same method name, number, order and types of parameters.) *) -val is_override_of_java_lang_object_equals : Procname.t -> bool -(** Whether the method is an override of `java.lang.Object.equals(Object)` or - `java.lang.Object.equals(Object)` itself *) - module ObjectiveC : sig val is_core_graphics_create_or_copy : Tenv.t -> string -> bool diff --git a/infer/src/bufferoverrun/bufferOverrunAnalysis.ml b/infer/src/bufferoverrun/bufferOverrunAnalysis.ml index 6b0fdd89a..26cf25ca6 100644 --- a/infer/src/bufferoverrun/bufferOverrunAnalysis.ml +++ b/infer/src/bufferoverrun/bufferOverrunAnalysis.ml @@ -156,7 +156,7 @@ module TransferFunctions = struct let is_java_enum_values tenv callee_pname = Option.exists (Procname.get_class_type_name callee_pname) ~f:(fun callee_class_name -> - PatternMatch.is_java_enum tenv callee_class_name + PatternMatch.Java.is_enum tenv callee_class_name && String.equal (Procname.get_method callee_pname) "values" ) diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index b6fb33f55..8f41a3cf3 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -1514,16 +1514,16 @@ module Call = struct ; -"__get_array_length" <>$ capt_exp $!--> get_array_length ; -"__infer_objc_cpp_throw" <>--> bottom ; -"__new" - <>$ any_arg_of_typ (+PatternMatch.implements_collection) + <>$ any_arg_of_typ (+PatternMatch.Java.implements_collection) $+...$--> Collection.new_collection ; -"__new" - <>$ any_arg_of_typ (+PatternMatch.implements_map) + <>$ any_arg_of_typ (+PatternMatch.Java.implements_map) $+...$--> Collection.new_collection ; -"__new" - <>$ any_arg_of_typ (+PatternMatch.implements_org_json "JSONArray") + <>$ any_arg_of_typ (+PatternMatch.Java.implements_org_json "JSONArray") $+...$--> Collection.new_collection ; -"__new" - <>$ any_arg_of_typ (+PatternMatch.implements_pseudo_collection) + <>$ any_arg_of_typ (+PatternMatch.Java.implements_pseudo_collection) $+...$--> Collection.new_collection ; -"__new" <>$ capt_exp $+...$--> malloc ~can_be_zero:true ; -"__new_array" <>$ capt_exp $+...$--> malloc ~can_be_zero:true @@ -1661,162 +1661,176 @@ module Call = struct ; -"google" &:: "StrLen" <>$ capt_exp $--> strlen ; (* Java models *) -"java.lang.Object" &:: "clone" <>$ capt_exp $--> Object.clone - ; +PatternMatch.implements_arrays &:: "asList" <>$ capt_exp $!--> create_copy_array - ; +PatternMatch.implements_arrays &:: "copyOf" <>$ capt_exp $+ capt_exp - $+...$--> Collection.copyOf + ; +PatternMatch.Java.implements_arrays &:: "asList" <>$ capt_exp $!--> create_copy_array + ; +PatternMatch.Java.implements_arrays + &:: "copyOf" <>$ capt_exp $+ capt_exp $+...$--> Collection.copyOf ; (* model sets and maps as lists *) - +PatternMatch.implements_collection + +PatternMatch.Java.implements_collection &:: "" <>$ capt_var_exn - $+ capt_exp_of_typ (+PatternMatch.implements_collection) + $+ capt_exp_of_typ (+PatternMatch.Java.implements_collection) $--> Collection.init_with_arg - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "" <>$ any_arg $+ capt_exp $--> Collection.init_with_capacity - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "add" <>$ capt_var_exn $+ capt_exp $+ any_arg $--> Collection.add_at_index - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "add" <>$ capt_var_exn $+ capt_exp $--> Collection.add - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "addAll" <>$ capt_var_exn $+ capt_exp $+ capt_exp $--> Collection.addAll_at_index - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "addAll" <>$ capt_var_exn $+ capt_exp $--> Collection.addAll - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "get" <>$ capt_var_exn $+ capt_exp $--> Collection.get_at_index - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "remove" <>$ capt_var_exn $+ capt_exp $--> Collection.remove_at_index - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "set" <>$ capt_var_exn $+ capt_exp $+ capt_exp $--> Collection.set_at_index - ; +PatternMatch.implements_collection &:: "size" <>$ capt_exp $!--> Collection.size - ; +PatternMatch.implements_collection &:: "toArray" <>$ capt_exp $+...$--> create_copy_array - ; +PatternMatch.implements_collections &:: "emptyList" <>--> Collection.new_collection - ; +PatternMatch.implements_collections &:: "emptyMap" <>--> Collection.new_collection - ; +PatternMatch.implements_collections &:: "emptySet" <>--> Collection.new_collection - ; +PatternMatch.implements_collections &:: "singleton" <>--> Collection.singleton_collection - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collection &:: "size" <>$ capt_exp $!--> Collection.size + ; +PatternMatch.Java.implements_collection + &:: "toArray" <>$ capt_exp $+...$--> create_copy_array + ; +PatternMatch.Java.implements_collections &:: "emptyList" <>--> Collection.new_collection + ; +PatternMatch.Java.implements_collections &:: "emptyMap" <>--> Collection.new_collection + ; +PatternMatch.Java.implements_collections &:: "emptySet" <>--> Collection.new_collection + ; +PatternMatch.Java.implements_collections + &:: "singleton" <>--> Collection.singleton_collection + ; +PatternMatch.Java.implements_collections &:: "singletonList" <>--> Collection.singleton_collection - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "singletonList" <>--> Collection.singleton_collection - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "singletonMap" <>--> Collection.singleton_collection - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "singletonMap" <>--> Collection.singleton_collection - ; +PatternMatch.implements_collections &::+ unmodifiable <>$ capt_exp $--> Collection.iterator - ; +PatternMatch.implements_google "common.collect.ImmutableSet" + ; +PatternMatch.Java.implements_collections + &::+ unmodifiable <>$ capt_exp $--> Collection.iterator + ; +PatternMatch.Java.implements_google "common.collect.ImmutableSet" &:: "of" &++> Collection.of_list - ; +PatternMatch.implements_google "common.base.Preconditions" + ; +PatternMatch.Java.implements_google "common.base.Preconditions" &:: "checkArgument" <>$ capt_exp $+...$--> Preconditions.check_argument - ; +PatternMatch.implements_google "common.base.Preconditions" + ; +PatternMatch.Java.implements_google "common.base.Preconditions" &:: "checkNotNull" <>$ capt_exp $+...$--> id - ; +PatternMatch.implements_google "common.base.Preconditions" + ; +PatternMatch.Java.implements_google "common.base.Preconditions" &:: "checkState" <>$ capt_exp $+...$--> Preconditions.check_argument - ; +PatternMatch.implements_infer_annotation "Assertions" + ; +PatternMatch.Java.implements_infer_annotation "Assertions" &:: "assertGet" <>$ capt_exp $+ capt_exp $--> InferAnnotation.assert_get - ; +PatternMatch.implements_infer_annotation "Assertions" + ; +PatternMatch.Java.implements_infer_annotation "Assertions" &:: "assertNotNull" <>$ capt_exp $+...$--> id - ; +PatternMatch.implements_infer_annotation "Assertions" + ; +PatternMatch.Java.implements_infer_annotation "Assertions" &:: "assumeNotNull" <>$ capt_exp $+...$--> id - ; +PatternMatch.implements_infer_annotation "Assertions" + ; +PatternMatch.Java.implements_infer_annotation "Assertions" &:: "nullsafeFIXME" <>$ capt_exp $+...$--> id - ; +PatternMatch.implements_infer_annotation "Assertions" &::.*--> no_model - ; +PatternMatch.implements_io "File" &:: "listFiles" <>$ capt_exp $--> File.list_files - ; +PatternMatch.implements_io "InputStream" + ; +PatternMatch.Java.implements_infer_annotation "Assertions" &::.*--> no_model + ; +PatternMatch.Java.implements_io "File" &:: "listFiles" <>$ capt_exp $--> File.list_files + ; +PatternMatch.Java.implements_io "InputStream" &:: "read" <>$ any_arg $+ any_arg $+ any_arg $+ capt_exp $--> InputStream.read - ; +PatternMatch.implements_iterator &:: "hasNext" <>$ capt_exp $!--> Collection.hasNext - ; +PatternMatch.implements_iterator &:: "next" <>$ capt_exp $!--> Collection.next - ; +PatternMatch.implements_lang "CharSequence" + ; +PatternMatch.Java.implements_iterator &:: "hasNext" <>$ capt_exp $!--> Collection.hasNext + ; +PatternMatch.Java.implements_iterator &:: "next" <>$ capt_exp $!--> Collection.next + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "" <>$ capt_exp $+ capt_exp $--> JavaString.copy_constructor - ; +PatternMatch.implements_lang "CharSequence" + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "" <>$ capt_exp $+ capt_exp_of_prim_typ char_array $--> JavaString.constructor_from_array - ; +PatternMatch.implements_lang "CharSequence" + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "charAt" <>$ capt_exp $+ capt_exp $--> JavaString.charAt - ; +PatternMatch.implements_lang "CharSequence" + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "equals" - $ any_arg_of_typ (+PatternMatch.implements_lang "CharSequence") - $+ any_arg_of_typ (+PatternMatch.implements_lang "CharSequence") + $ any_arg_of_typ (+PatternMatch.Java.implements_lang "CharSequence") + $+ any_arg_of_typ (+PatternMatch.Java.implements_lang "CharSequence") $--> by_value Dom.Val.Itv.unknown_bool - ; +PatternMatch.implements_lang "CharSequence" + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "length" <>$ capt_exp $!--> JavaString.length - ; +PatternMatch.implements_lang "CharSequence" + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "substring" <>$ any_arg $+ capt_exp $+ capt_exp $--> JavaString.substring - ; +PatternMatch.implements_lang "Class" + ; +PatternMatch.Java.implements_lang "Class" &:: "getCanonicalName" &::.*--> JavaString.inferbo_constant_string - ; +PatternMatch.implements_lang "Class" + ; +PatternMatch.Java.implements_lang "Class" &:: "getEnumConstants" <>$ capt_exp $--> JavaClass.get_enum_constants - ; +PatternMatch.implements_lang "Class" &:: "getFields" <>$ capt_exp $--> JavaClass.get_fields - ; +PatternMatch.implements_lang "Enum" &:: "name" &::.*--> JavaString.inferbo_constant_string - ; +PatternMatch.implements_lang "Integer" + ; +PatternMatch.Java.implements_lang "Class" + &:: "getFields" <>$ capt_exp $--> JavaClass.get_fields + ; +PatternMatch.Java.implements_lang "Enum" + &:: "name" &::.*--> JavaString.inferbo_constant_string + ; +PatternMatch.Java.implements_lang "Integer" &:: "intValue" <>$ capt_exp $--> JavaInteger.intValue - ; +PatternMatch.implements_lang "Integer" &:: "valueOf" <>$ capt_exp $--> JavaInteger.valueOf - ; +PatternMatch.implements_lang "Iterable" + ; +PatternMatch.Java.implements_lang "Integer" + &:: "valueOf" <>$ capt_exp $--> JavaInteger.valueOf + ; +PatternMatch.Java.implements_lang "Iterable" &:: "iterator" <>$ capt_exp $!--> Collection.iterator - ; +PatternMatch.implements_lang "Math" + ; +PatternMatch.Java.implements_lang "Math" &:: "max" <>$ capt_exp $+ capt_exp $--> eval_binop ~f:(Itv.max_sem ~use_minmax_bound:true) - ; +PatternMatch.implements_lang "Math" + ; +PatternMatch.Java.implements_lang "Math" &:: "min" <>$ capt_exp $+ capt_exp $--> eval_binop ~f:(Itv.min_sem ~use_minmax_bound:true) - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "" <>$ capt_exp $--> JavaString.empty_constructor - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "concat" <>$ capt_exp $+ capt_exp $+...$--> JavaString.concat - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "indexOf" <>$ capt_exp $+ any_arg $+...$--> JavaString.indexOf - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "lastIndexOf" <>$ capt_exp $+ any_arg $+...$--> JavaString.indexOf - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "replace" <>$ capt_exp $+ any_arg_of_prim_typ int_typ $+ any_arg_of_prim_typ int_typ $--> JavaString.replace - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "split" <>$ any_arg $+ any_arg $+ capt_exp $--> JavaString.split_with_limit - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "split" <>$ capt_exp $+ any_arg $--> JavaString.split - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "startsWith" - $ any_arg_of_typ (+PatternMatch.implements_lang "String") - $+ any_arg_of_typ (+PatternMatch.implements_lang "String") + $ any_arg_of_typ (+PatternMatch.Java.implements_lang "String") + $+ any_arg_of_typ (+PatternMatch.Java.implements_lang "String") $--> by_value Dom.Val.Itv.unknown_bool - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "substring" <>$ capt_exp $+ capt_exp $--> JavaString.substring_no_end - ; +PatternMatch.implements_lang "StringBuilder" + ; +PatternMatch.Java.implements_lang "StringBuilder" &:: "append" <>$ capt_exp $+ capt_exp $+...$--> JavaString.concat - ; +PatternMatch.implements_lang "StringBuilder" &:: "toString" <>$ capt_exp $+...$--> id - ; +PatternMatch.implements_list &:: "listIterator" <>$ capt_exp $+...$--> Collection.iterator - ; +PatternMatch.implements_list &:: "subList" <>$ any_arg $+ capt_exp $+ capt_exp - $--> Collection.subList - ; +PatternMatch.implements_map &:: "entrySet" <>$ capt_exp $!--> Collection.iterator - ; +PatternMatch.implements_map &:: "keySet" <>$ capt_exp $!--> Collection.iterator - ; +PatternMatch.implements_map &:: "put" <>$ capt_var_exn $+ any_arg $+ capt_exp + ; +PatternMatch.Java.implements_lang "StringBuilder" &:: "toString" <>$ capt_exp $+...$--> id + ; +PatternMatch.Java.implements_list + &:: "listIterator" <>$ capt_exp $+...$--> Collection.iterator + ; +PatternMatch.Java.implements_list + &:: "subList" <>$ any_arg $+ capt_exp $+ capt_exp $--> Collection.subList + ; +PatternMatch.Java.implements_map &:: "entrySet" <>$ capt_exp $!--> Collection.iterator + ; +PatternMatch.Java.implements_map &:: "keySet" <>$ capt_exp $!--> Collection.iterator + ; +PatternMatch.Java.implements_map &:: "put" <>$ capt_var_exn $+ any_arg $+ capt_exp $--> Collection.put_with_elem - ; +PatternMatch.implements_map &:: "putAll" <>$ capt_var_exn $+ capt_exp + ; +PatternMatch.Java.implements_map &:: "putAll" <>$ capt_var_exn $+ capt_exp $--> Collection.putAll - ; +PatternMatch.implements_map &:: "size" <>$ capt_exp $!--> Collection.size - ; +PatternMatch.implements_map &:: "values" <>$ capt_exp $!--> Collection.iterator - ; +PatternMatch.implements_nio "ByteBuffer" &:: "get" <>$ capt_exp $--> ByteBuffer.get_int - ; +PatternMatch.implements_nio "ByteBuffer" &:: "getInt" <>$ capt_exp $--> ByteBuffer.get_int - ; +PatternMatch.implements_nio "ByteBuffer" &:: "getLong" <>$ capt_exp $--> ByteBuffer.get_int - ; +PatternMatch.implements_nio "ByteBuffer" + ; +PatternMatch.Java.implements_map &:: "size" <>$ capt_exp $!--> Collection.size + ; +PatternMatch.Java.implements_map &:: "values" <>$ capt_exp $!--> Collection.iterator + ; +PatternMatch.Java.implements_nio "ByteBuffer" + &:: "get" <>$ capt_exp $--> ByteBuffer.get_int + ; +PatternMatch.Java.implements_nio "ByteBuffer" + &:: "getInt" <>$ capt_exp $--> ByteBuffer.get_int + ; +PatternMatch.Java.implements_nio "ByteBuffer" + &:: "getLong" <>$ capt_exp $--> ByteBuffer.get_int + ; +PatternMatch.Java.implements_nio "ByteBuffer" &:: "getShort" <>$ capt_exp $--> ByteBuffer.get_int - ; +PatternMatch.implements_nio "channels.FileChannel" + ; +PatternMatch.Java.implements_nio "channels.FileChannel" &:: "read" <>$ any_arg $+ capt_exp $+ any_arg $--> FileChannel.read - ; +PatternMatch.implements_org_json "JSONArray" + ; +PatternMatch.Java.implements_org_json "JSONArray" &:: "" <>$ capt_var_exn - $+ capt_exp_of_typ (+PatternMatch.implements_collection) + $+ capt_exp_of_typ (+PatternMatch.Java.implements_collection) $--> Collection.init_with_arg - ; +PatternMatch.implements_org_json "JSONArray" + ; +PatternMatch.Java.implements_org_json "JSONArray" &:: "length" <>$ capt_exp $!--> Collection.size - ; +PatternMatch.implements_org_json "JSONArray" + ; +PatternMatch.Java.implements_org_json "JSONArray" &:: "put" <>$ capt_var_exn $+...$--> Collection.put - ; +PatternMatch.implements_pseudo_collection + ; +PatternMatch.Java.implements_pseudo_collection &:: "put" <>$ capt_var_exn $+ any_arg $+ any_arg $--> Collection.put - ; +PatternMatch.implements_pseudo_collection &:: "size" <>$ capt_exp $!--> Collection.size + ; +PatternMatch.Java.implements_pseudo_collection + &:: "size" <>$ capt_exp $!--> Collection.size ; (* Java linked list models *) - +PatternMatch.implements_app_activity &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next - ; +PatternMatch.implements_app_fragment + +PatternMatch.Java.implements_app_activity + &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next + ; +PatternMatch.Java.implements_app_fragment &:: "getParentFragment" <>$ capt_arg $!--> JavaLinkedList.next - ; +PatternMatch.implements_graphql_story + ; +PatternMatch.Java.implements_graphql_story &:: "getAttachedStory" <>$ capt_arg $!--> JavaLinkedList.next - ; +PatternMatch.implements_psi_element &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next - ; +PatternMatch.implements_view_group &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next - ; +PatternMatch.implements_view_parent &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next - ] + ; +PatternMatch.Java.implements_psi_element + &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next + ; +PatternMatch.Java.implements_view_group + &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next + ; +PatternMatch.Java.implements_view_parent + &:: "getParent" <>$ capt_arg $!--> JavaLinkedList.next ] end diff --git a/infer/src/bufferoverrun/bufferOverrunTypModels.ml b/infer/src/bufferoverrun/bufferOverrunTypModels.ml index a960eaecb..8c282429b 100644 --- a/infer/src/bufferoverrun/bufferOverrunTypModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunTypModels.ml @@ -35,7 +35,7 @@ let dispatch : (Tenv.t, typ_model, unit) ProcnameDispatcher.TypName.dispatcher = make_dispatcher [ -"std" &:: "array" < capt_typ &+ capt_int >--> std_array ; -"std" &:: "vector" < any_typ &+ any_typ >--> std_vector - ; +PatternMatch.implements_collection &::.*--> Java.collection - ; +PatternMatch.implements_iterator &::.*--> Java.collection - ; +PatternMatch.implements_lang "Integer" &::.*--> Java.integer - ; +PatternMatch.implements_org_json "JSONArray" &::.*--> Java.collection ] + ; +PatternMatch.Java.implements_collection &::.*--> Java.collection + ; +PatternMatch.Java.implements_iterator &::.*--> Java.collection + ; +PatternMatch.Java.implements_lang "Integer" &::.*--> Java.integer + ; +PatternMatch.Java.implements_org_json "JSONArray" &::.*--> Java.collection ] diff --git a/infer/src/checkers/annotationReachability.ml b/infer/src/checkers/annotationReachability.ml index 76024da75..8d0d299ac 100644 --- a/infer/src/checkers/annotationReachability.ml +++ b/infer/src/checkers/annotationReachability.ml @@ -33,7 +33,7 @@ let is_allocator tenv pname = | Procname.Java pname_java -> let is_throwable () = let class_name = Procname.Java.get_class_type_name pname_java in - PatternMatch.is_throwable tenv class_name + PatternMatch.Java.is_throwable tenv class_name in Procname.is_constructor pname && (not (BuiltinDecl.is_declared pname)) @@ -43,7 +43,7 @@ let is_allocator tenv pname = let check_attributes check tenv pname = - PatternMatch.check_class_attributes check tenv pname + PatternMatch.Java.check_class_attributes check tenv pname || Annotations.pname_has_return_annot pname check diff --git a/infer/src/checkers/inefficientKeysetIterator.ml b/infer/src/checkers/inefficientKeysetIterator.ml index 44fc268bb..ea795d7cd 100644 --- a/infer/src/checkers/inefficientKeysetIterator.ml +++ b/infer/src/checkers/inefficientKeysetIterator.ml @@ -27,7 +27,7 @@ let find_first_arg_id ~fun_name ~class_name_f ~lhs_f = function let implements_map tenv s = - PatternMatch.implements_map tenv s || PatternMatch.implements_androidx_map tenv s + PatternMatch.Java.implements_map tenv s || PatternMatch.Java.implements_androidx_map tenv s (** If given a node that has 4 instructions and calls fun_name, pickup bcvarY, i.e. variable for the @@ -110,11 +110,11 @@ let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log} = (fun loop_head loop_nodes -> if find_first_arg_pvar loop_head ~fun_name:"hasNext" - ~class_name_f:(PatternMatch.implements_iterator tenv) + ~class_name_f:(PatternMatch.Java.implements_iterator tenv) |> Option.is_some then when_dominating_preds_satisfy idom loop_head ~fun_name:"iterator" - ~class_name_f:(PatternMatch.implements_set tenv) ~f:(fun itr_node _ -> + ~class_name_f:(PatternMatch.Java.implements_set tenv) ~f:(fun itr_node _ -> when_dominating_preds_satisfy idom itr_node ~fun_name:"keySet" ~class_name_f:(implements_map tenv) ~f:(fun _keySet_node get_pvar -> report_matching_get proc_desc err_log tenv get_pvar loop_nodes ) ) ) diff --git a/infer/src/checkers/purityModels.ml b/infer/src/checkers/purityModels.ml index 5c88f96f3..354b6da9c 100644 --- a/infer/src/checkers/purityModels.ml +++ b/infer/src/checkers/purityModels.ml @@ -50,105 +50,112 @@ module ProcName = struct ; -"__variable_initialization" <>--> PurityDomain.pure ; +(fun _ name -> BuiltinDecl.is_declared (Procname.from_string_c_fun name)) <>--> PurityDomain.impure_global - ; +PatternMatch.implements_android "text.TextUtils" &:: "isEmpty" <>--> PurityDomain.pure - ; +PatternMatch.implements_android "view.ViewGroup" &:: "getChildAt" <>--> PurityDomain.pure - ; +PatternMatch.implements_android "view.View" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_android "view.View" + ; +PatternMatch.Java.implements_android "text.TextUtils" &:: "isEmpty" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_android "view.ViewGroup" + &:: "getChildAt" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_android "view.View" + &::+ startsWith "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_android "view.View" &::+ startsWith "findViewById" <>--> PurityDomain.pure - ; +PatternMatch.implements_android "view.ViewGroup" + ; +PatternMatch.Java.implements_android "view.ViewGroup" &:: "getChildCount" <>--> PurityDomain.pure - ; +PatternMatch.implements_android "content.Context" + ; +PatternMatch.Java.implements_android "content.Context" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_android "content.res.Resources" + ; +PatternMatch.Java.implements_android "content.res.Resources" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_arrays &:: "asList" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Iterable" &:: "iterator" <>--> PurityDomain.pure - ; +PatternMatch.implements_list &:: "listIterator" <>--> PurityDomain.pure - ; +PatternMatch.implements_collection &:: "iterator" <>--> PurityDomain.pure - ; +PatternMatch.implements_iterator &:: "hasNext" <>--> PurityDomain.pure - ; +PatternMatch.implements_iterator &:: "next" <>--> modifies_first - ; +PatternMatch.implements_iterator &:: "remove" <>--> modifies_first - ; +PatternMatch.implements_collection &:: "size" <>--> PurityDomain.pure - ; +PatternMatch.implements_collection &:: "add" <>--> modifies_first - ; +PatternMatch.implements_collection &:: "addAll" <>--> modifies_first - ; +PatternMatch.implements_collection &:: "remove" <>--> modifies_first - ; +PatternMatch.implements_collection &:: "isEmpty" <>--> PurityDomain.pure - ; +PatternMatch.implements_collection &:: "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_collection &:: "set" <>--> modifies_first - ; +PatternMatch.implements_list &:: "contains" <>--> PurityDomain.pure - ; +PatternMatch.implements_collection &:: "contains" <>--> PurityDomain.pure - ; +PatternMatch.implements_enumeration &:: "hasMoreElements" <>--> PurityDomain.pure - ; +PatternMatch.implements_enumeration &:: "nextElement" <>--> modifies_first - ; +PatternMatch.implements_google "common.base.Preconditions" + ; +PatternMatch.Java.implements_arrays &:: "asList" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Iterable" &:: "iterator" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_list &:: "listIterator" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_collection &:: "iterator" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_iterator &:: "hasNext" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_iterator &:: "next" <>--> modifies_first + ; +PatternMatch.Java.implements_iterator &:: "remove" <>--> modifies_first + ; +PatternMatch.Java.implements_collection &:: "size" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_collection &:: "add" <>--> modifies_first + ; +PatternMatch.Java.implements_collection &:: "addAll" <>--> modifies_first + ; +PatternMatch.Java.implements_collection &:: "remove" <>--> modifies_first + ; +PatternMatch.Java.implements_collection &:: "isEmpty" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_collection &:: "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_collection &:: "set" <>--> modifies_first + ; +PatternMatch.Java.implements_list &:: "contains" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_collection &:: "contains" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_enumeration &:: "hasMoreElements" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_enumeration &:: "nextElement" <>--> modifies_first + ; +PatternMatch.Java.implements_google "common.base.Preconditions" &::+ startsWith "check" <>--> PurityDomain.pure - ; +PatternMatch.implements_inject "Provider" &:: "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_io "File" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_io "OutputStream" &:: "write" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_io "InputStream" &:: "read" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_io "PrintStream" &:: "print" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_io "PrintStream" &:: "println" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_io "Reader" &:: "read" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_io "BufferedReader" &:: "readLine" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_jackson "databind.JsonDeserializer" + ; +PatternMatch.Java.implements_inject "Provider" &:: "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_io "File" &::+ startsWith "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_io "OutputStream" &:: "write" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_io "InputStream" &:: "read" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_io "PrintStream" &:: "print" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_io "PrintStream" + &:: "println" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_io "Reader" &:: "read" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_io "BufferedReader" + &:: "readLine" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_jackson "databind.JsonDeserializer" &:: "deserialize" <>--> PurityDomain.pure - ; +PatternMatch.implements_jackson "core.JsonParser" &:: "nextToken" <>--> modifies_first - ; +PatternMatch.implements_jackson "core.JsonParser" + ; +PatternMatch.Java.implements_jackson "core.JsonParser" &:: "nextToken" <>--> modifies_first + ; +PatternMatch.Java.implements_jackson "core.JsonParser" &:: "getCurrentName" <>--> PurityDomain.pure - ; +PatternMatch.implements_jackson "core.JsonParser" &::+ getStarValue <>--> PurityDomain.pure - ; +PatternMatch.implements_jackson "core.JsonParser" + ; +PatternMatch.Java.implements_jackson "core.JsonParser" + &::+ getStarValue <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_jackson "core.JsonParser" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_pseudo_collection &:: "size" <>--> PurityDomain.pure - ; +PatternMatch.implements_pseudo_collection &:: "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_pseudo_collection &:: "valueAt" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Math" &:: "random" <>--> PurityDomain.impure_global - ; +PatternMatch.implements_lang "Math" &::.*--> PurityDomain.pure + ; +PatternMatch.Java.implements_pseudo_collection &:: "size" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_pseudo_collection &:: "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_pseudo_collection &:: "valueAt" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Math" &:: "random" <>--> PurityDomain.impure_global + ; +PatternMatch.Java.implements_lang "Math" &::.*--> PurityDomain.pure (* for (int|short|byte...)Value*) - ; +PatternMatch.implements_lang "Number" &::+ endsWith "Value" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Boolean" &:: "valueOf" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Boolean" &:: "parseBoolean" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Boolean" &::+ endsWith "Value" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Number" &:: "valueOf" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "length" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "charAt" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "substring" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "CharSequence" &:: "charAt" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "equals" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "startsWith" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "valueOf" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "String" &:: "replace" <>--> modifies_first - ; +PatternMatch.implements_lang "String" &:: "format" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Number" &::+ endsWith "Value" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Boolean" &:: "valueOf" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Boolean" &:: "parseBoolean" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Boolean" &::+ endsWith "Value" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Number" &:: "valueOf" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "length" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "charAt" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "substring" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "CharSequence" &:: "charAt" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "equals" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "startsWith" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "valueOf" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "String" &:: "replace" <>--> modifies_first + ; +PatternMatch.Java.implements_lang "String" &:: "format" <>--> PurityDomain.pure (* String.hashCode is deterministic whereas Object's might not be *) - ; +PatternMatch.implements_lang "String" &:: "hashCode" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "StringBuilder" &:: "" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "StringBuilder" &:: "append" <>--> modifies_first - ; +PatternMatch.implements_lang "StringBuilder" &:: "length" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Object" &:: "clone" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Object" &:: "equals" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Object" &:: "toString" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Object" &:: "getClass" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Class" &:: "getSimpleName" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Class" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "System" &:: "arraycopy" <>--> modifies_third - ; +PatternMatch.implements_lang "Enum" &:: "valueOf" <>--> PurityDomain.pure - ; +PatternMatch.implements_lang "Enum" &:: "ordinal" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "isEmpty" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "put" <>--> modifies_first - ; +PatternMatch.implements_map &:: "putAll" <>--> modifies_first - ; +PatternMatch.implements_map &:: "containsKey" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "keySet" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "values" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "entrySet" <>--> PurityDomain.pure - ; +PatternMatch.implements_map &:: "size" <>--> PurityDomain.pure - ; +PatternMatch.implements_map_entry &:: "getKey" <>--> PurityDomain.pure - ; +PatternMatch.implements_map_entry &:: "getValue" <>--> PurityDomain.pure - ; +PatternMatch.implements_queue &:: "poll" <>--> modifies_first - ; +PatternMatch.implements_queue &:: "add" <>--> modifies_first - ; +PatternMatch.implements_queue &:: "remove" <>--> modifies_first - ; +PatternMatch.implements_queue &:: "peek" <>--> PurityDomain.pure - ; +PatternMatch.implements_list &:: "subList" <>--> PurityDomain.pure - ; +PatternMatch.implements_arrays &:: "binarySearch" <>--> PurityDomain.pure - ; +PatternMatch.implements_org_json "JSONArray" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_org_json "JSONObject" &::+ startsWith "get" <>--> PurityDomain.pure - ; +PatternMatch.implements_org_json "JSONArray" &:: "length" <>--> PurityDomain.pure ] + ; +PatternMatch.Java.implements_lang "String" &:: "hashCode" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "StringBuilder" &:: "" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "StringBuilder" &:: "append" <>--> modifies_first + ; +PatternMatch.Java.implements_lang "StringBuilder" &:: "length" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Object" &:: "clone" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Object" &:: "equals" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Object" &:: "toString" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Object" &:: "getClass" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Class" &:: "getSimpleName" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Class" &::+ startsWith "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "System" &:: "arraycopy" <>--> modifies_third + ; +PatternMatch.Java.implements_lang "Enum" &:: "valueOf" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_lang "Enum" &:: "ordinal" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "isEmpty" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "put" <>--> modifies_first + ; +PatternMatch.Java.implements_map &:: "putAll" <>--> modifies_first + ; +PatternMatch.Java.implements_map &:: "containsKey" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "keySet" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "values" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "entrySet" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map &:: "size" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map_entry &:: "getKey" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_map_entry &:: "getValue" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_queue &:: "poll" <>--> modifies_first + ; +PatternMatch.Java.implements_queue &:: "add" <>--> modifies_first + ; +PatternMatch.Java.implements_queue &:: "remove" <>--> modifies_first + ; +PatternMatch.Java.implements_queue &:: "peek" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_list &:: "subList" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_arrays &:: "binarySearch" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_org_json "JSONArray" + &::+ startsWith "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_org_json "JSONObject" + &::+ startsWith "get" <>--> PurityDomain.pure + ; +PatternMatch.Java.implements_org_json "JSONArray" &:: "length" <>--> PurityDomain.pure ] end diff --git a/infer/src/concurrency/RacerDModels.ml b/infer/src/concurrency/RacerDModels.ml index 3185f554f..2b29b0ce0 100644 --- a/infer/src/concurrency/RacerDModels.ml +++ b/infer/src/concurrency/RacerDModels.ml @@ -364,7 +364,7 @@ let is_thread_safe_method pname tenv = let is_marked_thread_safe pname tenv = ((* current class not marked [@NotThreadSafe] *) not - (PatternMatch.check_current_class_attributes Annotations.ia_is_not_thread_safe tenv pname)) + (PatternMatch.Java.check_current_class_attributes Annotations.ia_is_not_thread_safe tenv pname)) && ConcurrencyModels.find_override_or_superclass_annotated is_thread_safe tenv pname |> Option.is_some diff --git a/infer/src/cost/costModels.ml b/infer/src/cost/costModels.ml index 7ee494022..79197660b 100644 --- a/infer/src/cost/costModels.ml +++ b/infer/src/cost/costModels.ml @@ -192,75 +192,82 @@ module Call = struct ; -"NSString" &:: "componentsSeparatedByString:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.mult ~of_function:"NSString.componentsSeparatedByString:" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "sort" $ capt_exp $+...$--> BoundsOfCollection.n_log_n_length ~of_function:"Collections.sort" - ; +PatternMatch.implements_list &:: "sort" $ capt_exp + ; +PatternMatch.Java.implements_list + &:: "sort" $ capt_exp $+...$--> BoundsOfCollection.n_log_n_length ~of_function:"List.sort" - ; +PatternMatch.implements_arrays &:: "sort" $ capt_exp + ; +PatternMatch.Java.implements_arrays + &:: "sort" $ capt_exp $+...$--> BoundsOfArray.n_log_n_length ~of_function:"Arrays.sort" - ; +PatternMatch.implements_list &:: "contains" <>$ capt_exp + ; +PatternMatch.Java.implements_list + &:: "contains" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"List.contains" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "binarySearch" <>$ capt_exp $+...$--> BoundsOfCollection.logarithmic_length ~of_function:"Collections.binarySearch" - ; +PatternMatch.implements_arrays &:: "binarySearch" <>$ capt_exp + ; +PatternMatch.Java.implements_arrays + &:: "binarySearch" <>$ capt_exp $+...$--> BoundsOfArray.logarithmic_length ~of_function:"Arrays.binarySearch" - ; +PatternMatch.implements_arrays &:: "copyOf" <>$ any_arg $+ capt_exp + ; +PatternMatch.Java.implements_arrays + &:: "copyOf" <>$ any_arg $+ capt_exp $+...$--> linear ~of_function:"Arrays.copyOf" - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "addAll" <>$ any_arg $+ any_arg $+ capt_exp $--> BoundsOfCollection.linear_length ~of_function:"Collection.addAll" - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "addAll" <>$ any_arg $+ capt_exp $--> BoundsOfCollection.linear_length ~of_function:"Collection.addAll" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "copy" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"Collections.copy" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "fill" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"Collections.fill" - ; +PatternMatch.implements_arrays &:: "fill" <>$ capt_exp + ; +PatternMatch.Java.implements_arrays + &:: "fill" <>$ capt_exp $+...$--> BoundsOfArray.linear_length ~of_function:"Arrays.fill" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "reverse" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"Collections.reverse" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "max" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"Collections.max" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "min" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"Collections.min" - ; +PatternMatch.implements_collections + ; +PatternMatch.Java.implements_collections &:: "shuffle" <>$ capt_exp $+...$--> BoundsOfCollection.linear_length ~of_function:"Collections.shuffle" - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "substring" <>$ capt_exp $+ capt_exp $--> JavaString.substring_no_end - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "indexOf" <>$ capt_exp - $+ capt_exp_of_typ (+PatternMatch.implements_lang "String") + $+ capt_exp_of_typ (+PatternMatch.Java.implements_lang "String") $--> JavaString.indexOf_str - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "indexOf" <>$ capt_exp $+ any_arg_of_prim_typ int_typ $+ capt_exp $--> JavaString.indexOf_char_starting_from - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "indexOf" <>$ capt_exp $+ any_arg_of_prim_typ int_typ $--> JavaString.indexOf_char - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &:: "substring" - $ any_arg_of_typ (+PatternMatch.implements_lang "String") + $ any_arg_of_typ (+PatternMatch.Java.implements_lang "String") $+ capt_exp $+ capt_exp $--> JavaString.substring - ; +PatternMatch.implements_inject "Provider" &:: "get" <>--> provider_get - ; +PatternMatch.implements_xmob_utils "IntHashMap" &:: "" <>--> unit_cost_model - ; +PatternMatch.implements_xmob_utils "IntHashMap" &:: "getElement" <>--> unit_cost_model - ; +PatternMatch.implements_xmob_utils "IntHashMap" + ; +PatternMatch.Java.implements_inject "Provider" &:: "get" <>--> provider_get + ; +PatternMatch.Java.implements_xmob_utils "IntHashMap" &:: "" <>--> unit_cost_model + ; +PatternMatch.Java.implements_xmob_utils "IntHashMap" + &:: "getElement" <>--> unit_cost_model + ; +PatternMatch.Java.implements_xmob_utils "IntHashMap" &:: "keys" <>$ capt_arg $--> IntHashMap.keys - ; +PatternMatch.implements_xmob_utils "IntHashMap" &:: "put" <>--> unit_cost_model - ; +PatternMatch.implements_xmob_utils "IntHashMap" &:: "remove" <>--> unit_cost_model - ; +PatternMatch.implements_google "common.collect.ImmutableSet" + ; +PatternMatch.Java.implements_xmob_utils "IntHashMap" &:: "put" <>--> unit_cost_model + ; +PatternMatch.Java.implements_xmob_utils "IntHashMap" &:: "remove" <>--> unit_cost_model + ; +PatternMatch.Java.implements_google "common.collect.ImmutableSet" &:: "chooseTableSize" <>$ capt_exp $+...$--> ImmutableSet.choose_table_size - ; +PatternMatch.implements_google "common.collect.ImmutableSet" + ; +PatternMatch.Java.implements_google "common.collect.ImmutableSet" &:: "construct" <>$ capt_exp_of_prim_typ int_typ $+...$--> ImmutableSet.construct - ; +PatternMatch.implements_google "common.collect.ImmutableSet" + ; +PatternMatch.Java.implements_google "common.collect.ImmutableSet" &:: "construct" <>$ any_arg $+ capt_exp_of_prim_typ int_typ $+...$--> ImmutableSet.construct ] in diff --git a/infer/src/nullsafe/AnnotatedField.ml b/infer/src/nullsafe/AnnotatedField.ml index 78226b7a4..0be191f46 100644 --- a/infer/src/nullsafe/AnnotatedField.ml +++ b/infer/src/nullsafe/AnnotatedField.ml @@ -29,7 +29,7 @@ let is_enum_value tenv ~class_typ (field_info : Struct.field_info) = match (get_type_name class_typ, get_type_name field_info.typ) with (* enums values are fields which type is the same as the type of the enum class *) | Some class_name, Some field_type_name - when Typ.equal_name class_name field_type_name && PatternMatch.is_java_enum tenv class_name -> + when Typ.equal_name class_name field_type_name && PatternMatch.Java.is_enum tenv class_name -> true (* Could not fetch one of the class names, or they are different. Should not happen for enum values. *) | _ -> diff --git a/infer/src/nullsafe/Initializers.ml b/infer/src/nullsafe/Initializers.ml index e98eaf418..caf034b25 100644 --- a/infer/src/nullsafe/Initializers.ml +++ b/infer/src/nullsafe/Initializers.ml @@ -107,7 +107,7 @@ let get_class pn = let final_initializer_typestates_lazy tenv curr_pname curr_pdesc typecheck_proc = lazy (let is_initializer proc_attributes = - PatternMatch.method_is_initializer tenv proc_attributes + PatternMatch.Java.method_is_initializer tenv proc_attributes || let ia = (* TODO(T62825735): support trusted callees for fields *) diff --git a/infer/src/nullsafe/eradicate.ml b/infer/src/nullsafe/eradicate.ml index a4b014008..e9ee6dec9 100644 --- a/infer/src/nullsafe/eradicate.ml +++ b/infer/src/nullsafe/eradicate.ml @@ -25,7 +25,7 @@ let callback1 ({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_da has very special meaning and nullability limitations (it can never be null). *) TypeOrigin.This - else if PatternMatch.is_override_of_java_lang_object_equals curr_pname then + else if PatternMatch.Java.is_override_of_lang_object_equals curr_pname then TypeOrigin.CurrMethodParameter ObjectEqualsOverride else TypeOrigin.CurrMethodParameter (Normal param_signature) in diff --git a/infer/src/nullsafe/models.ml b/infer/src/nullsafe/models.ml index ed34779a9..981e61788 100644 --- a/infer/src/nullsafe/models.ml +++ b/infer/src/nullsafe/models.ml @@ -48,7 +48,7 @@ let to_modelled_nullability ThirdPartyMethod.{ret_nullability; param_nullability let get_special_method_modelled_nullability tenv proc_name = let open IOption.Let_syntax in let* class_name = Procname.get_class_type_name proc_name in - if PatternMatch.is_java_enum tenv class_name then + if PatternMatch.Java.is_enum tenv class_name then match (Procname.get_method proc_name, Procname.get_parameters proc_name) with (* values() is a synthetic enum method that is never null *) | "values", [] -> @@ -138,7 +138,7 @@ let is_true_on_null proc_name = table_has_procedure true_on_null_table proc_name let is_false_on_null proc_name = (* The only usecase for now - consider all overrides of `Object.equals()` correctly implementing the Java specification contract (returning false on null). *) - PatternMatch.is_override_of_java_lang_object_equals proc_name + PatternMatch.Java.is_override_of_lang_object_equals proc_name (** Check if the procedure is Map.containsKey(). *) diff --git a/infer/src/pulse/PulseModels.ml b/infer/src/pulse/PulseModels.ml index b577b92e8..bac802581 100644 --- a/infer/src/pulse/PulseModels.ml +++ b/infer/src/pulse/PulseModels.ml @@ -859,7 +859,7 @@ module ProcNameDispatcher = struct ; +match_builtin BuiltinDecl.exit <>--> Misc.early_exit ; +match_builtin BuiltinDecl.__infer_initializer_list <>$ capt_arg_payload $+...$--> Misc.id_first_arg - ; +PatternMatch.implements_lang "System" &:: "exit" <>--> Misc.early_exit + ; +PatternMatch.Java.implements_lang "System" &:: "exit" <>--> Misc.early_exit ; +match_builtin BuiltinDecl.__get_array_length <>--> Misc.return_unknown_size ; (* consider that all fbstrings are small strings to avoid false positives due to manual ref-counting *) @@ -892,9 +892,9 @@ module ProcNameDispatcher = struct $++$--> StdFunction.operator_call ; -"std" &:: "function" &:: "operator=" $ capt_arg_payload $+ capt_arg_payload $--> StdFunction.operator_equal - ; +PatternMatch.implements_lang "Object" + ; +PatternMatch.Java.implements_lang "Object" &:: "clone" $ capt_arg_payload $--> JavaObject.clone - ; ( +PatternMatch.implements_lang "System" + ; ( +PatternMatch.Java.implements_lang "System" &:: "arraycopy" $ capt_arg_payload $+ any_arg $+ capt_arg_payload $+...$--> fun src dest -> Misc.shallow_copy_model "System.arraycopy" dest src ) ; -"std" &:: "atomic" &:: "atomic" <>$ capt_arg_payload $+ capt_arg_payload @@ -988,54 +988,61 @@ module ProcNameDispatcher = struct ; -"std" &:: "vector" &:: "shrink_to_fit" <>$ capt_arg_payload $--> StdVector.invalidate_references ShrinkToFit ; -"std" &:: "vector" &:: "push_back" <>$ capt_arg_payload $+...$--> StdVector.push_back - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "add" <>$ capt_arg_payload $+ capt_arg_payload $--> JavaCollection.add - ; +PatternMatch.implements_list &:: "add" <>$ capt_arg_payload $+ capt_arg_payload - $+ capt_arg_payload $--> JavaCollection.add_at - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_list + &:: "add" <>$ capt_arg_payload $+ capt_arg_payload $+ capt_arg_payload + $--> JavaCollection.add_at + ; +PatternMatch.Java.implements_collection &:: "remove" <>$ capt_arg_payload $+ any_arg $--> JavaCollection.remove - ; +PatternMatch.implements_list &:: "remove" <>$ capt_arg_payload $+ capt_arg_payload - $+ any_arg $--> JavaCollection.remove_at - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_list + &:: "remove" <>$ capt_arg_payload $+ capt_arg_payload $+ any_arg + $--> JavaCollection.remove_at + ; +PatternMatch.Java.implements_collection &::+ (fun _ str -> StringSet.mem str pushback_modeled) <>$ capt_arg_payload $+...$--> StdVector.push_back - ; +PatternMatch.implements_queue + ; +PatternMatch.Java.implements_queue &::+ (fun _ str -> StringSet.mem str pushback_modeled) <>$ capt_arg_payload $+...$--> StdVector.push_back - ; +PatternMatch.implements_lang "StringBuilder" + ; +PatternMatch.Java.implements_lang "StringBuilder" &::+ (fun _ str -> StringSet.mem str pushback_modeled) <>$ capt_arg_payload $+...$--> StdVector.push_back - ; +PatternMatch.implements_lang "StringBuilder" + ; +PatternMatch.Java.implements_lang "StringBuilder" &:: "setLength" <>$ capt_arg_payload $+...$--> StdVector.invalidate_references ShrinkToFit - ; +PatternMatch.implements_lang "String" + ; +PatternMatch.Java.implements_lang "String" &::+ (fun _ str -> StringSet.mem str pushback_modeled) <>$ capt_arg_payload $+...$--> StdVector.push_back - ; +PatternMatch.implements_iterator &:: "remove" <>$ capt_arg_payload + ; +PatternMatch.Java.implements_iterator + &:: "remove" <>$ capt_arg_payload $+...$--> JavaIterator.remove ~desc:"remove" - ; +PatternMatch.implements_map &:: "put" <>$ capt_arg_payload $+...$--> StdVector.push_back - ; +PatternMatch.implements_map &:: "putAll" <>$ capt_arg_payload + ; +PatternMatch.Java.implements_map &:: "put" <>$ capt_arg_payload + $+...$--> StdVector.push_back + ; +PatternMatch.Java.implements_map &:: "putAll" <>$ capt_arg_payload $+...$--> StdVector.push_back ; -"std" &:: "vector" &:: "reserve" <>$ capt_arg_payload $+...$--> StdVector.reserve - ; +PatternMatch.implements_collection + ; +PatternMatch.Java.implements_collection &:: "get" <>$ capt_arg_payload $+ capt_arg_payload $--> StdVector.at ~desc:"Collection.get()" - ; +PatternMatch.implements_list &:: "set" <>$ capt_arg_payload $+ capt_arg_payload - $+ capt_arg_payload $--> JavaCollection.set - ; +PatternMatch.implements_iterator &:: "hasNext" + ; +PatternMatch.Java.implements_list + &:: "set" <>$ capt_arg_payload $+ capt_arg_payload $+ capt_arg_payload + $--> JavaCollection.set + ; +PatternMatch.Java.implements_iterator + &:: "hasNext" &--> Misc.nondet ~fn_name:"Iterator.hasNext()" - ; +PatternMatch.implements_enumeration + ; +PatternMatch.Java.implements_enumeration &:: "hasMoreElements" &--> Misc.nondet ~fn_name:"Enumeration.hasMoreElements()" - ; +PatternMatch.implements_lang "Object" + ; +PatternMatch.Java.implements_lang "Object" &:: "equals" &--> Misc.nondet ~fn_name:"Object.equals" - ; +PatternMatch.implements_lang "Iterable" + ; +PatternMatch.Java.implements_lang "Iterable" &:: "iterator" <>$ capt_arg_payload $+...$--> JavaIterator.constructor ~desc:"Iterable.iterator" - ; +PatternMatch.implements_iterator &:: "next" <>$ capt_arg_payload + ; +PatternMatch.Java.implements_iterator + &:: "next" <>$ capt_arg_payload $!--> JavaIterator.next ~desc:"Iterator.next()" - ; ( +PatternMatch.implements_enumeration + ; ( +PatternMatch.Java.implements_enumeration &:: "nextElement" <>$ capt_arg_payload $!--> fun x -> StdVector.at ~desc:"Enumeration.nextElement" x (AbstractValue.mk_fresh (), []) )