[typ] extract Procname from Typ

Summary: No reason for this to be in Typ

Reviewed By: skcho

Differential Revision: D19162727

fbshipit-source-id: d6940637a
master
Nikos Gorogiannis 5 years ago committed by Facebook Github Bot
parent 33352623a5
commit 91fa6a5404

@ -33,10 +33,10 @@ let proc_kind_of_attr (proc_attributes : ProcAttributes.t) =
let replace pname pname_blob akind source_file attributes proc_desc callees =
let pname_str = Typ.Procname.to_string pname in
let pname_str = Procname.to_string pname in
let akind_int64 = int64_of_attributes_kind akind in
let proc_desc_blob = Procdesc.SQLite.serialize proc_desc in
let callees_blob = Typ.Procname.SQLiteList.serialize callees in
let callees_blob = Procname.SQLiteList.serialize callees in
DBWriter.replace_attributes ~pname_str ~pname:pname_blob ~akind:akind_int64 ~source_file
~attributes ~proc_desc:proc_desc_blob ~callees:callees_blob
@ -82,11 +82,11 @@ let find ~defined pname_blob =
|> Option.map ~f:ProcAttributes.SQLite.deserialize )
let load pname = Typ.Procname.SQLite.serialize pname |> find ~defined:false
let load pname = Procname.SQLite.serialize pname |> find ~defined:false
let store ~proc_desc (attr : ProcAttributes.t) =
let pkind = proc_kind_of_attr attr in
let key = Typ.Procname.SQLite.serialize attr.proc_name in
let key = Procname.SQLite.serialize attr.proc_name in
if should_try_to_update key pkind then
replace attr.proc_name key pkind
(SourceFile.SQLite.serialize attr.loc.Location.file)
@ -95,7 +95,7 @@ let store ~proc_desc (attr : ProcAttributes.t) =
(Option.map proc_desc ~f:Procdesc.get_static_callees |> Option.value ~default:[])
let load_defined pname = Typ.Procname.SQLite.serialize pname |> find ~defined:true
let load_defined pname = Procname.SQLite.serialize pname |> find ~defined:true
let find_file_capturing_procedure pname =
Option.map (load pname) ~f:(fun proc_attributes ->

@ -16,13 +16,13 @@ val deserialize_attributes_kind : Sqlite3.Data.t -> attributes_kind
val store : proc_desc:Procdesc.t option -> ProcAttributes.t -> unit
(** Save .attr file for the procedure into the attributes database. *)
val load : Typ.Procname.t -> ProcAttributes.t option
val load : Procname.t -> ProcAttributes.t option
(** Load the attributes for the procedure from the attributes database. *)
val load_defined : Typ.Procname.t -> ProcAttributes.t option
val load_defined : Procname.t -> ProcAttributes.t option
(** Load attributes for the procedure but only if is_defined is true *)
val find_file_capturing_procedure : Typ.Procname.t -> (SourceFile.t * [`Include | `Source]) option
val find_file_capturing_procedure : Procname.t -> (SourceFile.t * [`Include | `Source]) option
(** Find the file where the procedure was captured, if a cfg for that file exists. Return also a
boolean indicating whether the procedure is defined in an include file. *)

@ -7,28 +7,28 @@
open! IStd
type t = Typ.Procname.t
type t = Procname.t
let builtin_decls = ref Typ.Procname.Set.empty
let builtin_decls = ref Procname.Set.empty
let register pname = builtin_decls := Typ.Procname.Set.add pname !builtin_decls
let register pname = builtin_decls := Procname.Set.add pname !builtin_decls
let create_procname name =
let pname = Typ.Procname.from_string_c_fun name in
let pname = Procname.from_string_c_fun name in
register pname ; pname
let create_objc_class_method class_name method_name parameters =
let method_kind = Typ.Procname.ObjC_Cpp.ObjCClassMethod in
let method_kind = Procname.ObjC_Cpp.ObjCClassMethod in
let tname = Typ.Name.Objc.from_string class_name in
let pname =
Typ.Procname.ObjC_Cpp
(Typ.Procname.ObjC_Cpp.make tname method_name method_kind Typ.NoTemplate parameters)
Procname.ObjC_Cpp
(Procname.ObjC_Cpp.make tname method_name method_kind Typ.NoTemplate parameters)
in
register pname ; pname
let is_declared pname = Typ.Procname.Set.mem pname !builtin_decls
let is_declared pname = Procname.Set.mem pname !builtin_decls
let __array_access = create_procname "__array_access"

@ -9,6 +9,6 @@ open! IStd
(** Procnames for the builtin functions supported *)
include BUILTINS.S with type t = Typ.Procname.t
include BUILTINS.S with type t = Procname.t
val is_declared : Typ.Procname.t -> bool
val is_declared : Procname.t -> bool

@ -8,7 +8,7 @@
open! IStd
module F = Format
type t = {pname: Typ.Procname.t; loc: Location.t} [@@deriving compare]
type t = {pname: Procname.t; loc: Location.t} [@@deriving compare]
let equal = [%compare.equal: t]
@ -18,9 +18,9 @@ let loc t = t.loc
let make pname loc = {pname; loc}
let dummy = make Typ.Procname.empty_block Location.dummy
let dummy = make Procname.empty_block Location.dummy
let pp fmt t = F.fprintf fmt "%a at %a" Typ.Procname.pp t.pname Location.pp t.loc
let pp fmt t = F.fprintf fmt "%a at %a" Procname.pp t.pname Location.pp t.loc
module Set = PrettyPrintable.MakePPSet (struct
type nonrec t = t

@ -12,11 +12,11 @@ type t [@@deriving compare]
val equal : t -> t -> bool
val pname : t -> Typ.Procname.t
val pname : t -> Procname.t
val loc : t -> Location.t
val make : Typ.Procname.t -> Location.t -> t
val make : Procname.t -> Location.t -> t
val dummy : t

@ -11,15 +11,15 @@ module L = Logging
module F = Format
(** data type for the control flow graph *)
type t = Procdesc.t Typ.Procname.Hash.t
type t = Procdesc.t Procname.Hash.t
let create () = Typ.Procname.Hash.create 16
let create () = Procname.Hash.create 16
let iter_over_sorted_procs cfg ~f =
let compare_proc_desc_by_proc_name pdesc1 pdesc2 =
Typ.Procname.compare (Procdesc.get_proc_name pdesc1) (Procdesc.get_proc_name pdesc2)
Procname.compare (Procdesc.get_proc_name pdesc1) (Procdesc.get_proc_name pdesc2)
in
Typ.Procname.Hash.fold (fun _ pdesc acc -> pdesc :: acc) cfg []
Procname.Hash.fold (fun _ pdesc acc -> pdesc :: acc) cfg []
|> List.sort ~compare:compare_proc_desc_by_proc_name
|> List.iter ~f
@ -27,16 +27,16 @@ let iter_over_sorted_procs cfg ~f =
let get_all_defined_proc_names cfg =
let procs = ref [] in
let f pname pdesc = if Procdesc.is_defined pdesc then procs := pname :: !procs in
Typ.Procname.Hash.iter f cfg ; !procs
Procname.Hash.iter f cfg ; !procs
(** Create a new procdesc *)
let create_proc_desc cfg (proc_attributes : ProcAttributes.t) =
let pdesc = Procdesc.from_proc_attributes proc_attributes in
let pname = proc_attributes.proc_name in
if Typ.Procname.Hash.mem cfg pname then
if Procname.Hash.mem cfg pname then
L.die InternalError "Creating two procdescs for the same procname." ;
Typ.Procname.Hash.add cfg pname pdesc ;
Procname.Hash.add cfg pname pdesc ;
pdesc
@ -53,7 +53,7 @@ let store source_file cfg =
Procdesc.set_attributes proc_desc attributes' ;
Attributes.store ~proc_desc:(Some proc_desc) attributes'
in
Typ.Procname.Hash.iter save_proc cfg
Procname.Hash.iter save_proc cfg
(** Inline a synthetic (access or bridge) method. *)
@ -121,11 +121,10 @@ let inline_synthetic_method ((ret_id, _) as ret) etl pdesc loc_call : Sil.instr
let proc_inline_synthetic_methods cfg pdesc : unit =
let instr_inline_synthetic_method _node instr =
match instr with
| Sil.Call (ret_id_typ, Exp.Const (Const.Cfun (Typ.Procname.Java java_pn as pn)), etl, loc, _)
-> (
match Typ.Procname.Hash.find cfg pn with
| Sil.Call (ret_id_typ, Exp.Const (Const.Cfun (Procname.Java java_pn as pn)), etl, loc, _) -> (
match Procname.Hash.find cfg pn with
| pd ->
let is_access = Typ.Procname.Java.is_access_method java_pn in
let is_access = Procname.Java.is_access_method java_pn in
let attributes = Procdesc.get_attributes pd in
let is_synthetic = attributes.is_synthetic_method in
let is_bridge = attributes.is_bridge_method in
@ -142,8 +141,8 @@ let proc_inline_synthetic_methods cfg pdesc : unit =
let inline_java_synthetic_methods cfg =
let f pname pdesc = if Typ.Procname.is_java pname then proc_inline_synthetic_methods cfg pdesc in
Typ.Procname.Hash.iter f cfg
let f pname pdesc = if Procname.is_java pname then proc_inline_synthetic_methods cfg pdesc in
Procname.Hash.iter f cfg
let pp_proc_signatures fmt cfg =

@ -11,9 +11,9 @@ open! IStd
(** Control Flow Graph for Interprocedural Analysis *)
(** A control-flow graph is a collection of all the CFGs for the procedure names in a file *)
type t = Procdesc.t Typ.Procname.Hash.t
type t = Procdesc.t Procname.Hash.t
val get_all_defined_proc_names : t -> Typ.Procname.t list
val get_all_defined_proc_names : t -> Procname.t list
(** get all the procedure names that are defined in the current file *)
val store : SourceFile.t -> t -> unit

@ -13,7 +13,7 @@ module F = Format
type t =
| Cint of IntLit.t (** integer constants *)
| Cfun of Typ.Procname.t (** function names *)
| Cfun of Procname.t (** function names *)
| Cstr of string (** string constants *)
| Cfloat of float (** float constants *)
| Cclass of Ident.name (** class constant *)
@ -43,9 +43,9 @@ let pp pe f = function
| Cfun fn -> (
match pe.Pp.kind with
| HTML ->
F.fprintf f "_fun_%s" (Escape.escape_xml (F.asprintf "%a" Typ.Procname.pp fn))
F.fprintf f "_fun_%s" (Escape.escape_xml (F.asprintf "%a" Procname.pp fn))
| _ ->
F.fprintf f "_fun_%a" Typ.Procname.pp fn )
F.fprintf f "_fun_%a" Procname.pp fn )
| Cstr s ->
F.fprintf f "\"%s\"" (String.escaped s)
| Cfloat v ->

@ -14,7 +14,7 @@ module F = Format
(** Constants *)
type t =
| Cint of IntLit.t (** integer constants *)
| Cfun of Typ.Procname.t (** function names *)
| Cfun of Procname.t (** function names *)
| Cstr of string (** string constants *)
| Cfloat of float (** float constants *)
| Cclass of Ident.name (** class constant *)

@ -38,7 +38,7 @@ let split_var_clang var_name =
let builtin_functions_to_string pn =
if Typ.Procname.equal pn BuiltinDecl.__objc_alloc_no_fail then Some "alloc" else None
if Procname.equal pn BuiltinDecl.__objc_alloc_no_fail then Some "alloc" else None
let rec pp fmt = function
@ -51,10 +51,10 @@ let rec pp fmt = function
| Some str ->
F.pp_print_string fmt str
| None -> (
let procname_str = Typ.Procname.to_simplified_string pn in
let procname_str = Procname.to_simplified_string pn in
match pn with
| Typ.Procname.ObjC_Cpp {kind= ObjCInstanceMethod}
| Typ.Procname.ObjC_Cpp {kind= ObjCClassMethod} -> (
| Procname.ObjC_Cpp {kind= ObjCInstanceMethod} | Procname.ObjC_Cpp {kind= ObjCClassMethod}
-> (
match String.lsplit2 ~on:':' procname_str with
| Some (base_name, _) ->
F.pp_print_string fmt base_name
@ -75,10 +75,10 @@ let rec pp fmt = function
| Dconst (Cfun pname) ->
let s =
match pname with
| Typ.Procname.Java pname_java ->
Typ.Procname.Java.get_method pname_java
| Procname.Java pname_java ->
Procname.Java.get_method pname_java
| _ ->
Typ.Procname.to_string pname
Procname.to_string pname
in
F.pp_print_string fmt s
| de ->

@ -11,7 +11,7 @@ module F = Format
let pp_cfgnodename pname fmt (n : Procdesc.Node.t) =
F.fprintf fmt "\"%s_%d\""
(Escape.escape_dotty (Typ.Procname.to_filename pname))
(Escape.escape_dotty (Procname.to_filename pname))
(Procdesc.Node.get_id n :> int)
@ -32,7 +32,7 @@ let pp_cfgnodelabel pdesc fmt (n : Procdesc.Node.t) =
match Procdesc.Node.get_kind n with
| Start_node ->
let pname = Procdesc.Node.get_proc_name n in
let pname_string = Escape.escape_dotty (Typ.Procname.to_string pname) in
let pname_string = Escape.escape_dotty (Procname.to_string pname) in
let attributes = Procdesc.get_attributes pdesc in
Format.fprintf fmt "Start %s\\nFormals: %a\\nLocals: %a" pname_string pp_etlist
(Procdesc.get_formals pdesc) pp_local_list (Procdesc.get_locals pdesc) ;
@ -43,7 +43,7 @@ let pp_cfgnodelabel pdesc fmt (n : Procdesc.Node.t) =
Format.fprintf fmt "\\nAnnotation: %a" (Annot.Method.pp pname_string) method_annotation
| Exit_node ->
let pname = Procdesc.Node.get_proc_name n in
Format.fprintf fmt "Exit %s" (Escape.escape_dotty (Typ.Procname.to_string pname))
Format.fprintf fmt "Exit %s" (Escape.escape_dotty (Procname.to_string pname))
| Join_node ->
Format.pp_print_char fmt '+'
| Prune_node (is_true_branch, if_kind, _) ->
@ -135,7 +135,7 @@ let emit_proc_desc source proc_desc =
let filename =
let db_name =
DB.Results_dir.path_to_filename (DB.Results_dir.Abs_source_dir source)
[Typ.Procname.to_filename (Procdesc.get_proc_name proc_desc)]
[Procname.to_filename (Procdesc.get_proc_name proc_desc)]
in
DB.filename_to_string db_name ^ ".dot"
in

@ -13,8 +13,8 @@ module F = Format
type node_tag =
| Condition of bool
| Exception of Typ.name
| Procedure_start of Typ.Procname.t
| Procedure_end of Typ.Procname.t
| Procedure_start of Procname.t
| Procedure_end of Procname.t
(** Element of a loc trace *)
type loc_trace_elem =
@ -261,7 +261,7 @@ let log_issue procname ~clang_method_kind severity err_log ~loc ~node ~session ~
in
( if exn_developer then
let issue =
let lang = Typ.Procname.get_language procname in
let lang = Procname.get_language procname in
let clang_method_kind =
match lang with
| Language.Clang ->
@ -275,7 +275,7 @@ let log_issue procname ~clang_method_kind severity err_log ~loc ~node ~session ~
; clang_method_kind
; exception_triggered_location= error.ocaml_pos
; lang= Language.to_explicit_string lang
; procedure_name= Typ.Procname.to_string procname
; procedure_name= Procname.to_string procname
; source_location= loc }
in
EventLogger.log issue ) ;

@ -12,8 +12,8 @@ open! IStd
type node_tag =
| Condition of bool
| Exception of Typ.name
| Procedure_start of Typ.Procname.t
| Procedure_end of Typ.Procname.t
| Procedure_start of Procname.t
| Procedure_end of Procname.t
(** Element of a loc trace *)
type loc_trace_elem = private
@ -109,7 +109,7 @@ val update : t -> t -> unit
(** Update an old error log with a new one *)
val log_issue :
Typ.Procname.t
Procname.t
-> clang_method_kind:ClangMethodKind.t option
-> Exceptions.severity
-> t

@ -18,7 +18,7 @@ type ident_ = Ident.t
let compare_ident_ x y = Ident.compare y x
type closure = {name: Typ.Procname.t; captured_vars: (t * Pvar.t * Typ.t) list}
type closure = {name: Procname.t; captured_vars: (t * Pvar.t * Typ.t) list}
(** This records information about a [sizeof(typ)] expression.
@ -319,12 +319,7 @@ let pp_texp_full pe f = function
(** Dump a type expression with all the details. *)
let d_texp_full (te : t) = L.d_pp_with_pe pp_texp_full te
let is_objc_block_closure = function
| Closure {name} ->
Typ.Procname.is_objc_block name
| _ ->
false
let is_objc_block_closure = function Closure {name} -> Procname.is_objc_block name | _ -> false
let rec gen_free_vars =
let open Sequence.Generator in
@ -416,11 +411,7 @@ let rec get_java_class_initializer tenv = function
match Struct.get_field_type_and_annotation ~lookup:(Tenv.lookup tenv) fn typ with
| Some (field_typ, annot) when Annot.Item.is_final annot ->
let java_class = Typ.JavaClass (Pvar.get_name pvar) in
Some
( Typ.Procname.Java (Typ.Procname.Java.get_class_initializer java_class)
, pvar
, fn
, field_typ )
Some (Procname.Java (Procname.Java.get_class_initializer java_class), pvar, fn, field_typ)
| _ ->
None )
| Cast (_, e) | Lfield (e, _, _) ->

@ -13,7 +13,7 @@
open! IStd
module F = Format
type closure = {name: Typ.Procname.t; captured_vars: (t * Pvar.t * Typ.t) list}
type closure = {name: Procname.t; captured_vars: (t * Pvar.t * Typ.t) list}
(** This records information about a [sizeof(typ)] expression.
@ -170,6 +170,5 @@ val ignore_cast : t -> t
val ignore_integer_cast : t -> t
val get_java_class_initializer :
Tenv.t -> t -> (Typ.Procname.t * Pvar.t * Fieldname.t * Typ.t) option
val get_java_class_initializer : Tenv.t -> t -> (Procname.t * Pvar.t * Fieldname.t * Typ.t) option
(** Returns the class initializer of the given expression in Java *)

@ -8,7 +8,7 @@ open! IStd
type source_files_filter = SourceFile.t -> bool
type procedures_filter = SourceFile.t -> Typ.Procname.t -> bool
type procedures_filter = SourceFile.t -> Procname.t -> bool
let filter_of_regexp_opt ~to_string r =
match r with
@ -44,7 +44,7 @@ let mk_procedure_name_filter ~filter =
let source_file_filter =
filter_of_regexp_opt ~to_string:SourceFile.to_string source_file_regexp
in
let proc_name_filter = filter_of_regexp_opt ~to_string:Typ.Procname.to_string proc_name_regexp in
let proc_name_filter = filter_of_regexp_opt ~to_string:Procname.to_string proc_name_regexp in
source_file_filter &&& proc_name_filter

@ -9,7 +9,7 @@ open! IStd
type source_files_filter = SourceFile.t -> bool
type procedures_filter = SourceFile.t -> Typ.Procname.t -> bool
type procedures_filter = SourceFile.t -> Procname.t -> bool
val source_files_filter : source_files_filter Lazy.t
(** filter corresponding to `--source-files-filter` *)

@ -48,7 +48,7 @@ module T : sig
| UnaryOperator of Unop.t * t * Typ.t option
| BinaryOperator of Binop.t * t * t
| Exception of t
| Closure of Typ.Procname.t * (AccessPath.base * t) list
| Closure of Procname.t * (AccessPath.base * t) list
| Constant of Const.t
| Cast of Typ.t * t
| Sizeof of Typ.t * t option
@ -83,7 +83,7 @@ end = struct
| UnaryOperator of Unop.t * t * Typ.t option
| BinaryOperator of Binop.t * t * t
| Exception of t
| Closure of Typ.Procname.t * (AccessPath.base * t) list
| Closure of Procname.t * (AccessPath.base * t) list
| Constant of Const.t
| Cast of Typ.t * t
| Sizeof of Typ.t * t option
@ -181,7 +181,7 @@ and pp fmt = function
| _ ->
F.fprintf fmt "%a captured as %a" AccessPath.pp_base base pp exp
in
F.fprintf fmt "closure(%a, %a)" Typ.Procname.pp pname
F.fprintf fmt "closure(%a, %a)" Procname.pp pname
(PrettyPrintable.pp_collection ~pp_item)
captured
| Constant c ->

@ -27,7 +27,7 @@ type t =
(** Unary operator with type of the result if known *)
| BinaryOperator of Binop.t * t * t (** Binary operator *)
| Exception of t (** Exception *)
| Closure of Typ.Procname.t * (AccessPath.base * t) list (** Name of function + environment *)
| Closure of Procname.t * (AccessPath.base * t) list (** Name of function + environment *)
| Constant of Const.t (** Constants *)
| Cast of Typ.t * t (** Type cast *)
| Sizeof of Typ.t * t option

@ -9,11 +9,11 @@ open! IStd
module F = Format
module L = Logging
type call = Direct of Typ.Procname.t | Indirect of HilExp.AccessExpression.t [@@deriving compare]
type call = Direct of Procname.t | Indirect of HilExp.AccessExpression.t [@@deriving compare]
let pp_call fmt = function
| Direct pname ->
Typ.Procname.pp fmt pname
Procname.pp fmt pname
| Indirect access_expr ->
F.fprintf fmt "*%a" HilExp.AccessExpression.pp access_expr
@ -70,7 +70,7 @@ let of_sil ~include_array_indexes ~f_resolve_id (instr : Sil.instr) =
, (target_exp, _) :: (Sizeof {typ= cast_typ}, _) :: _
, loc
, _ )
when Typ.Procname.equal callee_pname BuiltinDecl.__cast ->
when Procname.equal callee_pname BuiltinDecl.__cast ->
analyze_id_assignment (Var.of_id ret_id) target_exp cast_typ loc
| Store {e1= lhs_exp; typ; e2= rhs_exp; loc} ->
let lhs_access_expr =

@ -9,7 +9,7 @@ open! IStd
module F = Format
(** type of a procedure call; either direct or via function pointer *)
type call = Direct of Typ.Procname.t | Indirect of HilExp.AccessExpression.t [@@deriving compare]
type call = Direct of Procname.t | Indirect of HilExp.AccessExpression.t [@@deriving compare]
val pp_call : F.formatter -> call -> unit [@@warning "-32"]

@ -109,7 +109,7 @@ h1 { font-size:14pt }
(** File name for the node, given the procedure name and node id *)
let node_filename pname id = F.sprintf "%s_node%d" (Typ.Procname.to_filename pname) id
let node_filename pname id = F.sprintf "%s_node%d" (Procname.to_filename pname) id
(** Print an html link to the given node. *)
let pp_node_link path_to_root pname ~description ~preds ~succs ~exn ~isvisited fmt id =
@ -129,7 +129,7 @@ h1 { font-size:14pt }
(** Print an html link to the given proc *)
let pp_proc_link path_to_root proc_name fmt text =
pp_link ~path:(path_to_root @ [Typ.Procname.to_filename proc_name]) fmt text
pp_link ~path:(path_to_root @ [Procname.to_filename proc_name]) fmt text
(** Print an html link to the given line number of the current source file *)

@ -20,7 +20,7 @@ module Html : sig
val modified_during_analysis : SourceFile.t -> DB.Results_dir.path -> bool
(** Return true if the html file was modified since the beginning of the analysis *)
val node_filename : Typ.Procname.t -> int -> string
val node_filename : Procname.t -> int -> string
(** File name for the node, given the procedure name and node id *)
val open_out : SourceFile.t -> DB.Results_dir.path -> Unix.File_descr.t * Format.formatter
@ -41,7 +41,7 @@ module Html : sig
val pp_node_link :
DB.Results_dir.path
-> Typ.Procname.t
-> Procname.t
-> description:string
-> preds:int list
-> succs:int list
@ -54,12 +54,12 @@ module Html : sig
[path_to_root] is the path to the dir for the procedure in the spec db. [id] is the node
identifier. *)
val pp_proc_link : DB.Results_dir.path -> Typ.Procname.t -> Format.formatter -> string -> unit
val pp_proc_link : DB.Results_dir.path -> Procname.t -> Format.formatter -> string -> unit
(** Print an html link to the given proc *)
val pp_session_link :
?with_name:bool
-> ?proc_name:Typ.Procname.t
-> ?proc_name:Procname.t
-> SourceFile.t
-> string list
-> Format.formatter

@ -9,28 +9,28 @@
open! IStd
type t = Errlog.t Typ.Procname.Map.t
type t = Errlog.t Procname.Map.t
let empty = Typ.Procname.Map.empty
let empty = Procname.Map.empty
let get_or_add ~proc m =
match Typ.Procname.Map.find_opt proc m with
match Procname.Map.find_opt proc m with
| Some errlog ->
(m, errlog)
| None ->
let errlog = Errlog.empty () in
let m = Typ.Procname.Map.add proc errlog m in
let m = Procname.Map.add proc errlog m in
(m, errlog)
let issues_serializer : Errlog.t Typ.Procname.Map.t Serialization.serializer =
let issues_serializer : Errlog.t Procname.Map.t Serialization.serializer =
Serialization.create_serializer Serialization.Key.issues
let iter ~f m = Typ.Procname.Map.iter f m
let iter ~f m = Procname.Map.iter f m
let store ~dir ~file m =
if not (Typ.Procname.Map.is_empty m) then (
if not (Procname.Map.is_empty m) then (
let abbrev_source_file = DB.source_file_encoding file in
let issues_dir = Config.results_dir ^/ dir in
Utils.create_dir issues_dir ;
@ -51,7 +51,7 @@ let load dir =
let file = DB.filename_from_string (Filename.concat issues_dir issues_file) in
load_issues file
|> Option.fold ~init ~f:(fun acc map ->
Typ.Procname.Map.merge
Procname.Map.merge
(fun _ issues1 issues2 ->
match (issues1, issues2) with
| Some issues1, Some issues2 ->

@ -12,10 +12,10 @@ type t
val empty : t
val iter : f:(Typ.Procname.t -> Errlog.t -> unit) -> t -> unit
val iter : f:(Procname.t -> Errlog.t -> unit) -> t -> unit
(** iterate a function on map contents *)
val get_or_add : proc:Typ.Procname.t -> t -> t * Errlog.t
val get_or_add : proc:Procname.t -> t -> t * Errlog.t
(** Get the error log for a given procname. If there is none, add an empty one to the map. Return
the resulting map together with the errlog. *)

@ -138,7 +138,7 @@ let line_ tags loc = line_tag_ tags Tags.line loc
let at_line tags loc = at_line_tag tags Tags.line loc
let call_to proc_name =
let proc_name_str = Typ.Procname.to_simplified_string proc_name in
let proc_name_str = Procname.to_simplified_string proc_name in
"call to " ^ MF.monospaced_to_string proc_name_str
@ -203,14 +203,14 @@ let deref_str_nullable proc_name_opt nullable_obj_str =
(** dereference strings for nonterminal nil arguments in c/objc variadic methods *)
let deref_str_nil_argument_in_variadic_method pn total_args arg_number =
let function_method, nil_null =
if Typ.Procname.is_c_method pn then ("method", "nil") else ("function", "null")
if Procname.is_c_method pn then ("method", "nil") else ("function", "null")
in
let problem_str =
Printf.sprintf
"could be %s which results in a call to %s with %d arguments instead of %d (%s indicates \
that the last argument of this variadic %s has been reached)"
nil_null
(Typ.Procname.to_simplified_string pn)
(Procname.to_simplified_string pn)
arg_number (total_args - 1) nil_null function_method
in
deref_str_null_ None problem_str
@ -219,7 +219,7 @@ let deref_str_nil_argument_in_variadic_method pn total_args arg_number =
(** dereference strings for an undefined value coming from the given procedure *)
let deref_str_undef (proc_name, loc) =
let tags = Tags.create () in
let proc_name_str = Typ.Procname.to_simplified_string proc_name in
let proc_name_str = Procname.to_simplified_string proc_name in
{ tags
; value_pre= Some (pointer_or_object ())
; value_post= None
@ -345,7 +345,7 @@ let nullable_annotation_name proc_name =
match Config.nullable_annotation with
| Some name ->
name
| None when Typ.Procname.is_java proc_name ->
| None when Procname.is_java proc_name ->
"@Nullable"
| None (* default Clang annotation name *) ->
"_Nullable"
@ -460,11 +460,11 @@ let desc_allocation_mismatch alloc dealloc =
let tags = Tags.create () in
let using (primitive_pname, called_pname, loc) =
let by_call =
if Typ.Procname.equal primitive_pname called_pname then ""
else " by call to " ^ MF.monospaced_to_string (Typ.Procname.to_simplified_string called_pname)
if Procname.equal primitive_pname called_pname then ""
else " by call to " ^ MF.monospaced_to_string (Procname.to_simplified_string called_pname)
in
"using "
^ MF.monospaced_to_string (Typ.Procname.to_simplified_string primitive_pname)
^ MF.monospaced_to_string (Procname.to_simplified_string primitive_pname)
^ by_call ^ " "
^ at_line (Tags.create ()) (* ignore the tag *) loc
in
@ -688,13 +688,13 @@ let desc_unary_minus_applied_to_unsigned_expression expr_str_opt typ_str loc =
let desc_skip_function proc_name =
let tags = Tags.create () in
let proc_name_str = Typ.Procname.to_string proc_name in
let proc_name_str = Procname.to_string proc_name in
Tags.update tags Tags.value proc_name_str ;
{no_desc with descriptions= [proc_name_str]; tags= !tags}
let desc_inherently_dangerous_function proc_name =
let proc_name_str = Typ.Procname.to_string proc_name in
let proc_name_str = Procname.to_string proc_name in
let tags = Tags.create () in
Tags.update tags Tags.value proc_name_str ;
{no_desc with descriptions= [MF.monospaced_to_string proc_name_str]; tags= !tags}

@ -63,13 +63,13 @@ val error_desc_get_dotty : error_desc -> string option
(** dereference strings used to explain a dereference action in an error message *)
type deref_str
val deref_str_null : Typ.Procname.t option -> deref_str
val deref_str_null : Procname.t option -> deref_str
(** dereference strings for null dereference *)
val deref_str_nullable : Typ.Procname.t option -> string -> deref_str
val deref_str_nullable : Procname.t option -> string -> deref_str
(** dereference strings for null dereference due to Nullable annotation *)
val deref_str_undef : Typ.Procname.t * Location.t -> deref_str
val deref_str_undef : Procname.t * Location.t -> deref_str
(** dereference strings for an undefined value coming from the given procedure *)
val deref_str_freed : PredSymb.res_action -> deref_str
@ -81,7 +81,7 @@ val deref_str_dangling : PredSymb.dangling_kind option -> deref_str
val deref_str_array_bound : IntLit.t option -> IntLit.t option -> deref_str
(** dereference strings for an array out of bound access *)
val deref_str_nil_argument_in_variadic_method : Typ.Procname.t -> int -> int -> deref_str
val deref_str_nil_argument_in_variadic_method : Procname.t -> int -> int -> deref_str
(** dereference strings for nonterminal nil arguments in c/objc variadic methods *)
val deref_str_pointer_size_mismatch : Typ.t -> Typ.t -> deref_str
@ -94,11 +94,11 @@ type access =
| Initialized_automatically
| Returned_from_call of int
val nullable_annotation_name : Typ.Procname.t -> string
val nullable_annotation_name : Procname.t -> string
(** Name of the nullable annotation *)
val dereference_string :
Typ.Procname.t -> deref_str -> string -> access option -> Location.t -> error_desc
Procname.t -> deref_str -> string -> access option -> Location.t -> error_desc
val parameter_field_not_null_checked_desc : error_desc -> Exp.t -> error_desc
@ -107,22 +107,20 @@ val is_parameter_not_null_checked_desc : error_desc -> bool
val is_field_not_null_checked_desc : error_desc -> bool
val desc_allocation_mismatch :
Typ.Procname.t * Typ.Procname.t * Location.t
-> Typ.Procname.t * Typ.Procname.t * Location.t
-> error_desc
Procname.t * Procname.t * Location.t -> Procname.t * Procname.t * Location.t -> error_desc
val desc_class_cast_exception :
Typ.Procname.t option -> string -> string -> string option -> Location.t -> error_desc
Procname.t option -> string -> string -> string option -> Location.t -> error_desc
val desc_condition_always_true_false : IntLit.t -> string option -> Location.t -> error_desc
val desc_deallocate_stack_variable : string -> Typ.Procname.t -> Location.t -> error_desc
val desc_deallocate_stack_variable : string -> Procname.t -> Location.t -> error_desc
val desc_deallocate_static_memory : string -> Typ.Procname.t -> Location.t -> error_desc
val desc_deallocate_static_memory : string -> Procname.t -> Location.t -> error_desc
val desc_divide_by_zero : string -> Location.t -> error_desc
val desc_empty_vector_access : Typ.Procname.t option -> string -> Location.t -> error_desc
val desc_empty_vector_access : Procname.t option -> string -> Location.t -> error_desc
val is_empty_vector_access_desc : error_desc -> bool
@ -145,7 +143,7 @@ val desc_custom_error : Location.t -> error_desc
(** kind of precondition not met *)
type pnm_kind = Pnm_bounds | Pnm_dangling
val desc_precondition_not_met : pnm_kind option -> Typ.Procname.t -> Location.t -> error_desc
val desc_precondition_not_met : pnm_kind option -> Procname.t -> Location.t -> error_desc
val desc_retain_cycle : string -> Location.t -> string option -> error_desc
@ -153,9 +151,9 @@ val desc_registered_observer_being_deallocated : Pvar.t -> Location.t -> error_d
val desc_stack_variable_address_escape : Pvar.t -> string option -> Location.t -> error_desc
val desc_skip_function : Typ.Procname.t -> error_desc
val desc_skip_function : Procname.t -> error_desc
val desc_inherently_dangerous_function : Typ.Procname.t -> error_desc
val desc_inherently_dangerous_function : Procname.t -> error_desc
val desc_unary_minus_applied_to_unsigned_expression :
string option -> string -> Location.t -> error_desc

@ -196,4 +196,4 @@ end
let is_core_lib_type typ = Core_foundation_model.is_core_lib_type typ
let is_malloc_model return_type pname =
Core_foundation_model.is_core_lib_create return_type (Typ.Procname.to_string pname)
Core_foundation_model.is_core_lib_create return_type (Procname.to_string pname)

@ -12,4 +12,4 @@ open! IStd
val is_core_lib_type : Typ.t -> bool
val is_malloc_model : Typ.t -> Typ.Procname.t -> bool
val is_malloc_model : Typ.t -> Procname.t -> bool

@ -52,7 +52,7 @@ type dangling_kind =
[@@deriving compare]
(** position in a path: proc name, node id *)
type path_pos = Typ.Procname.t * int [@@deriving compare]
type path_pos = Procname.t * int [@@deriving compare]
let equal_path_pos = [%compare.equal: path_pos]
@ -60,7 +60,7 @@ let equal_path_pos = [%compare.equal: path_pos]
type res_action =
{ ra_kind: res_act_kind (** kind of action *)
; ra_res: resource (** kind of resource *)
; ra_pname: Typ.Procname.t (** name of the procedure used to acquire/release the resource *)
; ra_pname: Procname.t (** name of the procedure used to acquire/release the resource *)
; ra_loc: Location.t (** location of the acquire/release *)
; ra_vpath: DecompiledExp.vpath (** vpath of the resource value *) }
@ -94,13 +94,13 @@ type t =
| Aresource of res_action (** resource acquire/release *)
| Aautorelease
| Adangling of dangling_kind (** dangling pointer *)
| Aundef of Typ.Procname.t * annot_item_ * location_ * path_pos_
| Aundef of Procname.t * annot_item_ * location_ * path_pos_
| Alocked
| Aunlocked
| Adiv0 of path_pos (** value appeared in second argument of division at given path position *)
| Aobjc_null
(** attributed exp is null due to a call to a method with given path as null receiver *)
| Aretval of Typ.Procname.t * Annot.Item.t
| Aretval of Procname.t * Annot.Item.t
(** value was returned from a call to the given procedure, plus the annots of the return value *)
| Aobserver (** denotes an object registered as an observers to a notification center *)
| Aunsubscribed_observer
@ -113,25 +113,25 @@ let equal = [%compare.equal: t]
(** name of the allocation function for the given memory kind *)
let mem_alloc_pname = function
| Mmalloc ->
Typ.Procname.from_string_c_fun "malloc"
Procname.from_string_c_fun "malloc"
| Mnew ->
Typ.Procname.from_string_c_fun "new"
Procname.from_string_c_fun "new"
| Mnew_array ->
Typ.Procname.from_string_c_fun "new[]"
Procname.from_string_c_fun "new[]"
| Mobjc ->
Typ.Procname.from_string_c_fun "alloc"
Procname.from_string_c_fun "alloc"
(** name of the deallocation function for the given memory kind *)
let mem_dealloc_pname = function
| Mmalloc ->
Typ.Procname.from_string_c_fun "free"
Procname.from_string_c_fun "free"
| Mnew ->
Typ.Procname.from_string_c_fun "delete"
Procname.from_string_c_fun "delete"
| Mnew_array ->
Typ.Procname.from_string_c_fun "delete[]"
Procname.from_string_c_fun "delete[]"
| Mobjc ->
Typ.Procname.from_string_c_fun "dealloc"
Procname.from_string_c_fun "dealloc"
(** Categories of attributes *)
@ -206,9 +206,7 @@ let to_string pe = function
let str_vpath =
if Config.trace_error then F.asprintf "%a" (DecompiledExp.pp_vpath pe) ra.ra_vpath else ""
in
name ^ Binop.str pe Lt
^ Typ.Procname.to_string ra.ra_pname
^ ":"
name ^ Binop.str pe Lt ^ Procname.to_string ra.ra_pname ^ ":"
^ string_of_int ra.ra_loc.Location.line
^ Binop.str pe Gt ^ str_vpath
| Aautorelease ->
@ -225,7 +223,7 @@ let to_string pe = function
in
"DANGL" ^ Binop.str pe Lt ^ dks ^ Binop.str pe Gt
| Aundef (pn, _, loc, _) ->
"UND" ^ Binop.str pe Lt ^ Typ.Procname.to_string pn ^ Binop.str pe Gt ^ ":"
"UND" ^ Binop.str pe Lt ^ Procname.to_string pn ^ Binop.str pe Gt ^ ":"
^ string_of_int loc.Location.line
| Alocked ->
"LOCKED"
@ -236,7 +234,7 @@ let to_string pe = function
| Aobjc_null ->
"OBJC_NULL"
| Aretval (pn, _) ->
"RET" ^ Binop.str pe Lt ^ Typ.Procname.to_string pn ^ Binop.str pe Gt
"RET" ^ Binop.str pe Lt ^ Procname.to_string pn ^ Binop.str pe Gt
| Aobserver ->
"OBSERVER"
| Aunsubscribed_observer ->

@ -42,7 +42,7 @@ type dangling_kind =
| DAminusone (** pointer is -1 *)
(** position in a path: proc name, node id *)
type path_pos = Typ.Procname.t * int [@@deriving compare]
type path_pos = Procname.t * int [@@deriving compare]
val equal_path_pos : path_pos -> path_pos -> bool
@ -50,7 +50,7 @@ val equal_path_pos : path_pos -> path_pos -> bool
type res_action =
{ ra_kind: res_act_kind (** kind of action *)
; ra_res: resource (** kind of resource *)
; ra_pname: Typ.Procname.t (** name of the procedure used to acquire/release the resource *)
; ra_pname: Procname.t (** name of the procedure used to acquire/release the resource *)
; ra_loc: Location.t (** location of the acquire/release *)
; ra_vpath: DecompiledExp.vpath (** vpath of the resource value *) }
@ -66,13 +66,13 @@ type t =
| Aresource of res_action (** resource acquire/release *)
| Aautorelease
| Adangling of dangling_kind (** dangling pointer *)
| Aundef of Typ.Procname.t * Annot.Item.t * Location.t * path_pos
| Aundef of Procname.t * Annot.Item.t * Location.t * path_pos
| Alocked
| Aunlocked
| Adiv0 of path_pos (** value appeared in second argument of division at given path position *)
| Aobjc_null
(** attributed exp is null due to a call to a method with given path as null receiver *)
| Aretval of Typ.Procname.t * Annot.Item.t
| Aretval of Procname.t * Annot.Item.t
(** value was returned from a call to the given procedure, plus the annots of the return value *)
| Aobserver (** denotes an object registered as an observers to a notification center *)
| Aunsubscribed_observer
@ -82,10 +82,10 @@ type t =
val equal : t -> t -> bool
val mem_alloc_pname : mem_kind -> Typ.Procname.t
val mem_alloc_pname : mem_kind -> Procname.t
(** name of the allocation function for the given memory kind *)
val mem_dealloc_pname : mem_kind -> Typ.Procname.t
val mem_dealloc_pname : mem_kind -> Procname.t
(** name of the deallocation function for the given memory kind *)
(** Categories of attributes *)

@ -60,7 +60,7 @@ type t =
; mutable locals: var_data list (** name, type and attributes of local variables *)
; method_annotation: Annot.Method.t (** annotations for all methods *)
; objc_accessor: objc_accessor_type option (** type of ObjC accessor, if any *)
; proc_name: Typ.Procname.t (** name of the procedure *)
; proc_name: Procname.t (** name of the procedure *)
; ret_type: Typ.t (** return type *)
; has_added_return_param: bool (** whether or not a return param was added *) }
@ -126,8 +126,8 @@ let pp f
let pp_bool_default ~default title b f () =
if not (Bool.equal default b) then F.fprintf f "; %s= %b@," title b
in
F.fprintf f "@[<v>{ proc_name= %a@,; translation_unit= %a@," Typ.Procname.pp proc_name
SourceFile.pp translation_unit ;
F.fprintf f "@[<v>{ proc_name= %a@,; translation_unit= %a@," Procname.pp proc_name SourceFile.pp
translation_unit ;
if not (PredSymb.equal_access default.access access) then
F.fprintf f "; access= %a@," (Pp.of_string ~f:PredSymb.string_of_access) access ;
if not ([%compare.equal: (Mangled.t * Typ.t) list] default.captured captured) then
@ -173,7 +173,7 @@ let pp f
F.fprintf f "; objc_accessor= %a@," (Pp.option pp_objc_accessor_type) objc_accessor ;
(* always print ret type *)
F.fprintf f "; ret_type= %a @," (Typ.pp_full Pp.text) ret_type ;
F.fprintf f "; proc_id= %a }@]" Typ.Procname.pp_unique_id proc_name
F.fprintf f "; proc_id= %a }@]" Procname.pp_unique_id proc_name
module SQLite = SqliteUtils.MarshalledDataNOTForComparison (struct

@ -44,11 +44,11 @@ type t =
; mutable locals: var_data list (** name, type and attributes of local variables *)
; method_annotation: Annot.Method.t (** annotations for all methods *)
; objc_accessor: objc_accessor_type option (** type of ObjC accessor, if any *)
; proc_name: Typ.Procname.t (** name of the procedure *)
; proc_name: Procname.t (** name of the procedure *)
; ret_type: Typ.t (** return type *)
; has_added_return_param: bool (** whether or not a return param was added *) }
val default : SourceFile.t -> Typ.Procname.t -> t
val default : SourceFile.t -> Procname.t -> t
(** Create a proc_attributes with default values. *)
val pp : Format.formatter -> t -> unit

@ -132,7 +132,7 @@ module Node = struct
; kind: nodekind (** kind of node *)
; loc: Location.t (** location in the source code *)
; mutable preds: t list (** predecessor nodes in the cfg *)
; pname: Typ.Procname.t (** name of the procedure the node belongs to *)
; pname: Procname.t (** name of the procedure the node belongs to *)
; mutable succs: t list (** successor nodes in the cfg *) }
let exn_handler_kind = Stmt_node ExceptionHandler
@ -534,14 +534,14 @@ let fold_instrs pdesc ~init ~f =
let get_static_callees pdesc =
let callees =
fold_instrs pdesc ~init:Typ.Procname.Set.empty ~f:(fun acc _node instr ->
fold_instrs pdesc ~init:Procname.Set.empty ~f:(fun acc _node instr ->
match instr with
| Sil.Call (_, Exp.Const (Const.Cfun callee_pn), _, _, _) ->
Typ.Procname.Set.add callee_pn acc
Procname.Set.add callee_pn acc
| _ ->
acc )
in
Typ.Procname.Set.remove (get_proc_name pdesc) callees |> Typ.Procname.Set.elements
Procname.Set.remove (get_proc_name pdesc) callees |> Procname.Set.elements
let find_map_nodes pdesc ~f = List.find_map ~f (get_nodes pdesc)
@ -741,7 +741,7 @@ let pp_signature fmt pdesc =
let attributes = get_attributes pdesc in
let pname = get_proc_name pdesc in
let defined_string = match is_defined pdesc with true -> "defined" | false -> "undefined" in
Format.fprintf fmt "@[%a [%s, Return type: %a, %aFormals: %a, Locals: %a" Typ.Procname.pp pname
Format.fprintf fmt "@[%a [%s, Return type: %a, %aFormals: %a, Locals: %a" Procname.pp pname
defined_string (Typ.pp_full Pp.text) (get_ret_type pdesc) pp_objc_accessor
attributes.ProcAttributes.objc_accessor pp_variable_list (get_formals pdesc) pp_locals_list
(get_locals pdesc) ;
@ -749,7 +749,7 @@ let pp_signature fmt pdesc =
Format.fprintf fmt ", Captured: %a" pp_variable_list (get_captured pdesc) ;
let method_annotation = attributes.ProcAttributes.method_annotation in
( if not (Annot.Method.is_empty method_annotation) then
let pname_string = Typ.Procname.to_string pname in
let pname_string = Procname.to_string pname in
Format.fprintf fmt ", Annotation: %a" (Annot.Method.pp pname_string) method_annotation ) ;
Format.fprintf fmt "]@]@;"
@ -769,9 +769,9 @@ let is_captured_pvar procdesc pvar =
let pvar_matches (name, _) = Mangled.equal name pvar_name in
let is_captured_var_cpp_lambda =
match procname with
| Typ.Procname.ObjC_Cpp cpp_pname ->
| Procname.ObjC_Cpp cpp_pname ->
(* var is captured if the procedure is a lambda and the var is not in the locals or formals *)
Typ.Procname.ObjC_Cpp.is_cpp_lambda cpp_pname
Procname.ObjC_Cpp.is_cpp_lambda cpp_pname
&& not
( List.exists ~f:pvar_local_matches (get_locals procdesc)
|| List.exists ~f:pvar_matches (get_formals procdesc) )
@ -780,7 +780,7 @@ let is_captured_pvar procdesc pvar =
in
let is_captured_var_objc_block =
(* var is captured if the procedure is a objc block and the var is in the captured *)
Typ.Procname.is_objc_block procname && List.exists ~f:pvar_matches (get_captured procdesc)
Procname.is_objc_block procname && List.exists ~f:pvar_matches (get_captured procdesc)
in
is_captured_var_cpp_lambda || is_captured_var_objc_block
@ -871,8 +871,7 @@ let load_statement =
let load pname =
ResultsDatabase.with_registered_statement load_statement ~f:(fun db stmt ->
Typ.Procname.SQLite.serialize pname
|> Sqlite3.bind stmt 1
Procname.SQLite.serialize pname |> Sqlite3.bind stmt 1
|> SqliteUtils.check_result_code db ~log:"load bind proc name" ;
SqliteUtils.result_single_column_option ~finalize:false ~log:"Procdesc.load" db stmt
|> Option.bind ~f:SQLite.deserialize )

@ -117,7 +117,7 @@ module Node : sig
val d_instrs : highlight:Sil.instr option -> t -> unit
(** Dump instructions for the node, highlighting the given subinstruction if present *)
val dummy : Typ.Procname.t -> t
val dummy : Procname.t -> t
(** Create a dummy node *)
val equal : t -> t -> bool
@ -156,7 +156,7 @@ module Node : sig
val get_siblings : t -> t Sequence.t
(** Get siblings of the current node *)
val get_proc_name : t -> Typ.Procname.t
val get_proc_name : t -> Procname.t
(** Get the name of the procedure the node belongs to *)
val get_succs : t -> t list
@ -245,7 +245,7 @@ val get_nodes : t -> Node.t list
val get_nodes_num : t -> int
val get_proc_name : t -> Typ.Procname.t
val get_proc_name : t -> Procname.t
val get_ret_type : t -> Typ.t
(** Return the return type of the procedure and type string *)
@ -256,7 +256,7 @@ val get_ret_var : t -> Pvar.t
val get_start_node : t -> Node.t
val get_static_callees : t -> Typ.Procname.t list
val get_static_callees : t -> Procname.t list
(** get a list of unique static callees excluding self *)
val is_defined : t -> bool
@ -321,4 +321,4 @@ module SQLite : SqliteUtils.Data with type t = t option
(** per-procedure CFGs are stored in the SQLite "procedures" table as NULL if the procedure has no
CFG *)
val load : Typ.Procname.t -> t option
val load : Procname.t -> t option

@ -0,0 +1,810 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module Hashtbl = Caml.Hashtbl
module F = Format
(** Level of verbosity of some to_string functions. *)
type detail_level = Verbose | Non_verbose | Simple [@@deriving compare, equal]
let is_verbose v = match v with Verbose -> true | _ -> false
module Java = struct
type kind =
| Non_Static
(** in Java, procedures called with invokevirtual, invokespecial, and invokeinterface *)
| Static (** in Java, procedures called with invokestatic *)
[@@deriving compare]
(* TODO: use Mangled.t here *)
type java_type = Typ.Name.Java.Split.t [@@deriving compare]
let java_void = Typ.Name.Java.Split.make "void"
(** Type of java procedure names. *)
type t =
{ method_name: string
; parameters: java_type list
; class_name: Typ.Name.t
; return_type: java_type option (* option because constructors have no return type *)
; kind: kind }
[@@deriving compare]
let make class_name return_type method_name parameters kind =
{class_name; return_type; method_name; parameters; kind}
let pp_type_verbosity verbosity fmt java_type =
Typ.Name.Java.Split.pp_type_verbosity ~verbose:(is_verbose verbosity) fmt java_type
(** Given a list of types, it creates a unique string of types separated by commas *)
let rec pp_param_list verbosity fmt inputList =
match inputList with
| [] ->
()
| [head] ->
pp_type_verbosity verbosity fmt head
| head :: rest ->
pp_type_verbosity verbosity fmt head ;
F.pp_print_string fmt "," ;
pp_param_list verbosity fmt rest
let java_type_of_name class_name = Typ.Name.Java.Split.of_string (Typ.Name.name class_name)
(** It is the same as java_type_to_string_verbosity, but Java return types are optional because of
constructors without type *)
let pp_return_type verbosity fmt j =
match j.return_type with None -> () | Some typ -> pp_type_verbosity verbosity fmt typ
let get_class_name j = Typ.Name.name j.class_name
let get_class_type_name j = j.class_name
let get_simple_class_name j = Typ.Name.Java.Split.(j |> get_class_name |> of_string |> type_name)
let get_package j = Typ.Name.Java.Split.(j |> get_class_name |> of_string |> package)
let get_method j = j.method_name
let replace_method_name method_name j = {j with method_name}
let replace_parameters parameters j = {j with parameters}
let replace_return_type ret_type j = {j with return_type= Some ret_type}
let get_parameters j = j.parameters
(** Prints a string of a java procname with the given level of verbosity *)
let pp ?(withclass = false) verbosity fmt j =
match verbosity with
| Verbose | Non_verbose ->
(* if verbose, then package.class.method(params): rtype,
else rtype package.class.method(params)
verbose is used for example to create unique filenames, non_verbose to create reports *)
let pp_class_name verbosity fmt j =
pp_type_verbosity verbosity fmt (Typ.Name.Java.split_typename j.class_name)
in
let separator =
match (j.return_type, verbosity) with None, _ -> "" | Some _, Verbose -> ":" | _ -> " "
in
if not (equal_detail_level verbosity Verbose) then
F.fprintf fmt "%a%s" (pp_return_type verbosity) j separator ;
F.fprintf fmt "%a.%s(%a)" (pp_class_name verbosity) j j.method_name
(pp_param_list verbosity) j.parameters ;
if equal_detail_level verbosity Verbose then
F.fprintf fmt "%s%a" separator (pp_return_type verbosity) j
| Simple ->
(* methodname(...) or without ... if there are no parameters *)
let pp_class_prefix ~withclass verbosity fmt j =
if withclass then
F.fprintf fmt "%a." (pp_type_verbosity verbosity)
(Typ.Name.Java.split_typename j.class_name)
in
let params = match j.parameters with [] -> "" | _ -> "..." in
let pp_method_name ~withclass verbosity fmt j =
if String.equal j.method_name "<init>" then
F.pp_print_string fmt (get_simple_class_name j)
else F.fprintf fmt "%a%s" (pp_class_prefix ~withclass verbosity) j j.method_name
in
F.fprintf fmt "%a(%s)" (pp_method_name ~withclass verbosity) j params
let get_return_typ pname_java =
let rec java_from_string = function
| "" | "void" ->
Typ.void
| "int" ->
Typ.int
| "byte" ->
Typ.java_byte
| "short" ->
Typ.java_short
| "boolean" ->
Typ.boolean
| "char" ->
Typ.char
| "long" ->
Typ.long
| "float" ->
Typ.float
| "double" ->
Typ.double
| typ_str when String.contains typ_str '[' ->
let stripped_typ = String.sub typ_str ~pos:0 ~len:(String.length typ_str - 2) in
Typ.mk (Tptr (Typ.mk_array (java_from_string stripped_typ), Pk_pointer))
| typ_str ->
Typ.mk (Tstruct (Typ.Name.Java.from_string typ_str))
in
let typ = java_from_string (F.asprintf "%a" (pp_return_type Verbose) pname_java) in
match typ.desc with Tstruct _ -> Typ.mk (Tptr (typ, Pk_pointer)) | _ -> typ
let is_close {method_name} = String.equal method_name "close"
let constructor_method_name = "<init>"
let class_initializer_method_name = "<clinit>"
let is_class_initializer {method_name} = String.equal method_name class_initializer_method_name
let get_class_initializer class_name =
{ method_name= class_initializer_method_name
; parameters= []
; class_name
; return_type= Some java_void
; kind= Static }
let is_constructor {method_name} = String.equal method_name constructor_method_name
let is_anonymous_inner_class_constructor {class_name} =
Typ.Name.Java.is_anonymous_inner_class_name class_name
let is_static {kind} = match kind with Static -> true | _ -> false
let is_lambda {method_name} = String.is_prefix ~prefix:"lambda$" method_name
let is_generated {method_name} = String.is_prefix ~prefix:"$" method_name
let is_access_method {method_name} =
match String.rsplit2 method_name ~on:'$' with
| Some ("access", s) ->
let is_int =
try
ignore (int_of_string s) ;
true
with Failure _ -> false
in
is_int
| _ ->
false
let is_autogen_method {method_name} = String.contains method_name '$'
(** Check if the proc name has the type of a java vararg. Note: currently only checks that the
last argument has type Object[]. *)
let is_vararg {parameters} =
(* FIXME this looks wrong due to the dot in the type name *)
List.last parameters
|> Option.exists ~f:(fun java_type ->
String.equal "java.lang.Object[]" (Typ.Name.Java.Split.type_name java_type) )
let is_external java_pname =
let package = get_package java_pname in
Option.exists ~f:Config.java_package_is_external package
end
module Parameter = struct
(** Type for parameters in clang procnames, [Some name] means the parameter is of type pointer to
struct, with [name] being the name of the struct, [None] means the parameter is of some other
type. *)
type clang_parameter = Typ.Name.t option [@@deriving compare]
(** Type for parameters in procnames, for java and clang. *)
type t = JavaParameter of Java.java_type | ClangParameter of clang_parameter
[@@deriving compare]
let of_typ typ =
match typ.Typ.desc with Typ.Tptr ({desc= Tstruct name}, Pk_pointer) -> Some name | _ -> None
let pp_parameters fmt parameters =
if List.exists ~f:Option.is_some parameters then
(* the tests rely on the fact that we discard non-pointer-to-struct types for some reason,
hence the slight re-implementation of [Pp.seq] to avoid building the list of [Some] items
explicitly *)
let rec pp_parameters_aux fmt = function
| [] ->
()
| [Some param] ->
F.pp_print_string fmt (Typ.Name.to_string param)
| None :: parameters ->
pp_parameters_aux fmt parameters
| (Some _ as param_some) :: None :: parameters ->
pp_parameters_aux fmt (param_some :: parameters)
| Some param :: (Some _ :: _ as parameters) ->
F.fprintf fmt "%s," (Typ.Name.to_string param) ;
pp_parameters_aux fmt parameters
in
F.fprintf fmt "(%a)" pp_parameters_aux parameters
let clang_param_of_name class_name : clang_parameter = Some class_name
end
module ObjC_Cpp = struct
type kind =
| CPPMethod of {mangled: string option}
| CPPConstructor of {mangled: string option; is_constexpr: bool}
| CPPDestructor of {mangled: string option}
| ObjCClassMethod
| ObjCInstanceMethod
| ObjCInternalMethod
[@@deriving compare]
type t =
{ class_name: Typ.Name.t
; kind: kind
; method_name: string
; parameters: Parameter.clang_parameter list
; template_args: Typ.template_spec_info }
[@@deriving compare]
let make class_name method_name kind template_args parameters =
{class_name; method_name; kind; template_args; parameters}
let get_class_name objc_cpp = Typ.Name.name objc_cpp.class_name
let get_class_type_name objc_cpp = objc_cpp.class_name
let get_class_qualifiers objc_cpp = Typ.Name.qual_name objc_cpp.class_name
let objc_method_kind_of_bool is_instance =
if is_instance then ObjCInstanceMethod else ObjCClassMethod
let is_objc_constructor method_name =
String.equal method_name "new" || String.is_prefix ~prefix:"init" method_name
let is_objc_kind = function
| ObjCClassMethod | ObjCInstanceMethod | ObjCInternalMethod ->
true
| _ ->
false
let is_objc_method {kind} = is_objc_kind kind
let is_objc_dealloc method_name = String.equal method_name "dealloc"
let is_destructor = function
| {kind= CPPDestructor _} ->
true
| name ->
is_objc_dealloc name.method_name
let is_inner_destructor ({method_name} as pname) =
is_destructor pname && String.is_prefix ~prefix:Config.clang_inner_destructor_prefix method_name
let is_constexpr = function {kind= CPPConstructor {is_constexpr= true}} -> true | _ -> false
let is_cpp_lambda {method_name} = String.is_substring ~substring:"operator()" method_name
let pp_verbose_kind fmt = function
| CPPMethod {mangled} | CPPDestructor {mangled} ->
F.fprintf fmt "(%s)" (Option.value ~default:"" mangled)
| CPPConstructor {mangled; is_constexpr} ->
F.fprintf fmt "{%s%s}"
(Option.value ~default:"" mangled)
(if is_constexpr then "|constexpr" else "")
| ObjCClassMethod ->
F.pp_print_string fmt "class"
| ObjCInstanceMethod ->
F.pp_print_string fmt "instance"
| ObjCInternalMethod ->
F.pp_print_string fmt "internal"
let pp verbosity fmt osig =
match verbosity with
| Simple ->
F.pp_print_string fmt osig.method_name
| Non_verbose ->
F.fprintf fmt "%s::%s" (Typ.Name.name osig.class_name) osig.method_name
| Verbose ->
F.fprintf fmt "%s::%s%a%a" (Typ.Name.name osig.class_name) osig.method_name
Parameter.pp_parameters osig.parameters pp_verbose_kind osig.kind
let get_parameters osig = osig.parameters
let replace_parameters new_parameters osig = {osig with parameters= new_parameters}
end
module C = struct
(** Type of c procedure names. *)
type t =
{ name: QualifiedCppName.t
; mangled: string option
; parameters: Parameter.clang_parameter list
; template_args: Typ.template_spec_info }
[@@deriving compare]
let c name mangled parameters template_args =
{name; mangled= Some mangled; parameters; template_args}
let from_string name =
{ name= QualifiedCppName.of_qual_string name
; mangled= None
; parameters= []
; template_args= NoTemplate }
let pp verbosity fmt {name; mangled; parameters} =
let plain = QualifiedCppName.to_qual_string name in
match verbosity with
| Simple ->
F.fprintf fmt "%s()" plain
| Non_verbose ->
F.pp_print_string fmt plain
| Verbose ->
let pp_mangled fmt = function None -> () | Some s -> F.fprintf fmt "{%s}" s in
F.fprintf fmt "%s%a%a" plain Parameter.pp_parameters parameters pp_mangled mangled
let get_parameters c = c.parameters
let replace_parameters new_parameters c = {c with parameters= new_parameters}
end
module Block = struct
(** Type of Objective C block names. *)
type block_name = string [@@deriving compare]
type t = {name: block_name; parameters: Parameter.clang_parameter list} [@@deriving compare]
let make name parameters = {name; parameters}
let pp verbosity fmt bsig =
match verbosity with
| Simple ->
F.pp_print_string fmt "block"
| Non_verbose ->
F.pp_print_string fmt bsig.name
| Verbose ->
F.fprintf fmt "%s%a" bsig.name Parameter.pp_parameters bsig.parameters
let get_parameters block = block.parameters
let replace_parameters new_parameters block = {block with parameters= new_parameters}
end
(** Type of procedure names. *)
type t =
| Java of Java.t
| C of C.t
| Linters_dummy_method
| Block of Block.t
| ObjC_Cpp of ObjC_Cpp.t
| WithBlockParameters of t * Block.block_name list
[@@deriving compare]
let equal = [%compare.equal: t]
(** hash function for procname *)
let hash = Hashtbl.hash
let with_block_parameters base blocks = WithBlockParameters (base, blocks)
let is_java = function Java _ -> true | _ -> false
(* TODO: deprecate this unfortunately named function and use is_clang instead *)
let is_c_method = function ObjC_Cpp _ -> true | _ -> false
let is_c_function = function C _ -> true | _ -> false
let is_clang = function ObjC_Cpp name -> ObjC_Cpp.is_objc_method name | name -> is_c_function name
let is_java_lift f = function Java java_pname -> f java_pname | _ -> false
let is_java_access_method = is_java_lift Java.is_access_method
let is_java_class_initializer = is_java_lift Java.is_class_initializer
let is_objc_method procname =
match procname with ObjC_Cpp name -> ObjC_Cpp.is_objc_method name | _ -> false
let block_name_of_procname procname =
match procname with
| Block block ->
block.name
| _ ->
Logging.die InternalError "Only to be called with Objective-C block names"
let empty_block = Block {name= ""; parameters= []}
(** Replace the class name component of a procedure name. In case of Java, replace package and class
name. *)
let rec replace_class t (new_class : Typ.Name.t) =
match t with
| Java j ->
Java {j with class_name= new_class}
| ObjC_Cpp osig ->
ObjC_Cpp {osig with class_name= new_class}
| WithBlockParameters (base, blocks) ->
WithBlockParameters (replace_class base new_class, blocks)
| C _ | Block _ | Linters_dummy_method ->
t
let get_class_type_name = function
| Java java_pname ->
Some (Java.get_class_type_name java_pname)
| ObjC_Cpp objc_pname ->
Some (ObjC_Cpp.get_class_type_name objc_pname)
| _ ->
None
let get_class_name = function
| Java java_pname ->
Some (Java.get_class_name java_pname)
| ObjC_Cpp objc_pname ->
Some (ObjC_Cpp.get_class_name objc_pname)
| _ ->
None
let is_method_in_objc_protocol t =
match t with ObjC_Cpp osig -> Typ.Name.is_objc_protocol osig.class_name | _ -> false
let rec objc_cpp_replace_method_name t (new_method_name : string) =
match t with
| ObjC_Cpp osig ->
ObjC_Cpp {osig with method_name= new_method_name}
| WithBlockParameters (base, blocks) ->
WithBlockParameters (objc_cpp_replace_method_name base new_method_name, blocks)
| C _ | Block _ | Linters_dummy_method | Java _ ->
t
(** Return the method/function of a procname. *)
let rec get_method = function
| ObjC_Cpp name ->
name.method_name
| WithBlockParameters (base, _) ->
get_method base
| C {name} ->
QualifiedCppName.to_qual_string name
| Block {name} ->
name
| Java j ->
j.method_name
| Linters_dummy_method ->
"Linters_dummy_method"
(** Return whether the procname is a block procname. *)
let is_objc_block = function Block _ -> true | _ -> false
(** Return the language of the procedure. *)
let get_language = function
| ObjC_Cpp _ ->
Language.Clang
| C _ ->
Language.Clang
| Block _ ->
Language.Clang
| Linters_dummy_method ->
Language.Clang
| WithBlockParameters _ ->
Language.Clang
| Java _ ->
Language.Java
(** [is_constructor pname] returns true if [pname] is a constructor *)
let is_constructor = function
| Java js ->
String.equal js.method_name Java.constructor_method_name
| ObjC_Cpp {kind= CPPConstructor _} ->
true
| ObjC_Cpp {kind; method_name} when ObjC_Cpp.is_objc_kind kind ->
ObjC_Cpp.is_objc_constructor method_name
| _ ->
false
(** [is_infer_undefined pn] returns true if [pn] is a special Infer undefined proc *)
let is_infer_undefined pn =
match pn with
| Java j ->
let regexp = Str.regexp_string "com.facebook.infer.builtins.InferUndefined" in
Str.string_match regexp (Java.get_class_name j) 0
| _ ->
(* TODO: add cases for obj-c, c, c++ *)
false
let get_global_name_of_initializer = function
| C {name}
when String.is_prefix ~prefix:Config.clang_initializer_prefix
(QualifiedCppName.to_qual_string name) ->
let name_str = QualifiedCppName.to_qual_string name in
let prefix_len = String.length Config.clang_initializer_prefix in
Some (String.sub name_str ~pos:prefix_len ~len:(String.length name_str - prefix_len))
| _ ->
None
(** Very verbose representation of an existing Procname.t *)
let rec pp_unique_id fmt = function
| Java j ->
Java.pp Verbose fmt j
| C osig ->
C.pp Verbose fmt osig
| ObjC_Cpp osig ->
ObjC_Cpp.pp Verbose fmt osig
| Block bsig ->
Block.pp Verbose fmt bsig
| WithBlockParameters (base, []) ->
pp_unique_id fmt base
| WithBlockParameters (base, (_ :: _ as blocks)) ->
pp_unique_id fmt base ;
F.pp_print_string fmt "_" ;
Pp.seq ~sep:"_" F.pp_print_string fmt blocks
| Linters_dummy_method ->
F.pp_print_string fmt "Linters_dummy_method"
let to_unique_id proc_name = F.asprintf "%a" pp_unique_id proc_name
(** Convert a proc name to a string for the user to see *)
let rec pp fmt = function
| Java j ->
Java.pp Non_verbose fmt j
| C osig ->
C.pp Non_verbose fmt osig
| ObjC_Cpp osig ->
ObjC_Cpp.pp Non_verbose fmt osig
| Block bsig ->
Block.pp Non_verbose fmt bsig
| WithBlockParameters (base, []) ->
pp fmt base
| WithBlockParameters (base, (_ :: _ as blocks)) ->
pp fmt base ;
F.pp_print_string fmt "_" ;
Pp.seq ~sep:"_" F.pp_print_string fmt blocks
| Linters_dummy_method ->
pp_unique_id fmt Linters_dummy_method
let to_string proc_name = F.asprintf "%a" pp proc_name
(** Convenient representation of a procname for external tools (e.g. eclipse plugin) *)
let rec pp_simplified_string ?(withclass = false) fmt = function
| Java j ->
Java.pp ~withclass Simple fmt j
| C osig ->
C.pp Simple fmt osig
| ObjC_Cpp osig ->
ObjC_Cpp.pp Simple fmt osig
| Block bsig ->
Block.pp Simple fmt bsig
| WithBlockParameters (base, _) ->
pp_simplified_string fmt base
| Linters_dummy_method ->
pp_unique_id fmt Linters_dummy_method
let to_simplified_string ?withclass proc_name =
F.asprintf "%a" (pp_simplified_string ?withclass) proc_name
let from_string_c_fun func = C (C.from_string func)
let java_inner_class_prefix_regex = Str.regexp "\\$[0-9]+"
let hashable_name proc_name =
match proc_name with
| Java pname -> (
(* Strip autogenerated anonymous inner class numbers in order to keep the bug hash
invariant when introducing new anonymous classes *)
let name = F.asprintf "%a" (Java.pp ~withclass:true Simple) pname in
match Str.search_forward java_inner_class_prefix_regex name 0 with
| _ ->
Str.global_replace java_inner_class_prefix_regex "$_" name
| exception Caml.Not_found ->
name )
| ObjC_Cpp m when ObjC_Cpp.is_objc_method m ->
(* In Objective C, the list of parameters is part of the method name. To prevent the bug
hash to change when a parameter is introduced or removed, only the part of the name
before the first colon is used for the bug hash *)
let name = F.asprintf "%a" (pp_simplified_string ~withclass:true) proc_name in
List.hd_exn (String.split_on_chars name ~on:[':'])
| _ ->
(* Other cases for C and C++ method names *)
F.asprintf "%a" (pp_simplified_string ~withclass:true) proc_name
let rec get_parameters procname =
let clang_param_to_param clang_params =
List.map ~f:(fun par -> Parameter.ClangParameter par) clang_params
in
match procname with
| Java j ->
List.map ~f:(fun par -> Parameter.JavaParameter par) (Java.get_parameters j)
| C osig ->
clang_param_to_param (C.get_parameters osig)
| ObjC_Cpp osig ->
clang_param_to_param (ObjC_Cpp.get_parameters osig)
| Block bsig ->
clang_param_to_param (Block.get_parameters bsig)
| WithBlockParameters (base, _) ->
get_parameters base
| Linters_dummy_method ->
[]
let rec replace_parameters new_parameters procname =
let params_to_java_params params =
List.map
~f:(fun param ->
match param with
| Parameter.JavaParameter par ->
par
| _ ->
Logging.(die InternalError)
"Expected Java parameters in Java procname, but got Clang parameters" params )
params
in
let params_to_clang_params params =
List.map
~f:(fun param ->
match param with
| Parameter.ClangParameter par ->
par
| _ ->
Logging.(die InternalError)
"Expected Clang parameters in Clang procname, but got Java parameters" params )
params
in
match procname with
| Java j ->
Java (Java.replace_parameters (params_to_java_params new_parameters) j)
| C osig ->
C (C.replace_parameters (params_to_clang_params new_parameters) osig)
| ObjC_Cpp osig ->
ObjC_Cpp (ObjC_Cpp.replace_parameters (params_to_clang_params new_parameters) osig)
| Block bsig ->
Block (Block.replace_parameters (params_to_clang_params new_parameters) bsig)
| WithBlockParameters (base, blocks) ->
WithBlockParameters (replace_parameters new_parameters base, blocks)
| Linters_dummy_method ->
procname
let parameter_of_name procname class_name =
match procname with
| Java _ ->
Parameter.JavaParameter (Java.java_type_of_name class_name)
| _ ->
Parameter.ClangParameter (Parameter.clang_param_of_name class_name)
let describe f pn =
let name = hashable_name pn in
match String.lsplit2 ~on:'<' name with
| Some (name_without_template, _template_part) ->
F.pp_print_string f name_without_template
| None ->
F.pp_print_string f name
module Hashable = struct
type nonrec t = t
let equal = equal
let hash = hash
end
module Hash = Hashtbl.Make (Hashable)
module Map = PrettyPrintable.MakePPMap (struct
type nonrec t = t
let compare = compare
let pp = pp
end)
module Set = PrettyPrintable.MakePPSet (struct
type nonrec t = t
let compare = compare
let pp = pp
end)
let get_qualifiers pname =
match pname with
| C {name} ->
name
| ObjC_Cpp objc_cpp ->
ObjC_Cpp.get_class_qualifiers objc_cpp
|> QualifiedCppName.append_qualifier ~qual:objc_cpp.method_name
| _ ->
QualifiedCppName.empty
(** Convert a proc name to a filename *)
let to_filename ?crc_only pname =
(* filenames for clang procs are REVERSED qualifiers with '#' as separator *)
let pp_rev_qualified fmt pname =
let rev_qualifiers = get_qualifiers pname |> QualifiedCppName.to_rev_list in
Pp.seq ~sep:"#" F.pp_print_string fmt rev_qualifiers
in
let proc_id =
match pname with
| C {parameters; mangled} ->
let pp_mangled fmt = function None -> () | Some mangled -> F.fprintf fmt "#%s" mangled in
F.asprintf "%a%a%a" pp_rev_qualified pname Parameter.pp_parameters parameters pp_mangled
mangled
| ObjC_Cpp objc_cpp ->
F.asprintf "%a%a#%a" pp_rev_qualified pname Parameter.pp_parameters objc_cpp.parameters
ObjC_Cpp.pp_verbose_kind objc_cpp.kind
| _ ->
F.asprintf "%a" pp_unique_id pname
in
Escape.escape_filename @@ DB.append_crc_cutoff ?crc_only proc_id
module SQLite = struct
module T = struct
type nonrec t = t
let compare = compare
let hash = hash
let sexp_of_t p = Sexp.Atom (F.asprintf "%a" pp p)
end
module Serializer = SqliteUtils.MarshalledDataForComparison (T)
let pname_to_key = Base.Hashtbl.create (module T)
let serialize pname =
let default () = Serializer.serialize pname in
Base.Hashtbl.find_or_add pname_to_key pname ~default
let deserialize = Serializer.deserialize
let clear_cache () = Base.Hashtbl.clear pname_to_key
end
module SQLiteList = SqliteUtils.MarshalledDataNOTForComparison (struct
type nonrec t = t list
end)

@ -0,0 +1,316 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module F = Format
(** Module for Procedure Names. *)
(** Type of java procedure names. *)
module Java : sig
type kind =
| Non_Static
(** in Java, procedures called with invokevirtual, invokespecial, and invokeinterface *)
| Static (** in Java, procedures called with invokestatic *)
type t [@@deriving compare]
type java_type = Typ.Name.Java.Split.t
val constructor_method_name : string
val class_initializer_method_name : string
val compare_java_type : java_type -> java_type -> int
val make : Typ.Name.t -> java_type option -> string -> java_type list -> kind -> t
(** Create a Java procedure name from its class_name method_name args_type_name return_type_name
method_kind. *)
val replace_method_name : string -> t -> t
(** Replace the method name of an existing java procname. *)
val replace_parameters : java_type list -> t -> t
(** Replace the parameters of a java procname. *)
val replace_return_type : java_type -> t -> t
(** Replace the method of a java procname. *)
val get_class_name : t -> string
(** Return the fully qualified class name of a java procedure name (package + class name) *)
val get_class_type_name : t -> Typ.Name.t
(** Return the class name as a typename of a java procedure name. *)
val get_simple_class_name : t -> string
(** Return the simple class name of a java procedure name (i.e. name without the package info). *)
val get_package : t -> string option
(** Return the package name of a java procedure name. *)
val get_method : t -> string
(** Return the method name of a java procedure name. *)
val get_parameters : t -> java_type list
(** Return the parameters of a java procedure name. *)
val get_return_typ : t -> Typ.t
(** Return the return type of [pname_java]. return Tvoid if there's no return type *)
val is_constructor : t -> bool
(** Whether the method is constructor *)
val is_access_method : t -> bool
(** Check if the procedure name is an acess method (e.g. access$100 used to access private members
from a nested class. *)
val is_autogen_method : t -> bool
(** Check if the procedure name is of an auto-generated method containing '$'. *)
val is_anonymous_inner_class_constructor : t -> bool
(** Check if the procedure name is an anonymous inner class constructor. *)
val is_close : t -> bool
(** Check if the method name is "close". *)
val is_static : t -> bool
(** Check if the java procedure is static. *)
val is_vararg : t -> bool
(** Check if the proc name has the type of a java vararg. Note: currently only checks that the
last argument has type Object[]. *)
val is_lambda : t -> bool
(** Check if the proc name comes from a lambda expression *)
val is_generated : t -> bool
(** Check if the proc name comes from generated code *)
val is_class_initializer : t -> bool
(** Check if this is a class initializer. *)
val get_class_initializer : Typ.Name.t -> t
(** Given a java class, generate the procname of its static initializer. *)
val is_external : t -> bool
(** Check if the method belongs to one of the specified external packages *)
end
module Parameter : sig
(** Type for parameters in clang procnames, [Some name] means the parameter is of type pointer to
struct, with [name] being the name of the struct, [None] means the parameter is of some other
type. *)
type clang_parameter = Typ.Name.t option [@@deriving compare]
(** Type for parameters in procnames, for java and clang. *)
type t = JavaParameter of Java.java_type | ClangParameter of clang_parameter
[@@deriving compare]
val of_typ : Typ.t -> clang_parameter
end
module ObjC_Cpp : sig
type kind =
| CPPMethod of {mangled: string option}
| CPPConstructor of {mangled: string option; is_constexpr: bool}
| CPPDestructor of {mangled: string option}
| ObjCClassMethod
| ObjCInstanceMethod
| ObjCInternalMethod
[@@deriving compare]
(** Type of Objective C and C++ procedure names: method signatures. *)
type t =
{ class_name: Typ.Name.t
; kind: kind
; method_name: string
; parameters: Parameter.clang_parameter list
; template_args: Typ.template_spec_info }
[@@deriving compare]
val make :
Typ.Name.t -> string -> kind -> Typ.template_spec_info -> Parameter.clang_parameter list -> t
(** Create an objc procedure name from a class_name and method_name. *)
val get_class_name : t -> string
val get_class_type_name : t -> Typ.Name.t [@@warning "-32"]
val get_class_qualifiers : t -> QualifiedCppName.t
val objc_method_kind_of_bool : bool -> kind
(** Create ObjC method type from a bool is_instance. *)
val is_objc_constructor : string -> bool
(** Check if this is a constructor method in Objective-C. *)
val is_objc_dealloc : string -> bool
(** Check if this is a dealloc method in Objective-C. *)
val is_destructor : t -> bool
(** Check if this is a dealloc method. *)
val is_inner_destructor : t -> bool
(** Check if this is a frontend-generated "inner" destructor (see D5834555/D7189239) *)
val is_constexpr : t -> bool
(** Check if this is a constexpr function. *)
val is_cpp_lambda : t -> bool
(** Return whether the procname is a cpp lambda. *)
end
module C : sig
(** Type of c procedure names. *)
type t = private
{ name: QualifiedCppName.t
; mangled: string option
; parameters: Parameter.clang_parameter list
; template_args: Typ.template_spec_info }
val c :
QualifiedCppName.t -> string -> Parameter.clang_parameter list -> Typ.template_spec_info -> t
(** Create a C procedure name from plain and mangled name. *)
end
module Block : sig
(** Type of Objective C block names. *)
type block_name = string
type t = {name: block_name; parameters: Parameter.clang_parameter list} [@@deriving compare]
val make : block_name -> Parameter.clang_parameter list -> t
end
(** Type of procedure names. WithBlockParameters is used for creating an instantiation of a method
that contains block parameters and it's called with concrete blocks. For example:
[foo(Block block) {block();}] [bar() {foo(my_block)}] is executed as
[foo_my_block() {my_block(); }] where foo_my_block is created with WithBlockParameters (foo,
[my_block]) *)
type t =
| Java of Java.t
| C of C.t
| Linters_dummy_method
| Block of Block.t
| ObjC_Cpp of ObjC_Cpp.t
| WithBlockParameters of t * Block.block_name list
[@@deriving compare]
val block_name_of_procname : t -> Block.block_name
val equal : t -> t -> bool
val get_class_type_name : t -> Typ.Name.t option
val get_class_name : t -> string option
val get_parameters : t -> Parameter.t list
val replace_parameters : Parameter.t list -> t -> t
val parameter_of_name : t -> Typ.Name.t -> Parameter.t
val is_java_access_method : t -> bool
val is_java_class_initializer : t -> bool
val is_objc_method : t -> bool
module Hash : Caml.Hashtbl.S with type key = t
(** Hash tables with proc names as keys. *)
module Map : PrettyPrintable.PPMap with type key = t
(** Maps from proc names. *)
module Set : PrettyPrintable.PPSet with type elt = t
(** Sets of proc names. *)
module SQLite : sig
val serialize : t -> Sqlite3.Data.t
val deserialize : Sqlite3.Data.t -> t
val clear_cache : unit -> unit
end
module SQLiteList : SqliteUtils.Data with type t = t list
val empty_block : t
(** Empty block name. *)
val get_language : t -> Language.t
(** Return the language of the procedure. *)
val get_method : t -> string
(** Return the method/function of a procname. *)
val is_objc_block : t -> bool
(** Return whether the procname is a block procname. *)
val is_c_method : t -> bool
(** Return true this is an Objective-C/C++ method name. *)
val is_clang : t -> bool
(** Return true if this is a C, C++, or Objective-C procedure name *)
val is_constructor : t -> bool
(** Check if this is a constructor. *)
val is_java : t -> bool
(** Check if this is a Java procedure name. *)
val with_block_parameters : t -> Block.block_name list -> t
(** Create a procedure name instantiated with block parameters from a base procedure name and a list
of block procedure names (the arguments). *)
val objc_cpp_replace_method_name : t -> string -> t
val is_infer_undefined : t -> bool
(** Check if this is a special Infer undefined procedure. *)
val get_global_name_of_initializer : t -> string option
(** Return the name of the global for which this procedure is the initializer if this is an
initializer, None otherwise. *)
val pp : Format.formatter -> t -> unit
(** Pretty print a proc name for the user to see. *)
val to_string : t -> string
(** Convert a proc name into a string for the user to see. *)
val describe : Format.formatter -> t -> unit
(** to use in user messages *)
val replace_class : t -> Typ.Name.t -> t
(** Replace the class name component of a procedure name. In case of Java, replace package and class
name. *)
val is_method_in_objc_protocol : t -> bool
val pp_simplified_string : ?withclass:bool -> F.formatter -> t -> unit
(** Pretty print a proc name as an easy string for the user to see in an IDE. *)
val to_simplified_string : ?withclass:bool -> t -> string
(** Convert a proc name into an easy string for the user to see in an IDE. *)
val from_string_c_fun : string -> t
(** Convert a string to a c function name. *)
val hashable_name : t -> string
(** Convert the procedure name in a format suitable for computing the bug hash. *)
val pp_unique_id : F.formatter -> t -> unit
(** Print a proc name as a unique identifier. *)
val to_unique_id : t -> string
(** Convert a proc name into a unique identifier. *)
val to_filename : ?crc_only:bool -> t -> string
(** Convert a proc name to a filename or only to its crc. *)
val get_qualifiers : t -> QualifiedCppName.t
(** get qualifiers of C/objc/C++ method/function *)

@ -21,11 +21,11 @@ and non_empty
type typ = Typ.t
type c = Typ.Procname.C.t
type c = Procname.C.t
type objc_cpp = Typ.Procname.ObjC_Cpp.t
type objc_cpp = Procname.ObjC_Cpp.t
type java = Typ.Procname.Java.t
type java = Procname.Java.t
type qual_name = QualifiedCppName.t
@ -53,8 +53,7 @@ let templated_name_of_class_name class_name =
let templated_name_of_java java =
let qual_name =
QualifiedCppName.of_list
[Typ.Procname.Java.get_class_name java; Typ.Procname.Java.get_method java]
QualifiedCppName.of_list [Procname.Java.get_class_name java; Procname.Java.get_method java]
in
(qual_name, [])
@ -117,7 +116,7 @@ let name_cons :
| _ ->
None
in
let on_objc_cpp context f (objc_cpp : Typ.Procname.ObjC_Cpp.t) =
let on_objc_cpp context f (objc_cpp : Procname.ObjC_Cpp.t) =
if match_fuzzy_name objc_cpp.method_name then
on_templated_name context f (templated_name_of_class_name objc_cpp.class_name)
else None
@ -138,7 +137,7 @@ let name_cons_f :
| _ ->
None
in
let on_objc_cpp context f (objc_cpp : Typ.Procname.ObjC_Cpp.t) =
let on_objc_cpp context f (objc_cpp : Procname.ObjC_Cpp.t) =
if f_name context objc_cpp.method_name then
on_templated_name context f (templated_name_of_class_name objc_cpp.class_name)
else None
@ -164,7 +163,7 @@ let all_names_cons :
on_templated_name_rec context f (rest, []) )
in
let on_templated_name = on_templated_name_rec in
let on_objc_cpp context f (objc_cpp : Typ.Procname.ObjC_Cpp.t) =
let on_objc_cpp context f (objc_cpp : Procname.ObjC_Cpp.t) =
match on_objc_cpp context f objc_cpp with
| Some _ as some ->
some
@ -182,7 +181,7 @@ let templ_begin :
let on_templated_name context f (qual_name, template_args) =
match on_qual_name context f qual_name with None -> None | Some f -> Some (f, template_args)
in
let on_objc_cpp context f (objc_cpp : Typ.Procname.ObjC_Cpp.t) =
let on_objc_cpp context f (objc_cpp : Procname.ObjC_Cpp.t) =
match on_objc_cpp context f objc_cpp with
| None ->
None
@ -468,7 +467,7 @@ module Call = struct
-> ('context, 'f_out, 'arg_payload) pre_result }
type ('context, 'f, 'arg_payload) dispatcher =
'context -> Typ.Procname.t -> 'arg_payload FuncArg.t list -> 'f option
'context -> Procname.t -> 'arg_payload FuncArg.t list -> 'f option
let args_begin :
('context, 'f_in, 'f_out, non_empty, 'arg_payload) path_matcher
@ -785,8 +784,7 @@ module Call = struct
let wrong_args_internal_error : _ matcher =
let on_procname procname =
Logging.(die InternalError)
"Unexpected number/types of arguments for %a" Typ.Procname.pp procname
Logging.(die InternalError) "Unexpected number/types of arguments for %a" Procname.pp procname
in
let on_c _context c _args = on_procname (C c) in
let on_java _context java _args = on_procname (Java java) in
@ -907,7 +905,7 @@ end
module ProcName = struct
include NameCommon
type ('context, 'f, 'arg_payload) dispatcher = 'context -> Typ.Procname.t -> 'f option
type ('context, 'f, 'arg_payload) dispatcher = 'context -> Procname.t -> 'f option
let make_dispatcher :
('context, 'f, 'arg_payload) matcher list -> ('context, 'f, 'arg_payload) dispatcher =
@ -919,7 +917,7 @@ module ProcName = struct
List.find_map matchers ~f:(fun (matcher : _ matcher) ->
matcher.on_templated_name context templated_name )
in
let on_java context (java : Typ.Procname.Java.t) =
let on_java context (java : Procname.Java.t) =
let templated_name = templated_name_of_java java in
on_templated_name context templated_name
in

@ -141,8 +141,7 @@ module type NameCommon = sig
end
module ProcName :
NameCommon
with type ('context, 'f, 'arg_payload) dispatcher = 'context -> Typ.Procname.t -> 'f option
NameCommon with type ('context, 'f, 'arg_payload) dispatcher = 'context -> Procname.t -> 'f option
module TypName :
NameCommon with type ('context, 'f, 'arg_payload) dispatcher = 'context -> Typ.name -> 'f option
@ -156,7 +155,7 @@ module Call : sig
include
Common
with type ('context, 'f, 'arg_payload) dispatcher =
'context -> Typ.Procname.t -> 'arg_payload FuncArg.t list -> 'f option
'context -> Procname.t -> 'arg_payload FuncArg.t list -> 'f option
val merge_dispatchers :
('context, 'f, 'arg_payload) dispatcher

@ -16,11 +16,10 @@ type translation_unit = SourceFile.t option [@@deriving compare]
(** Kind of global variables *)
type pvar_kind =
| Local_var of Typ.Procname.t (** local variable belonging to a function *)
| Callee_var of Typ.Procname.t (** local variable belonging to a callee *)
| Abduced_retvar of Typ.Procname.t * Location.t
(** synthetic variable to represent return value *)
| Abduced_ref_param of Typ.Procname.t * int * Location.t
| Local_var of Procname.t (** local variable belonging to a function *)
| Callee_var of Procname.t (** local variable belonging to a callee *)
| Abduced_retvar of Procname.t * Location.t (** synthetic variable to represent return value *)
| Abduced_ref_param of Procname.t * int * Location.t
(** synthetic variable to represent param passed by reference *)
| Global_var of
{ translation_unit: translation_unit
@ -38,7 +37,7 @@ type t = {pv_hash: int; pv_name: Mangled.t; pv_kind: pvar_kind} [@@deriving comp
let get_name_of_local_with_procname var =
match var.pv_kind with
| Local_var pname ->
Mangled.from_string (F.asprintf "%s_%a" (Mangled.to_string var.pv_name) Typ.Procname.pp pname)
Mangled.from_string (F.asprintf "%s_%a" (Mangled.to_string var.pv_name) Procname.pp pname)
| _ ->
var.pv_name
@ -131,7 +130,7 @@ let is_frontend_tmp pvar =
||
match pvar.pv_kind with
| Local_var pname ->
Typ.Procname.is_java pname && is_bytecode_tmp name
Procname.is_java pname && is_bytecode_tmp name
| _ ->
false
@ -218,7 +217,7 @@ let to_callee pname pvar =
let name_hash (name : Mangled.t) = Hashtbl.hash name
(** [mk name proc_name] creates a program var with the given function name *)
let mk (name : Mangled.t) (proc_name : Typ.Procname.t) : t =
let mk (name : Mangled.t) (proc_name : Procname.t) : t =
{pv_hash= name_hash name; pv_name= name; pv_kind= Local_var proc_name}
@ -228,7 +227,7 @@ let get_ret_param_pvar pname = mk Ident.name_return_param pname
(** [mk_callee name proc_name] creates a program var for a callee function with the given function
name *)
let mk_callee (name : Mangled.t) (proc_name : Typ.Procname.t) : t =
let mk_callee (name : Mangled.t) (proc_name : Procname.t) : t =
{pv_hash= name_hash name; pv_name= name; pv_kind= Callee_var proc_name}
@ -250,15 +249,13 @@ let mk_tmp name pname =
(** create an abduced return variable for a call to [proc_name] at [loc] *)
let mk_abduced_ret (proc_name : Typ.Procname.t) (loc : Location.t) : t =
let name = Mangled.from_string (F.asprintf "$RET_%a" Typ.Procname.pp_unique_id proc_name) in
let mk_abduced_ret (proc_name : Procname.t) (loc : Location.t) : t =
let name = Mangled.from_string (F.asprintf "$RET_%a" Procname.pp_unique_id proc_name) in
{pv_hash= name_hash name; pv_name= name; pv_kind= Abduced_retvar (proc_name, loc)}
let mk_abduced_ref_param (proc_name : Typ.Procname.t) (index : int) (loc : Location.t) : t =
let name =
Mangled.from_string (F.asprintf "$REF_PARAM_VAL_%a" Typ.Procname.pp_unique_id proc_name)
in
let mk_abduced_ref_param (proc_name : Procname.t) (index : int) (loc : Location.t) : t =
let name = Mangled.from_string (F.asprintf "$REF_PARAM_VAL_%a" Procname.pp_unique_id proc_name) in
{pv_hash= name_hash name; pv_name= name; pv_kind= Abduced_ref_param (proc_name, index, loc)}
@ -286,12 +283,12 @@ let get_initializer_pname {pv_name; pv_kind} =
match translation_unit with
| Some file ->
let mangled = SourceFile.to_string file |> Utils.string_crc_hex32 in
Typ.Procname.C
(Typ.Procname.C.c (QualifiedCppName.of_qual_string name) mangled [] Typ.NoTemplate)
Procname.C
(Procname.C.c (QualifiedCppName.of_qual_string name) mangled [] Typ.NoTemplate)
|> Option.return
| None ->
None
else Some (Typ.Procname.from_string_c_fun name)
else Some (Procname.from_string_c_fun name)
| _ ->
None

@ -27,7 +27,7 @@ val compare_modulo_this : t -> t -> int
val equal : t -> t -> bool
(** Equality for pvar's *)
val get_declaring_function : t -> Typ.Procname.t option
val get_declaring_function : t -> Procname.t option
(** if not a global, return function declaring var *)
val d : t -> unit
@ -36,10 +36,10 @@ val d : t -> unit
val get_name : t -> Mangled.t
(** Get the name component of a program variable. *)
val get_ret_pvar : Typ.Procname.t -> t
val get_ret_pvar : Procname.t -> t
(** [get_ret_pvar proc_name] retuns the return pvar associated with the procedure name *)
val get_ret_param_pvar : Typ.Procname.t -> t
val get_ret_param_pvar : Procname.t -> t
(** [get_ret_param_pvar proc_name] retuns the return_param pvar associated with the procedure name *)
val get_simplified_name : t -> string
@ -92,16 +92,16 @@ val is_objc_static_local_of_proc_name : string -> t -> bool
val is_block_pvar : t -> bool
(** Check if a pvar is a local pointing to a block in objc *)
val mk : Mangled.t -> Typ.Procname.t -> t
val mk : Mangled.t -> Procname.t -> t
(** [mk name proc_name] creates a program var with the given function name *)
val mk_abduced_ref_param : Typ.Procname.t -> int -> Location.t -> t
val mk_abduced_ref_param : Procname.t -> int -> Location.t -> t
(** create an abduced variable for a parameter passed by reference *)
val mk_abduced_ret : Typ.Procname.t -> Location.t -> t
val mk_abduced_ret : Procname.t -> Location.t -> t
(** create an abduced return variable for a call to [proc_name] at [loc] *)
val mk_callee : Mangled.t -> Typ.Procname.t -> t
val mk_callee : Mangled.t -> Procname.t -> t
(** [mk_callee name proc_name] creates a program var for a callee function with the given function
name *)
@ -116,7 +116,7 @@ val mk_global :
-> t
(** create a global variable with the given name *)
val mk_tmp : string -> Typ.Procname.t -> t
val mk_tmp : string -> Procname.t -> t
(** create a fresh temporary variable local to procedure [pname]. for use in the frontends only! *)
val pp : Pp.env -> F.formatter -> t -> unit
@ -130,7 +130,7 @@ val pp_value_non_verbose : F.formatter -> t -> unit
val pp_translation_unit : F.formatter -> translation_unit -> unit
val to_callee : Typ.Procname.t -> t -> t
val to_callee : Procname.t -> t -> t
(** Turn an ordinary program variable into a callee program variable *)
val to_seed : t -> t
@ -154,7 +154,7 @@ val is_pod : t -> bool
(** Is the variable's type a "Plain Old Data" type (C++)? Always (potentially incorrectly) returns
[true] for non-globals. *)
val get_initializer_pname : t -> Typ.Procname.t option
val get_initializer_pname : t -> Procname.t option
(** Get the procname of the initializer function for the given global variable *)
val get_name_of_local_with_procname : t -> Mangled.t

@ -194,7 +194,7 @@ let add_with_block_parameters_flag instr =
| Call (ret_id_typ, Exp.Const (Const.Cfun pname), arg_ts, loc, cf) ->
if
List.exists ~f:(fun (exp, _) -> Exp.is_objc_block_closure exp) arg_ts
&& Typ.Procname.is_clang pname
&& Procname.is_clang pname
(* to be extended to other methods *)
then
let cf' = {cf with cf_with_block_parameters= true} in

@ -23,7 +23,7 @@ let get_existing_data source_file =
SqliteUtils.result_option ~finalize:false db ~log:"looking for pre-existing source file data"
stmt ~read_row:(fun stmt ->
let tenv = Sqlite3.column stmt 0 |> Tenv.SQLite.deserialize
and proc_names = Sqlite3.column stmt 1 |> Typ.Procname.SQLiteList.deserialize in
and proc_names = Sqlite3.column stmt 1 |> Procname.SQLiteList.deserialize in
(tenv, proc_names) ) )
@ -64,7 +64,7 @@ let add source_file cfg tenv integer_type_widths =
~source_file:(SourceFile.SQLite.serialize source_file)
~tenv:(Tenv.SQLite.serialize tenv)
~integer_type_widths:(Typ.IntegerWidths.SQLite.serialize integer_type_widths)
~proc_names:(Typ.Procname.SQLiteList.serialize proc_names)
~proc_names:(Procname.SQLiteList.serialize proc_names)
let get_all ~filter () =
@ -91,7 +91,7 @@ let proc_names_of_source source =
|> SqliteUtils.check_result_code db ~log:"load bind source file" ;
SqliteUtils.result_single_column_option ~finalize:false db
~log:"SourceFiles.proc_names_of_source" load_stmt
|> Option.value_map ~default:[] ~f:Typ.Procname.SQLiteList.deserialize )
|> Option.value_map ~default:[] ~f:Procname.SQLiteList.deserialize )
let exists_source_statement =
@ -152,7 +152,7 @@ let select_all_source_files_statement =
let pp_all ~filter ~type_environment ~procedure_names ~freshly_captured fmt () =
let pp_procnames fmt procs =
F.fprintf fmt "@[<v>" ;
List.iter ~f:(F.fprintf fmt "%a@," Typ.Procname.pp) procs ;
List.iter ~f:(F.fprintf fmt "%a@," Procname.pp) procs ;
F.fprintf fmt "@]"
in
let pp_if stmt title condition deserialize pp fmt column =
@ -163,8 +163,7 @@ let pp_all ~filter ~type_environment ~procedure_names ~freshly_captured fmt () =
F.fprintf fmt "%a@,%a%a%a" SourceFile.pp source_file
(pp_if stmt "type_environment" type_environment Tenv.SQLite.deserialize Tenv.pp_per_file)
1
(pp_if stmt "procedure_names" procedure_names Typ.Procname.SQLiteList.deserialize
pp_procnames)
(pp_if stmt "procedure_names" procedure_names Procname.SQLiteList.deserialize pp_procnames)
2
(pp_if stmt "freshly_captured" freshly_captured deserialize_freshly_captured
Format.pp_print_bool)

@ -13,7 +13,7 @@ val add : SourceFile.t -> Cfg.t -> Tenv.per_file -> Typ.IntegerWidths.t option -
val get_all : filter:Filtering.source_files_filter -> unit -> SourceFile.t list
(** get all the source files in the database *)
val proc_names_of_source : SourceFile.t -> Typ.Procname.t list
val proc_names_of_source : SourceFile.t -> Procname.t list
(** list of all the proc names (declared and defined) found in a source file *)
val is_captured : SourceFile.t -> bool

@ -104,7 +104,7 @@ let with_formals_types_proc callee_pdesc resolved_pdesc substitutions =
when call_flags.CallFlags.cf_virtual && redirect_typename id <> None ->
let redirected_typename = Option.value_exn (redirect_typename id) in
let redirected_typ = mk_ptr_typ redirected_typename in
let redirected_pname = Typ.Procname.replace_class callee_pname redirected_typename in
let redirected_pname = Procname.replace_class callee_pname redirected_typename in
let args =
let other_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in
(Exp.Var id, redirected_typ) :: other_args
@ -152,8 +152,8 @@ let with_formals_types ?(has_clang_model = false) callee_pdesc resolved_pname ar
result
| Unequal_lengths ->
L.(debug Analysis Medium)
"Call mismatch: method %a has %i paramters but is called with %i arguments@."
Typ.Procname.pp resolved_pname
"Call mismatch: method %a has %i paramters but is called with %i arguments@." Procname.pp
resolved_pname
(List.length callee_attributes.formals)
(List.length args) ;
raise UnmatchedParameters
@ -171,7 +171,7 @@ let with_formals_types ?(has_clang_model = false) callee_pdesc resolved_pname ar
Logging.die InternalError
"specialize_types should only be called with defined procedures, but we cannot find \
the captured file of procname %a"
Typ.Procname.pp pname
Procname.pp pname
else callee_attributes.translation_unit
in
let resolved_attributes =
@ -185,7 +185,7 @@ let with_formals_types ?(has_clang_model = false) callee_pdesc resolved_pname ar
let resolved_proc_desc = with_formals_types_proc callee_pdesc resolved_proc_desc substitutions in
(* The attributes here are used to retrieve the per-file type environment for Clang languages.
The analysis for Java is using a global type environment *)
if not (Typ.Procname.is_java resolved_pname) then
if not (Procname.is_java resolved_pname) then
Attributes.store ~proc_desc:(Some resolved_proc_desc) resolved_attributes ;
resolved_proc_desc
@ -298,7 +298,7 @@ let with_block_args callee_pdesc pname_with_block_args block_args =
let callee_attributes = Procdesc.get_attributes callee_pdesc in
(* Substitution from a block parameter to the block name and the new formals
that correspond to the captured variables *)
let substitutions : (Typ.Procname.t * (Mangled.t * Typ.t) list) Mangled.Map.t =
let substitutions : (Procname.t * (Mangled.t * Typ.t) list) Mangled.Map.t =
List.fold2_exn callee_attributes.formals block_args ~init:Mangled.Map.empty
~f:(fun subts (param_name, _) block_arg_opt ->
match block_arg_opt with
@ -341,7 +341,7 @@ let with_block_args callee_pdesc pname_with_block_args block_args =
Logging.die InternalError
"specialize_with_block_args ahould only be called with defined procedures, but we cannot \
find the captured file of procname %a"
Typ.Procname.pp pname
Procname.pp pname
in
let resolved_attributes =
{ callee_attributes with

@ -10,13 +10,13 @@ open! IStd
exception UnmatchedParameters
val with_formals_types :
?has_clang_model:bool -> Procdesc.t -> Typ.Procname.t -> (Exp.t * Typ.t) list -> Procdesc.t
?has_clang_model:bool -> Procdesc.t -> Procname.t -> (Exp.t * Typ.t) list -> Procdesc.t
(** Creates a copy of a procedure description and a list of type substitutions of the form (name,
typ) where name is a parameter. The resulting procdesc is isomorphic but all the type of the
parameters are replaced in the instructions according to the list. The virtual calls are also
replaced to match the parameter types *)
val with_block_args : Procdesc.t -> Typ.Procname.t -> Exp.closure option list -> Procdesc.t
val with_block_args : Procdesc.t -> Procname.t -> Exp.closure option list -> Procdesc.t
(** Creates a copy of a procedure description given a list of possible closures that are passed as
arguments to the method. The resulting procdesc is isomorphic but

@ -17,9 +17,8 @@ type t =
{ fields: fields (** non-static fields *)
; statics: fields (** static fields *)
; supers: Typ.Name.t list (** superclasses *)
; methods: Typ.Procname.t list (** methods defined *)
; exported_objc_methods: Typ.Procname.t list
(** methods in ObjC interface, subset of [methods] *)
; methods: Procname.t list (** methods defined *)
; exported_objc_methods: Procname.t list (** methods in ObjC interface, subset of [methods] *)
; annots: Annot.Item.t (** annotations *)
; dummy: bool (** dummy struct for class including static method *) }
@ -49,9 +48,9 @@ let pp pe name f {fields; supers; methods; exported_objc_methods; annots} =
fields
(Pp.seq (fun f n -> F.fprintf f "@\n\t\t%a" Typ.Name.pp n))
supers
(Pp.seq (fun f m -> F.fprintf f "@\n\t\t%a" Typ.Procname.pp m))
(Pp.seq (fun f m -> F.fprintf f "@\n\t\t%a" Procname.pp m))
methods
(Pp.seq (fun f m -> F.fprintf f "@\n\t\t%a" Typ.Procname.pp m))
(Pp.seq (fun f m -> F.fprintf f "@\n\t\t%a" Procname.pp m))
exported_objc_methods Annot.Item.pp annots
else Typ.Name.pp f name

@ -18,9 +18,8 @@ type t = private
{ fields: fields (** non-static fields *)
; statics: fields (** static fields *)
; supers: Typ.Name.t list (** supers *)
; methods: Typ.Procname.t list (** methods defined *)
; exported_objc_methods: Typ.Procname.t list
(** methods in ObjC interface, subset of [methods] *)
; methods: Procname.t list (** methods defined *)
; exported_objc_methods: Procname.t list (** methods in ObjC interface, subset of [methods] *)
; annots: Annot.Item.t (** annotations *)
; dummy: bool (** dummy struct for class including static method *) }
@ -35,8 +34,8 @@ val internal_mk_struct :
?default:t
-> ?fields:fields
-> ?statics:fields
-> ?methods:Typ.Procname.t list
-> ?exported_objc_methods:Typ.Procname.t list
-> ?methods:Procname.t list
-> ?exported_objc_methods:Procname.t list
-> ?supers:Typ.Name.t list
-> ?annots:Annot.Item.t
-> ?dummy:bool

@ -37,8 +37,8 @@ val mk_struct :
-> ?default:Struct.t
-> ?fields:Struct.fields
-> ?statics:Struct.fields
-> ?methods:Typ.Procname.t list
-> ?exported_objc_methods:Typ.Procname.t list
-> ?methods:Procname.t list
-> ?exported_objc_methods:Procname.t list
-> ?supers:Typ.Name.t list
-> ?annots:Annot.Item.t
-> ?dummy:bool

@ -265,8 +265,24 @@ let void = mk Tvoid
let void_star = mk (Tptr (mk Tvoid, Pk_pointer))
let java_byte = mk (Tint IShort)
let java_short = java_byte
let boolean = mk (Tint IBool)
let char = mk (Tint IChar)
let float = mk (Tfloat FFloat)
let double = mk (Tfloat FDouble)
let int = mk (Tint IInt)
let uint = mk (Tint IUInt)
let long = mk (Tint ILong)
let get_ikind_opt {desc} = match desc with Tint ikind -> Some ikind | _ -> None
(* TODO: size_t should be implementation-dependent. *)
@ -431,7 +447,7 @@ module Name = struct
(** e.g. {type_name="int"; package=None} for primitive types
* or {type_name="PrintWriter"; package=Some "java.io"} for objects.
*)
type t = {package: string option; type_name: string}
type t = {package: string option; type_name: string} [@@deriving compare]
let make ?package type_name = {type_name; package}
@ -454,6 +470,12 @@ module Name = struct
let java_lang_string = make ~package:"java.lang" "String"
let void = make "void"
let pp_type_verbosity ~verbose fmt = function
| {package= Some package; type_name} when verbose ->
F.fprintf fmt "%s.%s" package type_name
| {type_name} ->
F.pp_print_string fmt type_name
end
let from_string name_str = JavaClass (Mangled.from_string name_str)
@ -597,826 +619,3 @@ let has_block_prefix s =
type typ = t
module Procname = struct
(** Level of verbosity of some to_string functions. *)
type detail_level = Verbose | Non_verbose | Simple [@@deriving compare]
let equal_detail_level = [%compare.equal: detail_level]
let is_verbose v = match v with Verbose -> true | _ -> false
module Java = struct
type kind =
| Non_Static
(** in Java, procedures called with invokevirtual, invokespecial, and invokeinterface *)
| Static (** in Java, procedures called with invokestatic *)
[@@deriving compare]
(* TODO: use Mangled.t here *)
type java_type = Name.Java.Split.t = {package: string option; type_name: string}
[@@deriving compare]
let java_void = {package= None; type_name= "void"}
(** Type of java procedure names. *)
type t =
{ method_name: string
; parameters: java_type list
; class_name: Name.t
; return_type: java_type option (* option because constructors have no return type *)
; kind: kind }
[@@deriving compare]
let make class_name return_type method_name parameters kind =
{class_name; return_type; method_name; parameters; kind}
(** A type is a pair (package, type_name) that is translated in a string package.type_name *)
let pp_type_verbosity verbosity fmt p =
match p with
| {package= Some package; type_name} when is_verbose verbosity ->
F.fprintf fmt "%s.%s" package type_name
| {type_name} ->
F.pp_print_string fmt type_name
(** Given a list of types, it creates a unique string of types separated by commas *)
let rec pp_param_list verbosity fmt inputList =
match inputList with
| [] ->
()
| [head] ->
pp_type_verbosity verbosity fmt head
| head :: rest ->
pp_type_verbosity verbosity fmt head ;
F.pp_print_string fmt "," ;
pp_param_list verbosity fmt rest
let java_type_of_name class_name = Name.Java.Split.of_string (Name.name class_name)
(** It is the same as java_type_to_string_verbosity, but Java return types are optional because
of constructors without type *)
let pp_return_type verbosity fmt j =
match j.return_type with None -> () | Some typ -> pp_type_verbosity verbosity fmt typ
let get_class_name j = Name.name j.class_name
let get_class_type_name j = j.class_name
let get_simple_class_name j = Name.Java.Split.(j |> get_class_name |> of_string |> type_name)
let get_package j = Name.Java.Split.(j |> get_class_name |> of_string |> package)
let get_method j = j.method_name
let replace_method_name method_name j = {j with method_name}
let replace_parameters parameters j = {j with parameters}
let replace_return_type ret_type j = {j with return_type= Some ret_type}
let get_parameters j = j.parameters
(** Prints a string of a java procname with the given level of verbosity *)
let pp ?(withclass = false) verbosity fmt j =
match verbosity with
| Verbose | Non_verbose ->
(* if verbose, then package.class.method(params): rtype,
else rtype package.class.method(params)
verbose is used for example to create unique filenames, non_verbose to create reports *)
let pp_class_name verbosity fmt j =
pp_type_verbosity verbosity fmt (Name.Java.split_typename j.class_name)
in
let separator =
match (j.return_type, verbosity) with
| None, _ ->
""
| Some _, Verbose ->
":"
| _ ->
" "
in
if not (equal_detail_level verbosity Verbose) then
F.fprintf fmt "%a%s" (pp_return_type verbosity) j separator ;
F.fprintf fmt "%a.%s(%a)" (pp_class_name verbosity) j j.method_name
(pp_param_list verbosity) j.parameters ;
if equal_detail_level verbosity Verbose then
F.fprintf fmt "%s%a" separator (pp_return_type verbosity) j
| Simple ->
(* methodname(...) or without ... if there are no parameters *)
let pp_class_prefix ~withclass verbosity fmt j =
if withclass then
F.fprintf fmt "%a." (pp_type_verbosity verbosity)
(Name.Java.split_typename j.class_name)
in
let params = match j.parameters with [] -> "" | _ -> "..." in
let pp_method_name ~withclass verbosity fmt j =
if String.equal j.method_name "<init>" then
F.pp_print_string fmt (get_simple_class_name j)
else F.fprintf fmt "%a%s" (pp_class_prefix ~withclass verbosity) j j.method_name
in
F.fprintf fmt "%a(%s)" (pp_method_name ~withclass verbosity) j params
let get_return_typ pname_java =
let rec java_from_string = function
| "" | "void" ->
mk Tvoid
| "int" ->
mk (Tint IInt)
| "byte" ->
mk (Tint IShort)
| "short" ->
mk (Tint IShort)
| "boolean" ->
mk (Tint IBool)
| "char" ->
mk (Tint IChar)
| "long" ->
mk (Tint ILong)
| "float" ->
mk (Tfloat FFloat)
| "double" ->
mk (Tfloat FDouble)
| typ_str when String.contains typ_str '[' ->
let stripped_typ = String.sub typ_str ~pos:0 ~len:(String.length typ_str - 2) in
mk (Tptr (mk_array (java_from_string stripped_typ), Pk_pointer))
| typ_str ->
mk (Tstruct (Name.Java.from_string typ_str))
in
let typ = java_from_string (F.asprintf "%a" (pp_return_type Verbose) pname_java) in
match typ.desc with Tstruct _ -> mk (Tptr (typ, Pk_pointer)) | _ -> typ
let is_close {method_name} = String.equal method_name "close"
let constructor_method_name = "<init>"
let class_initializer_method_name = "<clinit>"
let is_class_initializer {method_name} = String.equal method_name class_initializer_method_name
let get_class_initializer class_name =
{ method_name= class_initializer_method_name
; parameters= []
; class_name
; return_type= Some java_void
; kind= Static }
let is_constructor {method_name} = String.equal method_name constructor_method_name
let is_anonymous_inner_class_constructor {class_name} =
Name.Java.is_anonymous_inner_class_name class_name
let is_static {kind} = match kind with Static -> true | _ -> false
let is_lambda {method_name} = String.is_prefix ~prefix:"lambda$" method_name
let is_generated {method_name} = String.is_prefix ~prefix:"$" method_name
let is_access_method {method_name} =
match String.rsplit2 method_name ~on:'$' with
| Some ("access", s) ->
let is_int =
try
ignore (int_of_string s) ;
true
with Failure _ -> false
in
is_int
| _ ->
false
let is_autogen_method {method_name} = String.contains method_name '$'
(** Check if the proc name has the type of a java vararg.
Note: currently only checks that the last argument has type Object[]. *)
let is_vararg {parameters} =
match List.last parameters with Some {type_name= "java.lang.Object[]"} -> true | _ -> false
let is_external java_pname =
let package = get_package java_pname in
Option.exists ~f:Config.java_package_is_external package
end
module Parameter = struct
(** Type for parameters in clang procnames, [Some name] means the parameter is of type pointer to struct, with [name]
being the name of the struct, [None] means the parameter is of some other type. *)
type clang_parameter = Name.t option [@@deriving compare]
(** Type for parameters in procnames, for java and clang. *)
type t = JavaParameter of Java.java_type | ClangParameter of clang_parameter
[@@deriving compare]
let of_typ typ =
match typ.T.desc with T.Tptr ({desc= Tstruct name}, Pk_pointer) -> Some name | _ -> None
let pp_parameters fmt parameters =
if List.exists ~f:Option.is_some parameters then
(* the tests rely on the fact that we discard non-pointer-to-struct types for some reason,
hence the slight re-implementation of [Pp.seq] to avoid building the list of [Some] items
explicitly *)
let rec pp_parameters_aux fmt = function
| [] ->
()
| [Some param] ->
F.pp_print_string fmt (Name.to_string param)
| None :: parameters ->
pp_parameters_aux fmt parameters
| (Some _ as param_some) :: None :: parameters ->
pp_parameters_aux fmt (param_some :: parameters)
| Some param :: (Some _ :: _ as parameters) ->
F.fprintf fmt "%s," (Name.to_string param) ;
pp_parameters_aux fmt parameters
in
F.fprintf fmt "(%a)" pp_parameters_aux parameters
let clang_param_of_name class_name : clang_parameter = Some class_name
end
module ObjC_Cpp = struct
type kind =
| CPPMethod of {mangled: string option}
| CPPConstructor of {mangled: string option; is_constexpr: bool}
| CPPDestructor of {mangled: string option}
| ObjCClassMethod
| ObjCInstanceMethod
| ObjCInternalMethod
[@@deriving compare]
type t =
{ class_name: Name.t
; kind: kind
; method_name: string
; parameters: Parameter.clang_parameter list
; template_args: template_spec_info }
[@@deriving compare]
let make class_name method_name kind template_args parameters =
{class_name; method_name; kind; template_args; parameters}
let get_class_name objc_cpp = Name.name objc_cpp.class_name
let get_class_type_name objc_cpp = objc_cpp.class_name
let get_class_qualifiers objc_cpp = Name.qual_name objc_cpp.class_name
let objc_method_kind_of_bool is_instance =
if is_instance then ObjCInstanceMethod else ObjCClassMethod
let is_objc_constructor method_name =
String.equal method_name "new" || String.is_prefix ~prefix:"init" method_name
let is_objc_kind = function
| ObjCClassMethod | ObjCInstanceMethod | ObjCInternalMethod ->
true
| _ ->
false
let is_objc_method {kind} = is_objc_kind kind
let is_objc_dealloc method_name = String.equal method_name "dealloc"
let is_destructor = function
| {kind= CPPDestructor _} ->
true
| name ->
is_objc_dealloc name.method_name
let is_inner_destructor ({method_name} as pname) =
is_destructor pname
&& String.is_prefix ~prefix:Config.clang_inner_destructor_prefix method_name
let is_constexpr = function {kind= CPPConstructor {is_constexpr= true}} -> true | _ -> false
let is_cpp_lambda {method_name} = String.is_substring ~substring:"operator()" method_name
let pp_verbose_kind fmt = function
| CPPMethod {mangled} | CPPDestructor {mangled} ->
F.fprintf fmt "(%s)" (Option.value ~default:"" mangled)
| CPPConstructor {mangled; is_constexpr} ->
F.fprintf fmt "{%s%s}"
(Option.value ~default:"" mangled)
(if is_constexpr then "|constexpr" else "")
| ObjCClassMethod ->
F.pp_print_string fmt "class"
| ObjCInstanceMethod ->
F.pp_print_string fmt "instance"
| ObjCInternalMethod ->
F.pp_print_string fmt "internal"
let pp verbosity fmt osig =
match verbosity with
| Simple ->
F.pp_print_string fmt osig.method_name
| Non_verbose ->
F.fprintf fmt "%s::%s" (Name.name osig.class_name) osig.method_name
| Verbose ->
F.fprintf fmt "%s::%s%a%a" (Name.name osig.class_name) osig.method_name
Parameter.pp_parameters osig.parameters pp_verbose_kind osig.kind
let get_parameters osig = osig.parameters
let replace_parameters new_parameters osig = {osig with parameters= new_parameters}
end
module C = struct
(** Type of c procedure names. *)
type t =
{ name: QualifiedCppName.t
; mangled: string option
; parameters: Parameter.clang_parameter list
; template_args: template_spec_info }
[@@deriving compare]
let c name mangled parameters template_args =
{name; mangled= Some mangled; parameters; template_args}
let from_string name =
{ name= QualifiedCppName.of_qual_string name
; mangled= None
; parameters= []
; template_args= NoTemplate }
let pp verbosity fmt {name; mangled; parameters} =
let plain = QualifiedCppName.to_qual_string name in
match verbosity with
| Simple ->
F.fprintf fmt "%s()" plain
| Non_verbose ->
F.pp_print_string fmt plain
| Verbose ->
let pp_mangled fmt = function None -> () | Some s -> F.fprintf fmt "{%s}" s in
F.fprintf fmt "%s%a%a" plain Parameter.pp_parameters parameters pp_mangled mangled
let get_parameters c = c.parameters
let replace_parameters new_parameters c = {c with parameters= new_parameters}
end
module Block = struct
(** Type of Objective C block names. *)
type block_name = string [@@deriving compare]
type t = {name: block_name; parameters: Parameter.clang_parameter list} [@@deriving compare]
let make name parameters = {name; parameters}
let pp verbosity fmt bsig =
match verbosity with
| Simple ->
F.pp_print_string fmt "block"
| Non_verbose ->
F.pp_print_string fmt bsig.name
| Verbose ->
F.fprintf fmt "%s%a" bsig.name Parameter.pp_parameters bsig.parameters
let get_parameters block = block.parameters
let replace_parameters new_parameters block = {block with parameters= new_parameters}
end
(** Type of procedure names. *)
type t =
| Java of Java.t
| C of C.t
| Linters_dummy_method
| Block of Block.t
| ObjC_Cpp of ObjC_Cpp.t
| WithBlockParameters of t * Block.block_name list
[@@deriving compare]
let equal = [%compare.equal: t]
(** hash function for procname *)
let hash = Hashtbl.hash
let with_block_parameters base blocks = WithBlockParameters (base, blocks)
let is_java = function Java _ -> true | _ -> false
(* TODO: deprecate this unfortunately named function and use is_clang instead *)
let is_c_method = function ObjC_Cpp _ -> true | _ -> false
let is_c_function = function C _ -> true | _ -> false
let is_clang = function
| ObjC_Cpp name ->
ObjC_Cpp.is_objc_method name
| name ->
is_c_function name
let is_java_lift f = function Java java_pname -> f java_pname | _ -> false
let is_java_access_method = is_java_lift Java.is_access_method
let is_java_class_initializer = is_java_lift Java.is_class_initializer
let is_objc_method procname =
match procname with ObjC_Cpp name -> ObjC_Cpp.is_objc_method name | _ -> false
let block_name_of_procname procname =
match procname with
| Block block ->
block.name
| _ ->
Logging.die InternalError "Only to be called with Objective-C block names"
let empty_block = Block {name= ""; parameters= []}
(** Replace the class name component of a procedure name.
In case of Java, replace package and class name. *)
let rec replace_class t (new_class : Name.t) =
match t with
| Java j ->
Java {j with class_name= new_class}
| ObjC_Cpp osig ->
ObjC_Cpp {osig with class_name= new_class}
| WithBlockParameters (base, blocks) ->
WithBlockParameters (replace_class base new_class, blocks)
| C _ | Block _ | Linters_dummy_method ->
t
let get_class_type_name = function
| Java java_pname ->
Some (Java.get_class_type_name java_pname)
| ObjC_Cpp objc_pname ->
Some (ObjC_Cpp.get_class_type_name objc_pname)
| _ ->
None
let get_class_name = function
| Java java_pname ->
Some (Java.get_class_name java_pname)
| ObjC_Cpp objc_pname ->
Some (ObjC_Cpp.get_class_name objc_pname)
| _ ->
None
let is_method_in_objc_protocol t =
match t with ObjC_Cpp osig -> Name.is_objc_protocol osig.class_name | _ -> false
let rec objc_cpp_replace_method_name t (new_method_name : string) =
match t with
| ObjC_Cpp osig ->
ObjC_Cpp {osig with method_name= new_method_name}
| WithBlockParameters (base, blocks) ->
WithBlockParameters (objc_cpp_replace_method_name base new_method_name, blocks)
| C _ | Block _ | Linters_dummy_method | Java _ ->
t
(** Return the method/function of a procname. *)
let rec get_method = function
| ObjC_Cpp name ->
name.method_name
| WithBlockParameters (base, _) ->
get_method base
| C {name} ->
QualifiedCppName.to_qual_string name
| Block {name} ->
name
| Java j ->
j.method_name
| Linters_dummy_method ->
"Linters_dummy_method"
(** Return whether the procname is a block procname. *)
let is_objc_block = function Block _ -> true | _ -> false
(** Return the language of the procedure. *)
let get_language = function
| ObjC_Cpp _ ->
Language.Clang
| C _ ->
Language.Clang
| Block _ ->
Language.Clang
| Linters_dummy_method ->
Language.Clang
| WithBlockParameters _ ->
Language.Clang
| Java _ ->
Language.Java
(** [is_constructor pname] returns true if [pname] is a constructor *)
let is_constructor = function
| Java js ->
String.equal js.method_name Java.constructor_method_name
| ObjC_Cpp {kind= CPPConstructor _} ->
true
| ObjC_Cpp {kind; method_name} when ObjC_Cpp.is_objc_kind kind ->
ObjC_Cpp.is_objc_constructor method_name
| _ ->
false
(** [is_infer_undefined pn] returns true if [pn] is a special Infer undefined proc *)
let is_infer_undefined pn =
match pn with
| Java j ->
let regexp = Str.regexp_string "com.facebook.infer.builtins.InferUndefined" in
Str.string_match regexp (Java.get_class_name j) 0
| _ ->
(* TODO: add cases for obj-c, c, c++ *)
false
let get_global_name_of_initializer = function
| C {name}
when String.is_prefix ~prefix:Config.clang_initializer_prefix
(QualifiedCppName.to_qual_string name) ->
let name_str = QualifiedCppName.to_qual_string name in
let prefix_len = String.length Config.clang_initializer_prefix in
Some (String.sub name_str ~pos:prefix_len ~len:(String.length name_str - prefix_len))
| _ ->
None
(** Very verbose representation of an existing Procname.t *)
let rec pp_unique_id fmt = function
| Java j ->
Java.pp Verbose fmt j
| C osig ->
C.pp Verbose fmt osig
| ObjC_Cpp osig ->
ObjC_Cpp.pp Verbose fmt osig
| Block bsig ->
Block.pp Verbose fmt bsig
| WithBlockParameters (base, []) ->
pp_unique_id fmt base
| WithBlockParameters (base, (_ :: _ as blocks)) ->
pp_unique_id fmt base ;
F.pp_print_string fmt "_" ;
Pp.seq ~sep:"_" F.pp_print_string fmt blocks
| Linters_dummy_method ->
F.pp_print_string fmt "Linters_dummy_method"
let to_unique_id proc_name = F.asprintf "%a" pp_unique_id proc_name
(** Convert a proc name to a string for the user to see *)
let rec pp fmt = function
| Java j ->
Java.pp Non_verbose fmt j
| C osig ->
C.pp Non_verbose fmt osig
| ObjC_Cpp osig ->
ObjC_Cpp.pp Non_verbose fmt osig
| Block bsig ->
Block.pp Non_verbose fmt bsig
| WithBlockParameters (base, []) ->
pp fmt base
| WithBlockParameters (base, (_ :: _ as blocks)) ->
pp fmt base ;
F.pp_print_string fmt "_" ;
Pp.seq ~sep:"_" F.pp_print_string fmt blocks
| Linters_dummy_method ->
pp_unique_id fmt Linters_dummy_method
let to_string proc_name = F.asprintf "%a" pp proc_name
(** Convenient representation of a procname for external tools (e.g. eclipse plugin) *)
let rec pp_simplified_string ?(withclass = false) fmt = function
| Java j ->
Java.pp ~withclass Simple fmt j
| C osig ->
C.pp Simple fmt osig
| ObjC_Cpp osig ->
ObjC_Cpp.pp Simple fmt osig
| Block bsig ->
Block.pp Simple fmt bsig
| WithBlockParameters (base, _) ->
pp_simplified_string fmt base
| Linters_dummy_method ->
pp_unique_id fmt Linters_dummy_method
let to_simplified_string ?withclass proc_name =
F.asprintf "%a" (pp_simplified_string ?withclass) proc_name
let from_string_c_fun func = C (C.from_string func)
let java_inner_class_prefix_regex = Str.regexp "\\$[0-9]+"
let hashable_name proc_name =
match proc_name with
| Java pname -> (
(* Strip autogenerated anonymous inner class numbers in order to keep the bug hash
invariant when introducing new anonymous classes *)
let name = F.asprintf "%a" (Java.pp ~withclass:true Simple) pname in
match Str.search_forward java_inner_class_prefix_regex name 0 with
| _ ->
Str.global_replace java_inner_class_prefix_regex "$_" name
| exception Caml.Not_found ->
name )
| ObjC_Cpp m when ObjC_Cpp.is_objc_method m ->
(* In Objective C, the list of parameters is part of the method name. To prevent the bug
hash to change when a parameter is introduced or removed, only the part of the name
before the first colon is used for the bug hash *)
let name = F.asprintf "%a" (pp_simplified_string ~withclass:true) proc_name in
List.hd_exn (String.split_on_chars name ~on:[':'])
| _ ->
(* Other cases for C and C++ method names *)
F.asprintf "%a" (pp_simplified_string ~withclass:true) proc_name
let rec get_parameters procname =
let clang_param_to_param clang_params =
List.map ~f:(fun par -> Parameter.ClangParameter par) clang_params
in
match procname with
| Java j ->
List.map ~f:(fun par -> Parameter.JavaParameter par) (Java.get_parameters j)
| C osig ->
clang_param_to_param (C.get_parameters osig)
| ObjC_Cpp osig ->
clang_param_to_param (ObjC_Cpp.get_parameters osig)
| Block bsig ->
clang_param_to_param (Block.get_parameters bsig)
| WithBlockParameters (base, _) ->
get_parameters base
| Linters_dummy_method ->
[]
let rec replace_parameters new_parameters procname =
let params_to_java_params params =
List.map
~f:(fun param ->
match param with
| Parameter.JavaParameter par ->
par
| _ ->
Logging.(die InternalError)
"Expected Java parameters in Java procname, but got Clang parameters" params )
params
in
let params_to_clang_params params =
List.map
~f:(fun param ->
match param with
| Parameter.ClangParameter par ->
par
| _ ->
Logging.(die InternalError)
"Expected Clang parameters in Clang procname, but got Java parameters" params )
params
in
match procname with
| Java j ->
Java (Java.replace_parameters (params_to_java_params new_parameters) j)
| C osig ->
C (C.replace_parameters (params_to_clang_params new_parameters) osig)
| ObjC_Cpp osig ->
ObjC_Cpp (ObjC_Cpp.replace_parameters (params_to_clang_params new_parameters) osig)
| Block bsig ->
Block (Block.replace_parameters (params_to_clang_params new_parameters) bsig)
| WithBlockParameters (base, blocks) ->
WithBlockParameters (replace_parameters new_parameters base, blocks)
| Linters_dummy_method ->
procname
let parameter_of_name procname class_name =
match procname with
| Java _ ->
Parameter.JavaParameter (Java.java_type_of_name class_name)
| _ ->
Parameter.ClangParameter (Parameter.clang_param_of_name class_name)
let describe f pn =
let name = hashable_name pn in
match String.lsplit2 ~on:'<' name with
| Some (name_without_template, _template_part) ->
F.pp_print_string f name_without_template
| None ->
F.pp_print_string f name
module Hashable = struct
type nonrec t = t
let equal = equal
let hash = hash
end
module Hash = Hashtbl.Make (Hashable)
module Map = PrettyPrintable.MakePPMap (struct
type nonrec t = t
let compare = compare
let pp = pp
end)
module Set = PrettyPrintable.MakePPSet (struct
type nonrec t = t
let compare = compare
let pp = pp
end)
let get_qualifiers pname =
match pname with
| C {name} ->
name
| ObjC_Cpp objc_cpp ->
ObjC_Cpp.get_class_qualifiers objc_cpp
|> QualifiedCppName.append_qualifier ~qual:objc_cpp.method_name
| _ ->
QualifiedCppName.empty
(** Convert a proc name to a filename *)
let to_filename ?crc_only pname =
(* filenames for clang procs are REVERSED qualifiers with '#' as separator *)
let pp_rev_qualified fmt pname =
let rev_qualifiers = get_qualifiers pname |> QualifiedCppName.to_rev_list in
Pp.seq ~sep:"#" F.pp_print_string fmt rev_qualifiers
in
let proc_id =
match pname with
| C {parameters; mangled} ->
let pp_mangled fmt = function
| None ->
()
| Some mangled ->
F.fprintf fmt "#%s" mangled
in
F.asprintf "%a%a%a" pp_rev_qualified pname Parameter.pp_parameters parameters pp_mangled
mangled
| ObjC_Cpp objc_cpp ->
F.asprintf "%a%a#%a" pp_rev_qualified pname Parameter.pp_parameters objc_cpp.parameters
ObjC_Cpp.pp_verbose_kind objc_cpp.kind
| _ ->
F.asprintf "%a" pp_unique_id pname
in
Escape.escape_filename @@ DB.append_crc_cutoff ?crc_only proc_id
module SQLite = struct
module T = struct
type nonrec t = t
let compare = compare
let hash = hash
let sexp_of_t p = Sexp.Atom (F.asprintf "%a" pp p)
end
module Serializer = SqliteUtils.MarshalledDataForComparison (T)
let pname_to_key = Base.Hashtbl.create (module T)
let serialize pname =
let default () = Serializer.serialize pname in
Base.Hashtbl.find_or_add pname_to_key pname ~default
let deserialize = Serializer.deserialize
let clear_cache () = Base.Hashtbl.clear pname_to_key
end
module SQLiteList = SqliteUtils.MarshalledDataNOTForComparison (struct
type nonrec t = t list
end)
end

@ -137,9 +137,26 @@ val mk_array : ?default:t -> ?quals:type_quals -> ?length:IntLit.t -> ?stride:In
val void : t
(** void type *)
val java_byte : t
val java_short : t
val boolean : t
val char : t
val int : t
(** signed int type *)
val uint : t
(** unsigned int type *)
val long : t
val float : t
val double : t
val void_star : t
(** void* type *)
@ -186,6 +203,8 @@ module Name : sig
val get_template_spec_info : t -> template_spec_info option
val is_objc_protocol : t -> bool
module C : sig
val from_string : string -> t
@ -196,10 +215,12 @@ module Name : sig
module Java : sig
module Split : sig
type t
type t [@@deriving compare]
val make : ?package:string -> string -> t
val of_string : string -> t
val java_lang_object : t
val java_lang_string : t
@ -209,6 +230,8 @@ module Name : sig
val package : t -> string option
val type_name : t -> string
val pp_type_verbosity : verbose:bool -> F.formatter -> t -> unit
end
val from_string : string -> t
@ -230,6 +253,10 @@ module Name : sig
(** Given an inner classname like C$Inner1$Inner2, return Some C$Inner1. If the class is not an
inner class, return None *)
val is_anonymous_inner_class_name : t -> bool
val split_typename : t -> Split.t
val java_lang_object : t
val java_io_serializable : t
@ -326,311 +353,3 @@ val has_block_prefix : string -> bool
val unsome : string -> t option -> t
type typ = t
module Procname : sig
(** Module for Procedure Names. *)
(** Type of java procedure names. *)
module Java : sig
type kind =
| Non_Static
(** in Java, procedures called with invokevirtual, invokespecial, and invokeinterface *)
| Static (** in Java, procedures called with invokestatic *)
type t [@@deriving compare]
type java_type = Name.Java.Split.t
val constructor_method_name : string
val class_initializer_method_name : string
val compare_java_type : java_type -> java_type -> int
val make : Name.t -> java_type option -> string -> java_type list -> kind -> t
(** Create a Java procedure name from its
class_name method_name args_type_name return_type_name method_kind. *)
val replace_method_name : string -> t -> t
(** Replace the method name of an existing java procname. *)
val replace_parameters : java_type list -> t -> t
(** Replace the parameters of a java procname. *)
val replace_return_type : java_type -> t -> t
(** Replace the method of a java procname. *)
val get_class_name : t -> string
(** Return the fully qualified class name of a java procedure name (package + class name) *)
val get_class_type_name : t -> Name.t
(** Return the class name as a typename of a java procedure name. *)
val get_simple_class_name : t -> string
(** Return the simple class name of a java procedure name (i.e. name without the package info). *)
val get_package : t -> string option
(** Return the package name of a java procedure name. *)
val get_method : t -> string
(** Return the method name of a java procedure name. *)
val get_parameters : t -> java_type list
(** Return the parameters of a java procedure name. *)
val get_return_typ : t -> typ
(** Return the return type of [pname_java]. return Tvoid if there's no return type *)
val is_constructor : t -> bool
(** Whether the method is constructor *)
val is_access_method : t -> bool
(** Check if the procedure name is an acess method (e.g. access$100 used to
access private members from a nested class. *)
val is_autogen_method : t -> bool
(** Check if the procedure name is of an auto-generated method containing '$'. *)
val is_anonymous_inner_class_constructor : t -> bool
(** Check if the procedure name is an anonymous inner class constructor. *)
val is_close : t -> bool
(** Check if the method name is "close". *)
val is_static : t -> bool
(** Check if the java procedure is static. *)
val is_vararg : t -> bool
(** Check if the proc name has the type of a java vararg.
Note: currently only checks that the last argument has type Object[]. *)
val is_lambda : t -> bool
(** Check if the proc name comes from a lambda expression *)
val is_generated : t -> bool
(** Check if the proc name comes from generated code *)
val is_class_initializer : t -> bool
(** Check if this is a class initializer. *)
val get_class_initializer : Name.t -> t
(** Given a java class, generate the procname of its static initializer. *)
val is_external : t -> bool
(** Check if the method belongs to one of the specified external packages *)
end
module Parameter : sig
(** Type for parameters in clang procnames, [Some name] means the parameter is of type pointer to struct, with [name]
being the name of the struct, [None] means the parameter is of some other type. *)
type clang_parameter = Name.t option [@@deriving compare]
(** Type for parameters in procnames, for java and clang. *)
type t = JavaParameter of Java.java_type | ClangParameter of clang_parameter
[@@deriving compare]
val of_typ : typ -> clang_parameter
end
module ObjC_Cpp : sig
type kind =
| CPPMethod of {mangled: string option}
| CPPConstructor of {mangled: string option; is_constexpr: bool}
| CPPDestructor of {mangled: string option}
| ObjCClassMethod
| ObjCInstanceMethod
| ObjCInternalMethod
[@@deriving compare]
(** Type of Objective C and C++ procedure names: method signatures. *)
type t =
{ class_name: Name.t
; kind: kind
; method_name: string
; parameters: Parameter.clang_parameter list
; template_args: template_spec_info }
[@@deriving compare]
val make : Name.t -> string -> kind -> template_spec_info -> Parameter.clang_parameter list -> t
(** Create an objc procedure name from a class_name and method_name. *)
val get_class_name : t -> string
val get_class_type_name : t -> Name.t [@@warning "-32"]
val get_class_qualifiers : t -> QualifiedCppName.t
val objc_method_kind_of_bool : bool -> kind
(** Create ObjC method type from a bool is_instance. *)
val is_objc_constructor : string -> bool
(** Check if this is a constructor method in Objective-C. *)
val is_objc_dealloc : string -> bool
(** Check if this is a dealloc method in Objective-C. *)
val is_destructor : t -> bool
(** Check if this is a dealloc method. *)
val is_inner_destructor : t -> bool
(** Check if this is a frontend-generated "inner" destructor (see D5834555/D7189239) *)
val is_constexpr : t -> bool
(** Check if this is a constexpr function. *)
val is_cpp_lambda : t -> bool
(** Return whether the procname is a cpp lambda. *)
end
module C : sig
(** Type of c procedure names. *)
type t = private
{ name: QualifiedCppName.t
; mangled: string option
; parameters: Parameter.clang_parameter list
; template_args: template_spec_info }
val c :
QualifiedCppName.t -> string -> Parameter.clang_parameter list -> template_spec_info -> t
(** Create a C procedure name from plain and mangled name. *)
end
module Block : sig
(** Type of Objective C block names. *)
type block_name = string
type t = {name: block_name; parameters: Parameter.clang_parameter list} [@@deriving compare]
val make : block_name -> Parameter.clang_parameter list -> t
end
(** Type of procedure names.
WithBlockParameters is used for creating an instantiation of a method that contains block parameters
and it's called with concrete blocks. For example:
foo(Block block) {block();}
bar() {foo(my_block)} is executed as foo_my_block() {my_block(); }
where foo_my_block is created with WithBlockParameters (foo, [my_block]) *)
type t =
| Java of Java.t
| C of C.t
| Linters_dummy_method
| Block of Block.t
| ObjC_Cpp of ObjC_Cpp.t
| WithBlockParameters of t * Block.block_name list
[@@deriving compare]
val block_name_of_procname : t -> Block.block_name
val equal : t -> t -> bool
val get_class_type_name : t -> Name.t option
val get_class_name : t -> string option
val get_parameters : t -> Parameter.t list
val replace_parameters : Parameter.t list -> t -> t
val parameter_of_name : t -> Name.t -> Parameter.t
val is_java_access_method : t -> bool
val is_java_class_initializer : t -> bool
val is_objc_method : t -> bool
module Hash : Caml.Hashtbl.S with type key = t
(** Hash tables with proc names as keys. *)
module Map : PrettyPrintable.PPMap with type key = t
(** Maps from proc names. *)
module Set : PrettyPrintable.PPSet with type elt = t
(** Sets of proc names. *)
module SQLite : sig
val serialize : t -> Sqlite3.Data.t
val deserialize : Sqlite3.Data.t -> t
val clear_cache : unit -> unit
end
module SQLiteList : SqliteUtils.Data with type t = t list
val empty_block : t
(** Empty block name. *)
val get_language : t -> Language.t
(** Return the language of the procedure. *)
val get_method : t -> string
(** Return the method/function of a procname. *)
val is_objc_block : t -> bool
(** Return whether the procname is a block procname. *)
val is_c_method : t -> bool
(** Return true this is an Objective-C/C++ method name. *)
val is_clang : t -> bool
(** Return true if this is a C, C++, or Objective-C procedure name *)
val is_constructor : t -> bool
(** Check if this is a constructor. *)
val is_java : t -> bool
(** Check if this is a Java procedure name. *)
val with_block_parameters : t -> Block.block_name list -> t
(** Create a procedure name instantiated with block parameters from a base procedure name
and a list of block procedure names (the arguments). *)
val objc_cpp_replace_method_name : t -> string -> t
val is_infer_undefined : t -> bool
(** Check if this is a special Infer undefined procedure. *)
val get_global_name_of_initializer : t -> string option
(** Return the name of the global for which this procedure is the initializer if this is an
initializer, None otherwise. *)
val pp : Format.formatter -> t -> unit
(** Pretty print a proc name for the user to see. *)
val to_string : t -> string
(** Convert a proc name into a string for the user to see. *)
val describe : Format.formatter -> t -> unit
(** to use in user messages *)
val replace_class : t -> Name.t -> t
(** Replace the class name component of a procedure name.
In case of Java, replace package and class name. *)
val is_method_in_objc_protocol : t -> bool
val pp_simplified_string : ?withclass:bool -> F.formatter -> t -> unit
(** Pretty print a proc name as an easy string for the user to see in an IDE. *)
val to_simplified_string : ?withclass:bool -> t -> string
(** Convert a proc name into an easy string for the user to see in an IDE. *)
val from_string_c_fun : string -> t
(** Convert a string to a c function name. *)
val hashable_name : t -> string
(** Convert the procedure name in a format suitable for computing the bug hash. *)
val pp_unique_id : F.formatter -> t -> unit
(** Print a proc name as a unique identifier. *)
val to_unique_id : t -> string
(** Convert a proc name into a unique identifier. *)
val to_filename : ?crc_only:bool -> t -> string
(** Convert a proc name to a filename or only to its crc. *)
val get_qualifiers : t -> QualifiedCppName.t
(** get qualifiers of C/objc/C++ method/function *)
end

@ -54,7 +54,7 @@ let get_declaring_function = function
let is_local_to_procedure proc_name var =
get_declaring_function var |> Option.exists ~f:(Typ.Procname.equal proc_name)
get_declaring_function var |> Option.exists ~f:(Procname.equal proc_name)
let get_all_vars_in_exp e =

@ -33,7 +33,7 @@ val get_pvar : t -> Pvar.t option
val is_global : t -> bool
val is_local_to_procedure : Typ.Procname.t -> t -> bool
val is_local_to_procedure : Procname.t -> t -> bool
val is_return : t -> bool

@ -29,7 +29,7 @@ end = struct
L.(die InternalError)
"Exceeded max widening threshold %d while analyzing %a. Please check your widening \
operator or increase the threshold"
Config.max_widens Typ.Procname.pp (Procdesc.get_proc_name pdesc) ;
Config.max_widens Procname.pp (Procdesc.get_proc_name pdesc) ;
visit_count'
end
@ -217,7 +217,7 @@ module AbstractInterpreterCommon (TransferFunctions : TransferFunctions.SIL) = s
else if is_narrowing && not (Domain.leq ~lhs:new_pre ~rhs:old_state.State.pre) then (
L.(debug Analysis Verbose)
"Terminate narrowing because old and new states are not comparable at %a:%a@."
Typ.Procname.pp (Summary.get_proc_name summary) Node.pp_id node_id ;
Procname.pp (Summary.get_proc_name summary) Node.pp_id node_id ;
(inv_map, ReachedFixPoint) )
else
let visit_count' =

@ -36,7 +36,7 @@ module Make (TransferFunctions : TransferFunctions.HIL) (HilConfig : HilConfig)
let is_java_unlock pname actuals =
(* would check is_java, but we want to include builtins too *)
(not (Typ.Procname.is_c_method pname))
(not (Procname.is_c_method pname))
&& match ConcurrencyModels.get_lock_effect pname actuals with Unlock _ -> true | _ -> false

@ -178,8 +178,7 @@ let get_vararg_type_names tenv (call_node : Procdesc.Node.t) (ivar : Pvar.t) : s
|> Option.exists ~f:(fun t2 ->
Instrs.exists instrs ~f:(function
| Sil.Call ((t1, _), Exp.Const (Const.Cfun pn), _, _, _) ->
Ident.equal t1 t2
&& Typ.Procname.equal pn (Typ.Procname.from_string_c_fun "__new_array")
Ident.equal t1 t2 && Procname.equal pn (Procname.from_string_c_fun "__new_array")
| _ ->
false ) )
in
@ -283,8 +282,8 @@ let method_is_initializer (tenv : Tenv.t) (proc_attributes : ProcAttributes.t) :
| Some this_type ->
if type_has_initializer tenv this_type then
match proc_attributes.ProcAttributes.proc_name with
| Typ.Procname.Java pname_java ->
let mname = Typ.Procname.Java.get_method pname_java in
| Procname.Java pname_java ->
let mname = Procname.Java.get_method pname_java in
List.exists ~f:(String.equal mname) initializer_methods
| _ ->
false
@ -313,7 +312,7 @@ let java_get_vararg_values node pvar idenv =
[]
let proc_calls resolve_attributes pdesc filter : (Typ.Procname.t * ProcAttributes.t) list =
let proc_calls resolve_attributes pdesc filter : (Procname.t * ProcAttributes.t) list =
let res = ref [] in
let do_instruction _ instr =
match instr with
@ -335,13 +334,13 @@ let proc_calls resolve_attributes pdesc filter : (Typ.Procname.t * ProcAttribute
let is_override_of proc_name =
let method_name = Typ.Procname.get_method proc_name in
let parameter_length = List.length (Typ.Procname.get_parameters proc_name) in
let method_name = Procname.get_method proc_name in
let parameter_length = List.length (Procname.get_parameters proc_name) in
Staged.stage (fun pname ->
(not (Typ.Procname.is_constructor pname))
&& String.equal (Typ.Procname.get_method pname) method_name
(not (Procname.is_constructor pname))
&& String.equal (Procname.get_method pname) method_name
(* TODO (T32979782): match parameter types, taking subtyping and type erasure into account *)
&& Int.equal (List.length (Typ.Procname.get_parameters pname)) parameter_length )
&& Int.equal (List.length (Procname.get_parameters pname)) parameter_length )
let override_find ?(check_current_type = true) f tenv proc_name =
@ -361,11 +360,10 @@ let override_find ?(check_current_type = true) f tenv proc_name =
if check_current_type && f proc_name then Some proc_name
else
match proc_name with
| Typ.Procname.Java proc_name_java ->
find_super_type
(Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name proc_name_java))
| Typ.Procname.ObjC_Cpp proc_name_cpp ->
find_super_type (Typ.Procname.ObjC_Cpp.get_class_type_name proc_name_cpp)
| Procname.Java proc_name_java ->
find_super_type (Typ.Name.Java.from_string (Procname.Java.get_class_name proc_name_java))
| Procname.ObjC_Cpp proc_name_cpp ->
find_super_type (Procname.ObjC_Cpp.get_class_type_name proc_name_cpp)
| _ ->
None
@ -421,9 +419,9 @@ 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
| Typ.Procname.Java java_pname ->
| Procname.Java java_pname ->
let check_class_annots _ {Struct.annots} = check annots in
supertype_exists tenv check_class_annots (Typ.Procname.Java.get_class_type_name java_pname)
supertype_exists tenv check_class_annots (Procname.Java.get_class_type_name java_pname)
| _ ->
false
@ -431,8 +429,8 @@ let check_class_attributes check tenv = function
(** 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
| Typ.Procname.Java java_pname -> (
match Tenv.lookup tenv (Typ.Procname.Java.get_class_type_name java_pname) with
| Procname.Java java_pname -> (
match Tenv.lookup tenv (Procname.Java.get_class_type_name java_pname) with
| Some struct_typ ->
check struct_typ.annots
| _ ->

@ -105,22 +105,22 @@ val java_get_vararg_values : Procdesc.Node.t -> Pvar.t -> Idenv.t -> Exp.t list
(** Get the values of a vararg parameter given the pvar used to assign the elements. *)
val proc_calls :
(Typ.Procname.t -> ProcAttributes.t option)
(Procname.t -> ProcAttributes.t option)
-> Procdesc.t
-> (Typ.Procname.t -> ProcAttributes.t -> bool)
-> (Typ.Procname.t * ProcAttributes.t) list
-> (Procname.t -> ProcAttributes.t -> bool)
-> (Procname.t * ProcAttributes.t) list
(** Return the callees that satisfy [filter]. *)
val override_exists :
?check_current_type:bool -> (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t -> bool
?check_current_type:bool -> (Procname.t -> bool) -> Tenv.t -> Procname.t -> bool
(** Return true if applying the given predicate to an override of [procname] (including [procname]
itself when [check_current_type] is true, which it is by default) returns true. *)
val override_iter : (Typ.Procname.t -> unit) -> Tenv.t -> Typ.Procname.t -> unit
val override_iter : (Procname.t -> unit) -> Tenv.t -> Procname.t -> unit
(** Apply the given predicate to procname and each override of [procname]. For the moment, this only
works for Java *)
val lookup_attributes : Tenv.t -> Typ.Procname.t -> ProcAttributes.t option
val lookup_attributes : Tenv.t -> Procname.t -> ProcAttributes.t option
val type_get_annotation : Tenv.t -> Typ.t -> Annot.Item.t option
@ -139,11 +139,11 @@ val is_throwable : Tenv.t -> Typ.Name.t -> bool
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 -> Typ.Procname.t -> bool
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 -> Typ.Procname.t -> bool
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*)
@ -151,4 +151,4 @@ 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 : Typ.Procname.t -> (Typ.Procname.t -> bool) Staged.t
val is_override_of : Procname.t -> (Procname.t -> bool) Staged.t

@ -20,11 +20,11 @@ module type S = sig
val of_summary : Summary.t -> t option
val read_full : caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> (Procdesc.t * t) option
val read_full : caller_summary:Summary.t -> callee_pname:Procname.t -> (Procdesc.t * t) option
val read : caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> t option
val read : caller_summary:Summary.t -> callee_pname:Procname.t -> t option
val read_toplevel_procedure : Typ.Procname.t -> t option
val read_toplevel_procedure : Procname.t -> t option
end
module Make (P : Payload) : S with type t = P.t = struct

@ -22,14 +22,14 @@ module type S = sig
val of_summary : Summary.t -> t option
(** Read the corresponding part of the payload from the procedure summary *)
val read_full : caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> (Procdesc.t * t) option
val read_full : caller_summary:Summary.t -> callee_pname:Procname.t -> (Procdesc.t * t) option
(** Return the proc desc and payload for the given procedure. Runs the analysis on-demand if
necessary. *)
val read : caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> t option
val read : caller_summary:Summary.t -> callee_pname:Procname.t -> t option
(** Return the payload for the given procedure. Runs the analysis on-demand if necessary. *)
val read_toplevel_procedure : Typ.Procname.t -> t option
val read_toplevel_procedure : Procname.t -> t option
end
module Make (P : Payload) : S with type t = P.t

@ -480,7 +480,7 @@ let log_frontend_issue method_decl_opt (node : Ctl_parser_types.ast_node)
| Some method_decl ->
CType_decl.CProcname.from_decl_for_linters method_decl
| None ->
Typ.Procname.Linters_dummy_method
Procname.Linters_dummy_method
in
let issue_log', errlog = IssueLog.get_or_add ~proc:procname !issue_log in
issue_log := issue_log' ;

@ -768,11 +768,11 @@ let get_method_name_from_context context =
let is_objc_constructor context =
Typ.Procname.ObjC_Cpp.is_objc_constructor (get_method_name_from_context context)
Procname.ObjC_Cpp.is_objc_constructor (get_method_name_from_context context)
let is_objc_dealloc context =
Typ.Procname.ObjC_Cpp.is_objc_dealloc (get_method_name_from_context context)
Procname.ObjC_Cpp.is_objc_dealloc (get_method_name_from_context context)
let is_in_method context name =

@ -8,9 +8,9 @@ open! IStd
module F = Format
module type NodeSig = sig
type t = private {id: int; pname: Typ.Procname.t; mutable successors: int list; mutable flag: bool}
type t = private {id: int; pname: Procname.t; mutable successors: int list; mutable flag: bool}
val make : int -> Typ.Procname.t -> int list -> t
val make : int -> Procname.t -> int list -> t
val add_successor : t -> int -> unit
@ -22,7 +22,7 @@ module type NodeSig = sig
end
module Node : NodeSig = struct
type t = {id: int; pname: Typ.Procname.t; mutable successors: int list; mutable flag: bool}
type t = {id: int; pname: Procname.t; mutable successors: int list; mutable flag: bool}
let make id pname successors = {id; pname; successors; flag= false}
@ -37,13 +37,13 @@ module Node : NodeSig = struct
let pp_edge fmt src dst = F.fprintf fmt " %a -> %a ;@\n" pp_id src pp_id dst in
let pp_flag fmt flag = F.fprintf fmt "%B" flag in
F.fprintf fmt " %a [ label = %S, flag = %a ];@\n" pp_id id
(F.asprintf "%a" Typ.Procname.pp pname)
(F.asprintf "%a" Procname.pp pname)
pp_flag flag ;
List.iter successors ~f:(pp_edge fmt id) ;
F.pp_print_newline fmt ()
end
module IdMap = Typ.Procname.Hash
module IdMap = Procname.Hash
module NodeMap = Caml.Hashtbl.Make (Int)
(** [node_map] is a map from ids (unique ints) to nodes corresponding to defined procedures.

@ -8,9 +8,9 @@ open! IStd
module F = Format
module type NodeSig = sig
type t = private {id: int; pname: Typ.Procname.t; mutable successors: int list; mutable flag: bool}
type t = private {id: int; pname: Procname.t; mutable successors: int list; mutable flag: bool}
val make : int -> Typ.Procname.t -> int list -> t
val make : int -> Procname.t -> int list -> t
val add_successor : t -> int -> unit
@ -37,15 +37,15 @@ val n_procs : t -> int
val mem : t -> int -> bool
(** is an int [id] the index of a node in the graph? *)
val flag : t -> Typ.Procname.t -> unit
val flag : t -> Procname.t -> unit
val flag_reachable : t -> Typ.Procname.t -> unit
val flag_reachable : t -> Procname.t -> unit
(** flag all nodes reachable from the node of the given procname, if it exists *)
val get_unflagged_leaves : t -> Node.t list
(** get all leaves that have their flag set to false *)
val remove : t -> Typ.Procname.t -> unit
val remove : t -> Procname.t -> unit
val to_dotty : t -> string -> unit
(** output call graph in dotty format with the given filename in results dir *)
@ -56,11 +56,11 @@ val trim_id_map : t -> unit
val remove_unflagged_and_unflag_all : t -> unit
(** remove all nodes with flag set to false, and set flag to false on all remaining nodes *)
val add_edge : t -> pname:Typ.Procname.t -> successor_pname:Typ.Procname.t -> unit
val add_edge : t -> pname:Procname.t -> successor_pname:Procname.t -> unit
(** add an edge from [pname] to [successor_pname] in the graph, creating a node for [pname] if there
isn't one already *)
val create_node : t -> Typ.Procname.t -> Typ.Procname.t list -> unit
val create_node : t -> Procname.t -> Procname.t list -> unit
(** create a new node with edges from [pname] to [successor_pnames] in the graph *)
val fold_flagged : t -> f:(Node.t -> 'a -> 'a) -> 'a -> 'a

@ -259,8 +259,8 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
in
let msg =
(* Java Only *)
if String.equal method_name Typ.Procname.Java.constructor_method_name then "constructor"
else if String.equal method_name Typ.Procname.Java.class_initializer_method_name then
if String.equal method_name Procname.Java.constructor_method_name then "constructor"
else if String.equal method_name Procname.Java.class_initializer_method_name then
"class initializer"
else "this function"
in

@ -8,9 +8,9 @@ open! IStd
module L = Logging
module PerfProfilerDataMap = Caml.Map.Make (struct
type t = Typ.Procname.t
type t = Procname.t
let compare = Typ.Procname.compare
let compare = Procname.compare
end)
let global_perf_profiler_data : Perf_profiler_t.perf_profiler_item PerfProfilerDataMap.t ref =

@ -7,4 +7,4 @@
open! IStd
val in_profiler_data_map : Typ.Procname.t -> bool
val in_profiler_data_map : Procname.t -> bool

@ -13,9 +13,7 @@ module F = Format
module L = Logging
let clear_caches () =
Ondemand.LocalCache.clear () ;
Summary.OnDisk.clear_cache () ;
Typ.Procname.SQLite.clear_cache ()
Ondemand.LocalCache.clear () ; Summary.OnDisk.clear_cache () ; Procname.SQLite.clear_cache ()
let analyze_target : SchedulerTypes.target Tasks.doer =
@ -37,7 +35,7 @@ let analyze_target : SchedulerTypes.target Tasks.doer =
decr procs_left ;
if Int.( <= ) !procs_left 0 then (
L.log_task "Analysing block of %d procs, starting with %a@." per_procedure_logging_granularity
Typ.Procname.pp proc_name ;
Procname.pp proc_name ;
procs_left := per_procedure_logging_granularity ) ;
Ondemand.analyze_proc_name_toplevel exe_env proc_name
in

@ -23,16 +23,16 @@ let error_desc_to_plain_string error_desc =
let error_desc_to_dotty_string error_desc = Localise.error_desc_get_dotty error_desc
let compute_key (bug_type : string) (proc_name : Typ.Procname.t) (filename : string) =
let compute_key (bug_type : string) (proc_name : Procname.t) (filename : string) =
let base_filename = Filename.basename filename
and simple_procedure_name = Typ.Procname.get_method proc_name in
and simple_procedure_name = Procname.get_method proc_name in
String.concat ~sep:"|" [base_filename; simple_procedure_name; bug_type]
let compute_hash ~(severity : string) ~(bug_type : string) ~(proc_name : Typ.Procname.t)
let compute_hash ~(severity : string) ~(bug_type : string) ~(proc_name : Procname.t)
~(file : string) ~(qualifier : string) =
let base_filename = Filename.basename file in
let hashable_procedure_name = Typ.Procname.hashable_name proc_name in
let hashable_procedure_name = Procname.hashable_name proc_name in
let location_independent_qualifier =
(* Removing the line,column, and infer temporary variable (e.g., n$67) information from the
error message as well as the index of the annonymmous class to make the hash invariant
@ -97,8 +97,8 @@ let summary_values summary =
let pp fmt = Pp.seq pp_line fmt lines_visited in
F.asprintf "%t" pp
in
{ vname= Typ.Procname.to_string proc_name
; vname_id= Typ.Procname.to_filename proc_name
{ vname= Procname.to_string proc_name
; vname_id= Procname.to_filename proc_name
; vspecs= List.length specs
; vto= Summary.Stats.failure_kind_to_string stats
; vsymop= Summary.Stats.symops stats
@ -213,17 +213,17 @@ end
type json_issue_printer_typ =
{ error_filter: SourceFile.t -> IssueType.t -> bool
; proc_name: Typ.Procname.t
; proc_name: Procname.t
; proc_loc_opt: Location.t option
; err_key: Errlog.err_key
; err_data: Errlog.err_data }
let procedure_id_of_procname proc_name =
match Typ.Procname.get_language proc_name with
match Procname.get_language proc_name with
| Language.Java ->
Typ.Procname.to_unique_id proc_name
Procname.to_unique_id proc_name
| _ ->
Typ.Procname.to_string proc_name
Procname.to_string proc_name
module JsonIssuePrinter = MakeJsonListPrinter (struct
@ -314,14 +314,14 @@ module IssuesJson = struct
end
type json_costs_printer_typ =
{loc: Location.t; proc_name: Typ.Procname.t; cost_opt: CostDomain.summary option}
{loc: Location.t; proc_name: Procname.t; cost_opt: CostDomain.summary option}
module JsonCostsPrinter = MakeJsonListPrinter (struct
type elt = json_costs_printer_typ
let to_string {loc; proc_name; cost_opt} =
match cost_opt with
| Some {post; is_on_ui_thread} when not (Typ.Procname.is_java_access_method proc_name) ->
| Some {post; is_on_ui_thread} when not (Procname.is_java_access_method proc_name) ->
let hum cost =
let degree_with_term = CostDomain.BasicCost.get_degree_with_term cost in
{ Jsonbug_t.hum_polynomial= Format.asprintf "%a" CostDomain.BasicCost.pp_hum cost
@ -344,7 +344,7 @@ module JsonCostsPrinter = MakeJsonListPrinter (struct
let file = SourceFile.to_rel_path loc.Location.file in
{ Jsonbug_t.hash= compute_hash ~severity:"" ~bug_type:"" ~proc_name ~file ~qualifier:""
; loc= {file; lnum= loc.Location.line; cnum= loc.Location.col; enum= -1}
; procedure_name= Typ.Procname.get_method proc_name
; procedure_name= Procname.get_method proc_name
; procedure_id= procedure_id_of_procname proc_name
; is_on_ui_thread
; exec_cost= cost_info (CostDomain.get_cost_kind CostKind.OperationCost post)
@ -599,7 +599,7 @@ module StatsLogs = struct
ClangMethodKind.to_string (Summary.get_attributes summary).clang_method_kind
in
let proc_name = Summary.get_proc_name summary in
let lang = Typ.Procname.get_language proc_name in
let lang = Procname.get_language proc_name in
let stats =
EventLogger.AnalysisStats
{ analysis_nodes_visited= Summary.Stats.nb_visited summary.stats
@ -608,7 +608,7 @@ module StatsLogs = struct
; clang_method_kind= (match lang with Language.Clang -> Some clang_method_kind | _ -> None)
; lang= Language.to_explicit_string lang
; method_location= Summary.get_loc summary
; method_name= Typ.Procname.to_string proc_name
; method_name= Procname.to_string proc_name
; num_preposts
; symops= Summary.Stats.symops summary.stats }
in
@ -642,16 +642,16 @@ module PreconditionStats = struct
match Prop.CategorizePreconditions.categorize preconditions with
| Prop.CategorizePreconditions.Empty ->
incr nr_empty ;
L.result "Procedure: %a footprint:Empty@." Typ.Procname.pp proc_name
L.result "Procedure: %a footprint:Empty@." Procname.pp proc_name
| Prop.CategorizePreconditions.OnlyAllocation ->
incr nr_onlyallocation ;
L.result "Procedure: %a footprint:OnlyAllocation@." Typ.Procname.pp proc_name
L.result "Procedure: %a footprint:OnlyAllocation@." Procname.pp proc_name
| Prop.CategorizePreconditions.NoPres ->
incr nr_nopres ;
L.result "Procedure: %a footprint:NoPres@." Typ.Procname.pp proc_name
L.result "Procedure: %a footprint:NoPres@." Procname.pp proc_name
| Prop.CategorizePreconditions.DataConstraints ->
incr nr_dataconstraints ;
L.result "Procedure: %a footprint:DataConstraints@." Typ.Procname.pp proc_name
L.result "Procedure: %a footprint:DataConstraints@." Procname.pp proc_name
let pp_stats () =
@ -819,7 +819,7 @@ module SummaryStats = struct
let do_summary proc_name summary = results := MetricResults.add !results proc_name summary
let pp_stats () = L.result "%a@\n" (MetricResults.pp ~pp_k:Typ.Procname.pp) !results
let pp_stats () = L.result "%a@\n" (MetricResults.pp ~pp_k:Procname.pp) !results
end
let error_filter filters proc_name file error_name =
@ -953,7 +953,7 @@ let pp_stats error_filter linereader summary stats stats_format_list =
let pp_summary summary =
L.result "Procedure: %a@\n%a@." Typ.Procname.pp (Summary.get_proc_name summary) Summary.pp_text
L.result "Procedure: %a@\n%a@." Procname.pp (Summary.get_proc_name summary) Summary.pp_text
summary

@ -9,7 +9,7 @@ open! IStd
module L = Logging
type t =
{ proc_name: Typ.Procname.t
{ proc_name: Procname.t
; proc_location: Location.t
; err_key: Errlog.err_key
; err_data: Errlog.err_data }
@ -23,7 +23,7 @@ let compare_err_data_ (err_data1 : Errlog.err_data) (err_data2 : Errlog.err_data
Location.compare err_data1.loc err_data2.loc
type proc_name_ = Typ.Procname.t
type proc_name_ = Procname.t
(* ignore proc name *)
let compare_proc_name_ _ _ = 0

@ -8,7 +8,7 @@
open! IStd
type t =
{ proc_name: Typ.Procname.t
{ proc_name: Procname.t
; proc_location: Location.t
; err_key: Errlog.err_key
; err_data: Errlog.err_data }

@ -32,17 +32,17 @@ let try_capture (attributes : ProcAttributes.t) : ProcAttributes.t option =
(* peek at the results to know if capture succeeded, but only in debug mode *)
L.(debug Capture Verbose)
"Captured file %a to get procedure %a but it wasn't found there@\n" SourceFile.pp
definition_file Typ.Procname.pp attributes.proc_name )
definition_file Procname.pp attributes.proc_name )
else
L.(debug Capture Verbose)
"Wanted to capture file %a to get procedure %a but file was already captured@\n"
SourceFile.pp definition_file Typ.Procname.pp attributes.proc_name
SourceFile.pp definition_file Procname.pp attributes.proc_name
in
match definition_file_opt with
| None ->
L.(debug Capture Medium)
"Couldn't find source file for %a (declared in %a)@\n" Typ.Procname.pp
attributes.proc_name SourceFile.pp decl_file
"Couldn't find source file for %a (declared in %a)@\n" Procname.pp attributes.proc_name
SourceFile.pp decl_file
| Some file ->
try_compile file ) ;
(* It's important to call load_defined_attributes again in all cases to make sure we try

@ -13,7 +13,7 @@ let get_all ~filter () =
SqliteUtils.result_fold_rows db ~log:"reading all procedure names" stmt ~init:[]
~f:(fun rev_results stmt ->
let source_file = Sqlite3.column stmt 0 |> SourceFile.SQLite.deserialize in
let proc_name = Sqlite3.column stmt 1 |> Typ.Procname.SQLite.deserialize in
let proc_name = Sqlite3.column stmt 1 |> Procname.SQLite.deserialize in
if filter source_file proc_name then proc_name :: rev_results else rev_results )
@ -35,7 +35,7 @@ let pp_all ~filter ~proc_name:proc_name_cond ~attr_kind ~source_file:source_file
Format.fprintf fmt "@[<v2>%s@,%a%a%a%a@]@\n" proc_name_hum
(pp_if source_file_cond "source_file" SourceFile.pp)
source_file
(pp_if proc_name_cond "proc_name" Typ.Procname.pp)
(pp_if proc_name_cond "proc_name" Procname.pp)
proc_name
(pp_column_if stmt attr_kind "attribute_kind" Attributes.deserialize_attributes_kind
Attributes.pp_attributes_kind)
@ -50,6 +50,6 @@ let pp_all ~filter ~proc_name:proc_name_cond ~attr_kind ~source_file:source_file
"SELECT proc_name, proc_name_hum, attr_kind, source_file, proc_attributes FROM procedures"
|> Container.iter ~fold:(SqliteUtils.result_fold_rows db ~log:"print all procedures")
~f:(fun stmt ->
let proc_name = Sqlite3.column stmt 0 |> Typ.Procname.SQLite.deserialize in
let proc_name = Sqlite3.column stmt 0 |> Procname.SQLite.deserialize in
let source_file = Sqlite3.column stmt 3 |> SourceFile.SQLite.deserialize in
if filter source_file proc_name then pp_row stmt fmt source_file proc_name )

@ -7,7 +7,7 @@
open! IStd
val get_all : filter:Filtering.procedures_filter -> unit -> Typ.Procname.t list
val get_all : filter:Filtering.procedures_filter -> unit -> Procname.t list
val pp_all :
filter:Filtering.procedures_filter

@ -9,7 +9,7 @@ open! IStd
let register_summary graph summary =
let caller_pname = Summary.get_proc_name summary in
let callee_pnames = summary.Summary.callee_pnames in
Typ.Procname.Set.iter
Procname.Set.iter
(fun callee_pname -> CallGraph.add_edge graph ~pname:callee_pname ~successor_pname:caller_pname)
callee_pnames

@ -6,4 +6,4 @@
*)
open! IStd
type target = Procname of Typ.Procname.t | File of SourceFile.t
type target = Procname of Procname.t | File of SourceFile.t

@ -14,6 +14,6 @@ val iter_from_config : f:(Summary.t -> unit) -> unit
(** Iterates over all sumaries from the .specs files unless a list of specs files has been passed on
the command line *)
val delete : Typ.Procname.t -> unit
val delete : Procname.t -> unit
(** Delete the .specs file associated with a summary and remove the summary from the caches in
Summary.ml and ondemand.ml *)

@ -71,7 +71,7 @@ include struct
; status: Status.t
; proc_desc: Procdesc.t
; err_log: Errlog.t
; mutable callee_pnames: Typ.Procname.Set.t }
; mutable callee_pnames: Procname.Set.t }
[@@deriving fields]
end
@ -102,7 +102,7 @@ let pp_errlog fmt err_log =
let pp_signature fmt summary =
let pp_formal fmt (p, typ) = F.fprintf fmt "%a %a" (Typ.pp_full Pp.text) typ Mangled.pp p in
F.fprintf fmt "%a %a(%a)" (Typ.pp_full Pp.text) (get_ret_type summary) Typ.Procname.pp
F.fprintf fmt "%a %a(%a)" (Typ.pp_full Pp.text) (get_ret_type summary) Procname.pp
(get_proc_name summary) (Pp.seq ~sep:", " pp_formal) (get_formals summary)
@ -133,21 +133,21 @@ let pp_html source fmt summary =
module OnDisk = struct
open PolyVariantEqual
type cache = t Typ.Procname.Hash.t
type cache = t Procname.Hash.t
let cache : cache = Typ.Procname.Hash.create 128
let cache : cache = Procname.Hash.create 128
let clear_cache () = Typ.Procname.Hash.clear cache
let clear_cache () = Procname.Hash.clear cache
let remove_from_cache pname = Typ.Procname.Hash.remove cache pname
let remove_from_cache pname = Procname.Hash.remove cache pname
(** Add the summary to the table for the given function *)
let add (proc_name : Typ.Procname.t) (summary : t) : unit =
Typ.Procname.Hash.replace cache proc_name summary
let add (proc_name : Procname.t) (summary : t) : unit =
Procname.Hash.replace cache proc_name summary
let specs_filename pname =
let pname_file = Typ.Procname.to_filename pname in
let pname_file = Procname.to_filename pname in
pname_file ^ Config.specs_files_suffix
@ -213,7 +213,7 @@ module OnDisk = struct
let get proc_name =
match Typ.Procname.Hash.find cache proc_name with
match Procname.Hash.find cache proc_name with
| summary ->
BackendStats.incr_summary_cache_hits () ;
Some summary
@ -258,15 +258,15 @@ module OnDisk = struct
; status= Status.Pending
; proc_desc
; err_log= Errlog.empty ()
; callee_pnames= Typ.Procname.Set.empty }
; callee_pnames= Procname.Set.empty }
in
Typ.Procname.Hash.replace cache (Procdesc.get_proc_name proc_desc) summary ;
Procname.Hash.replace cache (Procdesc.get_proc_name proc_desc) summary ;
summary
let dummy =
let dummy_attributes =
ProcAttributes.default (SourceFile.invalid __FILE__) Typ.Procname.empty_block
ProcAttributes.default (SourceFile.invalid __FILE__) Procname.empty_block
in
let dummy_proc_desc = Procdesc.from_proc_attributes dummy_attributes in
reset dummy_proc_desc

@ -47,11 +47,11 @@ type t =
; status: Status.t
; proc_desc: Procdesc.t
; err_log: Errlog.t
; mutable callee_pnames: Typ.Procname.Set.t }
; mutable callee_pnames: Procname.Set.t }
val poly_fields : t PolyFields.t
val get_proc_name : t -> Typ.Procname.t
val get_proc_name : t -> Procname.t
(** Get the procedure name *)
val get_proc_desc : t -> Procdesc.t
@ -79,29 +79,29 @@ val pp_text : Format.formatter -> t -> unit
(** Print the summary in text format *)
module OnDisk : sig
val has_model : Typ.Procname.t -> bool
val has_model : Procname.t -> bool
(** Check if a summary for a given procedure exists in the models directory *)
val clear_cache : unit -> unit
(** Remove all the elements from the cache of summaries *)
val remove_from_cache : Typ.Procname.t -> unit
val remove_from_cache : Procname.t -> unit
(** Remove an element from the cache of summaries. Contrast to reset which re-initializes a
summary keeping the same Procdesc and updates the cache accordingly. *)
val get : Typ.Procname.t -> t option
val get : Procname.t -> t option
(** Return the summary option for the procedure name *)
val reset : Procdesc.t -> t
(** Reset a summary rebuilding the dependents and preserving the proc attributes if present. *)
val specs_filename_of_procname : Typ.Procname.t -> DB.filename
val specs_filename_of_procname : Procname.t -> DB.filename
(** Return the path to the .specs file for the given procedure in the current results directory *)
val load_from_file : DB.filename -> t option
(** Load procedure summary from the given file *)
val proc_resolve_attributes : Typ.Procname.t -> ProcAttributes.t option
val proc_resolve_attributes : Procname.t -> ProcAttributes.t option
(** Try to find the attributes for a defined proc. First look at specs (to get attributes computed
by analysis) then look at the attributes table. If no attributes can be found, return None. *)

@ -6,11 +6,11 @@
*)
open! IStd
module L = Logging
module IdMap = Typ.Procname.Hash
module IdMap = Procname.Hash
let build_from_captured_procs g =
let hashcons_pname =
let pname_tbl : Typ.Procname.t IdMap.t = IdMap.create 1001 in
let pname_tbl : Procname.t IdMap.t = IdMap.create 1001 in
fun pname ->
match IdMap.find_opt pname_tbl pname with
| Some pname' ->
@ -21,9 +21,9 @@ let build_from_captured_procs g =
let db = ResultsDatabase.get_database () in
let stmt = Sqlite3.prepare db "SELECT proc_name, callees FROM procedures" in
SqliteUtils.result_fold_rows db ~log:"creating call graph" stmt ~init:() ~f:(fun () stmt ->
let proc_name = Sqlite3.column stmt 0 |> Typ.Procname.SQLite.deserialize |> hashcons_pname in
let proc_name = Sqlite3.column stmt 0 |> Procname.SQLite.deserialize |> hashcons_pname in
let callees =
Sqlite3.column stmt 1 |> Typ.Procname.SQLiteList.deserialize |> List.map ~f:hashcons_pname
Sqlite3.column stmt 1 |> Procname.SQLiteList.deserialize |> List.map ~f:hashcons_pname
in
CallGraph.create_node g proc_name callees )
@ -66,9 +66,9 @@ let bottom_up sources : SchedulerTypes.target ProcessPool.TaskGenerator.t =
let syntactic_call_graph = CallGraph.create CallGraph.default_initial_capacity in
let initialized = ref false in
let pending : CallGraph.Node.t list ref = ref [] in
let scheduled = ref Typ.Procname.Set.empty in
let scheduled = ref Procname.Set.empty in
let is_empty () =
let empty = !initialized && List.is_empty !pending && Typ.Procname.Set.is_empty !scheduled in
let empty = !initialized && List.is_empty !pending && Procname.Set.is_empty !scheduled in
if empty then (
remaining := 0 ;
L.progress "Finished call graph scheduling, %d procs remaining (in, or reaching, cycles).@."
@ -88,7 +88,7 @@ let bottom_up sources : SchedulerTypes.target ProcessPool.TaskGenerator.t =
next_aux ()
| n :: ns ->
pending := ns ;
scheduled := Typ.Procname.Set.add n.pname !scheduled ;
scheduled := Procname.Set.add n.pname !scheduled ;
CallGraph.flag syntactic_call_graph n.pname ;
Some (Procname n.pname)
in
@ -97,7 +97,7 @@ let bottom_up sources : SchedulerTypes.target ProcessPool.TaskGenerator.t =
assert false
| Procname pname ->
decr remaining ;
scheduled := Typ.Procname.Set.remove pname !scheduled ;
scheduled := Procname.Set.remove pname !scheduled ;
CallGraph.remove syntactic_call_graph pname
in
let next () =

@ -10,7 +10,7 @@ open! IStd
(** Module to register and invoke callbacks *)
type proc_callback_args =
{get_procs_in_file: Typ.Procname.t -> Typ.Procname.t list; summary: Summary.t; exe_env: Exe_env.t}
{get_procs_in_file: Procname.t -> Procname.t list; summary: Summary.t; exe_env: Exe_env.t}
type proc_callback_t = proc_callback_args -> Summary.t
@ -49,7 +49,7 @@ let get_procedure_definition exe_env proc_name =
let iterate_procedure_callbacks exe_env summary =
let proc_desc = Summary.get_proc_desc summary in
let proc_name = Procdesc.get_proc_name proc_desc in
let procedure_language = Typ.Procname.get_language proc_name in
let procedure_language = Procname.get_language proc_name in
Language.curr_language := procedure_language ;
let get_procs_in_file proc_name =
let source_file =
@ -68,7 +68,7 @@ let iterate_procedure_callbacks exe_env summary =
PerfEvent.(
log (fun logger ->
log_begin_event logger ~name ~categories:["backend"]
~arguments:[("proc", `String (Typ.Procname.to_string proc_name))]
~arguments:[("proc", `String (Procname.to_string proc_name))]
() )) ;
let summary = callback {get_procs_in_file; summary; exe_env} in
PerfEvent.(log (fun logger -> log_end_event logger ())) ;
@ -85,7 +85,7 @@ let iterate_cluster_callbacks all_procs exe_env source_file =
let language_matches language =
match procedures with
| (_, summary) :: _ ->
Language.equal language (Typ.Procname.get_language (Summary.get_proc_name summary))
Language.equal language (Procname.get_language (Summary.get_proc_name summary))
| _ ->
true
in

@ -10,7 +10,7 @@ open! IStd
(** Module to register and invoke callbacks *)
type proc_callback_args =
{get_procs_in_file: Typ.Procname.t -> Typ.Procname.t list; summary: Summary.t; exe_env: Exe_env.t}
{get_procs_in_file: Procname.t -> Procname.t list; summary: Summary.t; exe_env: Exe_env.t}
(** Type of a procedure callback:
@ -35,5 +35,5 @@ val register_cluster_callback : name:string -> Language.t -> cluster_callback_t
val iterate_procedure_callbacks : Exe_env.t -> Summary.t -> Summary.t
(** Invoke all registered procedure callbacks on the given procedure. *)
val iterate_cluster_callbacks : Typ.Procname.t list -> Exe_env.t -> SourceFile.t -> unit
val iterate_cluster_callbacks : Procname.t list -> Exe_env.t -> SourceFile.t -> unit
(** Invoke all registered cluster callbacks on a cluster of procedures. *)

@ -22,8 +22,8 @@ let is_one_of_classes = QualifiedCppName.Match.match_qualifiers
let is_method_of_objc_cpp_class pname matcher =
match pname with
| Typ.Procname.ObjC_Cpp objc_cpp ->
let class_qual_opt = Typ.Procname.ObjC_Cpp.get_class_qualifiers objc_cpp in
| Procname.ObjC_Cpp objc_cpp ->
let class_qual_opt = Procname.ObjC_Cpp.get_class_qualifiers objc_cpp in
is_one_of_classes matcher class_qual_opt
| _ ->
false
@ -166,7 +166,7 @@ let rec find_normal_variable_load_ tenv (seen : Exp.Set.t) node id : DExp.t opti
L.d_ln () ) ;
exp_lv_dexp_ tenv seen node e
| Sil.Call ((id0, _), Exp.Const (Const.Cfun pn), (e, _) :: _, _, _)
when Ident.equal id id0 && Typ.Procname.equal pn (Typ.Procname.from_string_c_fun "__cast") ->
when Ident.equal id id0 && Procname.equal pn (Procname.from_string_c_fun "__cast") ->
if verbose then (
L.d_str "find_normal_variable_load cast on " ;
Exp.d_exp e ;
@ -962,7 +962,7 @@ let explain_access_ proc_name tenv ?(use_buckets = false) ?(outermost_array = fa
L.d_ln () ) ;
Some e
| Some (Sil.Call (_, Exp.Const (Const.Cfun fn), [(e, _)], _, _))
when List.exists ~f:(Typ.Procname.equal fn)
when List.exists ~f:(Procname.equal fn)
[BuiltinDecl.free; BuiltinDecl.__delete; BuiltinDecl.__delete_array] ->
if verbose then (
L.d_str "explain_dereference Sil.Call " ;

@ -40,12 +40,12 @@ val explain_allocation_mismatch : PredSymb.res_action -> PredSymb.res_action ->
(** Produce a description of a mismatch between an allocation function and a deallocation function *)
val explain_array_access :
Typ.Procname.t -> Tenv.t -> Localise.deref_str -> 'a Prop.t -> Location.t -> Localise.error_desc
Procname.t -> Tenv.t -> Localise.deref_str -> 'a Prop.t -> Location.t -> Localise.error_desc
(** Produce a description of the array access performed in the current instruction, if any. *)
val explain_class_cast_exception :
Tenv.t
-> Typ.Procname.t option
-> Procname.t option
-> Exp.t
-> Exp.t
-> Exp.t
@ -61,7 +61,7 @@ val explain_deallocate_constant_string : string -> PredSymb.res_action -> Locali
(** Explain a deallocate constant string error *)
val explain_dereference :
Typ.Procname.t
Procname.t
-> Tenv.t
-> ?use_buckets:bool
-> ?is_nullable:bool
@ -73,7 +73,7 @@ val explain_dereference :
(** Produce a description of which expression is dereferenced in the current instruction, if any. *)
val explain_dereference_as_caller_expression :
Typ.Procname.t
Procname.t
-> Tenv.t
-> ?use_buckets:bool
-> Localise.deref_str

@ -38,16 +38,16 @@ let create_file_data table source =
type t =
{ proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *)
{ proc_map: file_data Procname.Hash.t (** map from procedure name to file data *)
; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) }
let get_file_data exe_env pname =
try Some (Typ.Procname.Hash.find exe_env.proc_map pname)
try Some (Procname.Hash.find exe_env.proc_map pname)
with Caml.Not_found ->
let source_file_opt =
match Attributes.load pname with
| None ->
L.debug Analysis Medium "can't find attributes for %a@." Typ.Procname.pp pname ;
L.debug Analysis Medium "can't find attributes for %a@." Procname.pp pname ;
None
| Some proc_attributes when Config.reactive_capture ->
let get_captured_file {ProcAttributes.translation_unit} = translation_unit in
@ -57,7 +57,7 @@ let get_file_data exe_env pname =
in
let get_file_data_for_source source_file =
let file_data = create_file_data exe_env.file_map source_file in
Typ.Procname.Hash.replace exe_env.proc_map pname file_data ;
Procname.Hash.replace exe_env.proc_map pname file_data ;
file_data
in
Option.map ~f:get_file_data_for_source source_file_opt
@ -92,7 +92,7 @@ let get_column_value ~value_on_java ~file_data_to_value ~column_name exe_env pro
()
in
match proc_name with
| Typ.Procname.Java _ ->
| Procname.Java _ ->
Lazy.force value_on_java
| _ -> (
match get_file_data exe_env proc_name with
@ -102,12 +102,12 @@ let get_column_value ~value_on_java ~file_data_to_value ~column_name exe_env pro
v
| None ->
let loc_opt = State.get_loc () in
L.die InternalError "get_column_value: %s not found for %a%a" column_name Typ.Procname.pp
L.die InternalError "get_column_value: %s not found for %a%a" column_name Procname.pp
proc_name pp_loc_opt loc_opt )
| None ->
let loc_opt = State.get_loc () in
L.die InternalError "get_column_value: file_data not found for %a%a" Typ.Procname.pp
proc_name pp_loc_opt loc_opt )
L.die InternalError "get_column_value: file_data not found for %a%a" Procname.pp proc_name
pp_loc_opt loc_opt )
(** return the type environment associated to the procedure *)
@ -123,4 +123,4 @@ let get_integer_type_widths =
~file_data_to_value:file_data_to_integer_type_widths ~column_name:"integer type widths"
let mk () = {proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1}
let mk () = {proc_map= Procname.Hash.create 17; file_map= SourceFile.Hash.create 1}

@ -14,14 +14,14 @@ open! IStd
type file_data
type t = private
{ proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *)
{ proc_map: file_data Procname.Hash.t (** map from procedure name to file data *)
; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) }
val mk : unit -> t
(** Create a new cache *)
val get_tenv : t -> Typ.Procname.t -> Tenv.t
val get_tenv : t -> Procname.t -> Tenv.t
(** return the type environment associated with the procedure *)
val get_integer_type_widths : t -> Typ.Procname.t -> Typ.IntegerWidths.t
val get_integer_type_widths : t -> Procname.t -> Typ.IntegerWidths.t
(** return the integer type widths associated with the procedure *)

@ -13,7 +13,7 @@ type path_filter = SourceFile.t -> bool
type error_filter = IssueType.t -> bool
type proc_filter = Typ.Procname.t -> bool
type proc_filter = Procname.t -> bool
type filters = {path_filter: path_filter; error_filter: error_filter; proc_filter: proc_filter}
@ -46,8 +46,8 @@ let is_matching patterns source_file =
(** Check if a proc name is matching the name given as string. *)
let match_method language proc_name method_name =
(not (BuiltinDecl.is_declared proc_name))
&& Language.equal (Typ.Procname.get_language proc_name) language
&& String.equal (Typ.Procname.get_method proc_name) method_name
&& Language.equal (Procname.get_language proc_name) language
&& String.equal (Procname.get_method proc_name) method_name
(* Module to create matcher based on strings present in the source file *)
@ -92,7 +92,7 @@ type pattern =
(* Module to create matcher based on source file names or class names and method names *)
module FileOrProcMatcher = struct
type matcher = SourceFile.t -> Typ.Procname.t -> bool
type matcher = SourceFile.t -> Procname.t -> bool
let default_matcher : matcher = fun _ _ -> false
@ -110,8 +110,8 @@ module FileOrProcMatcher = struct
~init:String.Map.empty m_patterns
in
let do_java pname_java =
let class_name = Typ.Procname.Java.get_class_name pname_java
and method_name = Typ.Procname.Java.get_method pname_java in
let class_name = Procname.Java.get_class_name pname_java
and method_name = Procname.Java.get_method pname_java in
try
let class_patterns = String.Map.find_exn pattern_map class_name in
List.exists
@ -121,7 +121,7 @@ module FileOrProcMatcher = struct
with Not_found_s _ | Caml.Not_found -> false
in
fun _ proc_name ->
match proc_name with Typ.Procname.Java pname_java -> do_java pname_java | _ -> false
match proc_name with Procname.Java pname_java -> do_java pname_java | _ -> false
let create_file_matcher patterns =

@ -14,20 +14,20 @@ type path_filter = SourceFile.t -> bool
type error_filter = IssueType.t -> bool
(** Filter type for a procedure name *)
type proc_filter = Typ.Procname.t -> bool
type proc_filter = Procname.t -> bool
type filters = {path_filter: path_filter; error_filter: error_filter; proc_filter: proc_filter}
val create_filters : unit -> filters
(** Create filters based on the config file *)
val never_return_null_matcher : SourceFile.t -> Typ.Procname.t -> bool
val never_return_null_matcher : SourceFile.t -> Procname.t -> bool
val skip_translation_matcher : SourceFile.t -> Typ.Procname.t -> bool
val skip_translation_matcher : SourceFile.t -> Procname.t -> bool
val skip_implementation_matcher : SourceFile.t -> Typ.Procname.t -> bool
val skip_implementation_matcher : SourceFile.t -> Procname.t -> bool
val modeled_expensive_matcher : (string -> bool) -> Typ.Procname.t -> bool
val modeled_expensive_matcher : (string -> bool) -> Procname.t -> bool
val test : unit -> unit
(** Load the config file and list the files to report on *)

@ -15,21 +15,20 @@ module F = Format
let exe_env_ref = ref None
module LocalCache = struct
let results = lazy (Typ.Procname.Hash.create 128)
let results = lazy (Procname.Hash.create 128)
let clear () = Typ.Procname.Hash.clear (Lazy.force results)
let clear () = Procname.Hash.clear (Lazy.force results)
let remove pname = Typ.Procname.Hash.remove (Lazy.force results) pname
let remove pname = Procname.Hash.remove (Lazy.force results) pname
let get proc_name =
let summ_opt_opt = Typ.Procname.Hash.find_opt (Lazy.force results) proc_name in
let summ_opt_opt = Procname.Hash.find_opt (Lazy.force results) proc_name in
if Option.is_some summ_opt_opt then BackendStats.incr_ondemand_local_cache_hits ()
else BackendStats.incr_ondemand_local_cache_misses () ;
summ_opt_opt
let add proc_name summary_option =
Typ.Procname.Hash.add (Lazy.force results) proc_name summary_option
let add proc_name summary_option = Procname.Hash.add (Lazy.force results) proc_name summary_option
end
let set_exe_env (env : Exe_env.t) = exe_env_ref := Some env
@ -46,12 +45,11 @@ let max_nesting_to_print = 8
let current_taskbar_status : (Mtime.t * string) option ref = ref None
let is_active, add_active, remove_active =
let currently_analyzed = ref Typ.Procname.Set.empty in
let is_active proc_name = Typ.Procname.Set.mem proc_name !currently_analyzed
and add_active proc_name =
currently_analyzed := Typ.Procname.Set.add proc_name !currently_analyzed
let currently_analyzed = ref Procname.Set.empty in
let is_active proc_name = Procname.Set.mem proc_name !currently_analyzed
and add_active proc_name = currently_analyzed := Procname.Set.add proc_name !currently_analyzed
and remove_active proc_name =
currently_analyzed := Typ.Procname.Set.remove proc_name !currently_analyzed
currently_analyzed := Procname.Set.remove proc_name !currently_analyzed
in
(is_active, add_active, remove_active)
@ -151,7 +149,7 @@ let analyze callee_summary =
if !nesting <= max_nesting_to_print then String.make !nesting '>'
else Printf.sprintf "%d>" !nesting
in
F.asprintf "%s%a: %a" nesting SourceFile.pp source_file Typ.Procname.pp proc_name
F.asprintf "%s%a: %a" nesting SourceFile.pp source_file Procname.pp proc_name
in
current_taskbar_status := Some (t0, status) ;
!ProcessPoolState.update_status t0 status ;
@ -166,13 +164,13 @@ let run_proc_analysis ~caller_pdesc callee_pdesc =
let start_time = Mtime_clock.counter () in
fun () ->
L.(debug Analysis Medium)
"Elapsed analysis time: %a: %a@\n" Typ.Procname.pp callee_pname Mtime.Span.pp
"Elapsed analysis time: %a: %a@\n" Procname.pp callee_pname Mtime.Span.pp
(Mtime_clock.count start_time)
in
if Config.trace_ondemand then
L.progress "[%d] run_proc_analysis %a -> %a@." !nesting (Pp.option Typ.Procname.pp)
L.progress "[%d] run_proc_analysis %a -> %a@." !nesting (Pp.option Procname.pp)
(Option.map caller_pdesc ~f:Procdesc.get_proc_name)
Typ.Procname.pp callee_pname ;
Procname.pp callee_pname ;
let preprocess () =
incr nesting ;
Preanal.do_preanalysis (Option.value_exn !exe_env_ref) callee_pdesc ;
@ -224,11 +222,11 @@ let run_proc_analysis ~caller_pdesc callee_pdesc =
let source_file = attributes.ProcAttributes.translation_unit in
let location = attributes.ProcAttributes.loc in
L.internal_error "While analysing function %a:%a at %a@\n" SourceFile.pp source_file
Typ.Procname.pp callee_pname Location.pp_file_pos location ;
Procname.pp callee_pname Location.pp_file_pos location ;
logged_error := true ) ;
restore_global_state old_state ;
not Config.keep_going ) ;
L.internal_error "@\nERROR RUNNING BACKEND: %a %s@\n@\nBACK TRACE@\n%s@?" Typ.Procname.pp
L.internal_error "@\nERROR RUNNING BACKEND: %a %s@\n@\nBACK TRACE@\n%s@?" Procname.pp
callee_pname (Exn.to_string exn) backtrace ;
match exn with
| SymOp.Analysis_failure_exe kind ->
@ -246,7 +244,7 @@ let run_proc_analysis ~caller_pdesc callee_pdesc =
log (fun logger ->
let callee_pname = Procdesc.get_proc_name callee_pdesc in
log_begin_event logger ~name:"ondemand" ~categories:["backend"]
~arguments:[("proc", `String (Typ.Procname.to_string callee_pname))]
~arguments:[("proc", `String (Procname.to_string callee_pname))]
() )) ;
let summary = run_proc_analysis ~caller_pdesc callee_pdesc in
PerfEvent.(log (fun logger -> log_end_event logger ())) ;
@ -278,7 +276,7 @@ let dump_duplicate_procs source_file procs =
let fmt = F.formatter_of_out_channel outc in
List.iter duplicate_procs ~f:(fun (pname, source_captured) ->
F.fprintf fmt "DUPLICATE_SYMBOLS source:%a source_captured:%a pname:%a@\n" SourceFile.pp
source_file SourceFile.pp source_captured Typ.Procname.pp pname ) ;
source_file SourceFile.pp source_captured Procname.pp pname ) ;
F.pp_print_flush fmt () )
in
if not (List.is_empty duplicate_procs) then output_to_file duplicate_procs
@ -292,7 +290,7 @@ let create_perf_stats_report source_file =
let register_callee ?caller_summary callee_pname =
Option.iter
~f:(fun (summary : Summary.t) ->
summary.callee_pnames <- Typ.Procname.Set.add callee_pname summary.callee_pnames )
summary.callee_pnames <- Procname.Set.add callee_pname summary.callee_pnames )
caller_summary
@ -303,7 +301,7 @@ let get_proc_desc callee_pname =
; lazy (Topl.get_proc_desc callee_pname) ]
type callee = ProcName of Typ.Procname.t | ProcDesc of Procdesc.t
type callee = ProcName of Procname.t | ProcDesc of Procdesc.t
let proc_name_of_callee = function
| ProcName proc_name ->
@ -346,7 +344,7 @@ let analyze_callee ?caller_summary callee =
| None ->
Summary.OnDisk.get callee_pname
else (
EventLogger.log_skipped_pname (F.asprintf "%a" Typ.Procname.pp callee_pname) ;
EventLogger.log_skipped_pname (F.asprintf "%a" Procname.pp callee_pname) ;
Summary.OnDisk.get callee_pname )
in
LocalCache.add callee_pname summ_opt ;

@ -9,18 +9,18 @@ open! IStd
(** Module for on-demand analysis. *)
val get_proc_desc : Typ.Procname.t -> Procdesc.t option
val get_proc_desc : Procname.t -> Procdesc.t option
(** Find a proc desc for the procedure, perhaps loading it from disk. *)
val analyze_proc_desc : caller_summary:Summary.t -> Procdesc.t -> Summary.t option
(** [analyze_proc_desc ~caller_summary callee_pdesc] performs an on-demand analysis of callee_pdesc
triggered during the analysis of caller_summary *)
val analyze_proc_name : caller_summary:Summary.t -> Typ.Procname.t -> Summary.t option
val analyze_proc_name : caller_summary:Summary.t -> Procname.t -> Summary.t option
(** [analyze_proc_name ~caller_summary callee_pname] performs an on-demand analysis of callee_pname
triggered during the analysis of caller_summary *)
val analyze_proc_name_no_caller : Typ.Procname.t -> Summary.t option
val analyze_proc_name_no_caller : Procname.t -> Summary.t option
(** [analyze_proc_name_no_caller callee_pname] performs an on-demand analysis of callee_pname
triggered by the top-level of a cluster checker *)
@ -31,12 +31,12 @@ module LocalCache : sig
val clear : unit -> unit
(** Empty the cache of ondemand results *)
val remove : Typ.Procname.t -> unit
val remove : Procname.t -> unit
(** Remove an element from the cache of ondemand results *)
end
val analyze_file : Exe_env.t -> SourceFile.t -> unit
(** Invoke all the callbacks registered in {!Callbacks} on the given file. *)
val analyze_proc_name_toplevel : Exe_env.t -> Typ.Procname.t -> unit
val analyze_proc_name_toplevel : Exe_env.t -> Procname.t -> unit
(** Invoke all the callbacks registered in {!Callbacks} on the given procedure. *)

@ -74,7 +74,7 @@ module Liveness = struct
astate
let cache_node = ref (Procdesc.Node.dummy Typ.Procname.Linters_dummy_method)
let cache_node = ref (Procdesc.Node.dummy Procname.Linters_dummy_method)
let cache_instr = ref Sil.skip_instr
@ -129,7 +129,7 @@ module Liveness = struct
let add_nullify_instrs summary tenv liveness_inv_map =
let address_taken_vars =
if Typ.Procname.is_java (Summary.get_proc_name summary) then AddressTaken.Domain.empty
if Procname.is_java (Summary.get_proc_name summary) then AddressTaken.Domain.empty
(* can't take the address of a variable in Java *)
else
let initial = AddressTaken.Domain.empty in
@ -236,9 +236,7 @@ end
let do_preanalysis exe_env pdesc =
let summary = Summary.OnDisk.reset pdesc in
let tenv = Exe_env.get_tenv exe_env (Procdesc.get_proc_name pdesc) in
if
Config.function_pointer_specialization
&& not (Typ.Procname.is_java (Procdesc.get_proc_name pdesc))
if Config.function_pointer_specialization && not (Procname.is_java (Procdesc.get_proc_name pdesc))
then FunctionPointerSubstitution.process summary tenv ;
Liveness.process summary tenv ;
AddAbstractionInstructions.process pdesc ;

@ -131,7 +131,7 @@ end = struct
line ;
F.fprintf fmt "PROC: %a LINE: %a@\n"
(Io_infer.Html.pp_proc_link [".."] proc_name)
(Escape.escape_xml (Typ.Procname.to_string proc_name))
(Escape.escape_xml (Procname.to_string proc_name))
(Io_infer.Html.pp_line_link source [".."])
line ;
F.fprintf fmt "<br>PREDS:@\n" ;
@ -174,10 +174,10 @@ end = struct
let source = loc.file in
let nodes = List.sort ~compare:Procdesc.Node.compare (Procdesc.get_nodes pdesc) in
let linenum = loc.Location.line in
let fd, fmt = Io_infer.Html.create source [Typ.Procname.to_filename pname] in
let fd, fmt = Io_infer.Html.create source [Procname.to_filename pname] in
F.fprintf fmt "<center><h1>Procedure %a</h1></center>@\n"
(Io_infer.Html.pp_line_link source
~text:(Some (Escape.escape_xml (Typ.Procname.to_string pname)))
~text:(Some (Escape.escape_xml (Procname.to_string pname)))
[])
linenum ;
pp_node_link_seq [] ~description:true fmt nodes ;
@ -257,7 +257,7 @@ end = struct
match Procdesc.Node.get_kind n with
| Procdesc.Node.Start_node ->
let proc_name = Procdesc.Node.get_proc_name n in
let proc_name_escaped = Escape.escape_xml (Typ.Procname.to_string proc_name) in
let proc_name_escaped = Escape.escape_xml (Procname.to_string proc_name) in
if Summary.OnDisk.get proc_name |> Option.is_some then (
F.pp_print_char fmt ' ' ;
let label = F.asprintf "summary for %s" proc_name_escaped in
@ -309,9 +309,9 @@ end = struct
if is_whitelisted file then (
let pdescs_in_file =
try Hashtbl.find pdescs_in_source file
with Caml.Not_found -> Typ.Procname.Map.empty
with Caml.Not_found -> Procname.Map.empty
in
let pdescs_in_file = Typ.Procname.Map.add proc_name proc_desc pdescs_in_file in
let pdescs_in_file = Procname.Map.add proc_name proc_desc pdescs_in_file in
Hashtbl.replace pdescs_in_source file pdescs_in_file ;
SourceFile.Set.add file files )
else files
@ -324,7 +324,7 @@ end = struct
let pdescs_in_file =
match Hashtbl.find pdescs_in_source file with
| pdescs_map ->
Typ.Procname.Map.bindings pdescs_map |> List.map ~f:snd
Procname.Map.bindings pdescs_map |> List.map ~f:snd
| exception Caml.Not_found ->
[]
in

@ -31,15 +31,15 @@ let log_issue_from_summary severity summary ~node ~session ~loc ~ltr ?extras exn
let procname = attrs.proc_name in
let is_java_generated_method =
match procname with
| Typ.Procname.Java java_pname ->
Typ.Procname.Java.is_generated java_pname
| Procname.Java java_pname ->
Procname.Java.is_generated java_pname
| _ ->
false
in
let is_java_external_package =
match procname with
| Typ.Procname.Java java_pname ->
Typ.Procname.Java.is_external java_pname
| Procname.Java java_pname ->
Procname.Java.is_external java_pname
| _ ->
false
in
@ -73,7 +73,7 @@ let log_issue_deprecated_using_state severity proc_name ?node ?loc ?ltr exn =
L.(die InternalError)
"Trying to report error on procedure %a, but cannot because no summary exists for this \
procedure. Did you mean to log the error on the caller of %a instead?"
Typ.Procname.pp proc_name Typ.Procname.pp proc_name
Procname.pp proc_name Procname.pp proc_name
let checker_exception issue_type error_message =

@ -13,7 +13,7 @@ type log_t = ?ltr:Errlog.loc_trace -> ?extras:Jsonbug_t.extra -> IssueType.t ->
val log_issue_deprecated_using_state :
Exceptions.severity
-> Typ.Procname.t
-> Procname.t
-> ?node:Procdesc.Node.t
-> ?loc:Location.t
-> ?ltr:Errlog.loc_trace
@ -23,7 +23,7 @@ val log_issue_deprecated_using_state :
DEPRECATED as it can create race conditions between checkers. Use log_error/warning instead *)
val log_frontend_issue :
Typ.Procname.t
Procname.t
-> Exceptions.severity
-> Errlog.t
-> loc:Location.t
@ -43,7 +43,7 @@ val log_error_using_state : Summary.t -> exn -> unit
(** Add an error to the given summary using biabduction state (DO NOT USE ELSEWHERE). *)
val log_issue_external :
Typ.Procname.t
Procname.t
-> issue_log:IssueLog.t
-> Exceptions.severity
-> loc:Location.t

@ -13,29 +13,29 @@ open! IStd
(** Abstraction rules discovered *)
type rules
val abstract : Typ.Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
val abstract : Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
(** Abstract a proposition. *)
val abstract_spec :
Typ.Procname.t -> Tenv.t -> Prop.normal BiabductionSummary.spec -> BiabductionSummary.NormSpec.t
Procname.t -> Tenv.t -> Prop.normal BiabductionSummary.spec -> BiabductionSummary.NormSpec.t
(** Normalizes names and applies simplifications, soem of which require looking at both pre and
post. *)
val abstract_junk : Typ.Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
val abstract_junk : Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
(** Check whether the prop contains junk. If it does, and [Config.allowleak] is true, remove the
junk, otherwise raise a Leak exception. *)
val abstract_no_symop : Typ.Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
val abstract_no_symop : Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
(** Abstract a proposition but don't pay a SymOp *)
val get_current_rules : unit -> rules
(** Get the current rules discoveres *)
val lifted_abstract : Typ.Procname.t -> Tenv.t -> Propset.t -> Propset.t
val lifted_abstract : Procname.t -> Tenv.t -> Propset.t -> Propset.t
(** Abstract each proposition in [propset] *)
val remove_redundant_array_elements :
Typ.Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
Procname.t -> Tenv.t -> Prop.normal Prop.t -> Prop.normal Prop.t
(** Remove redundant elements in an array, and check for junk afterwards *)
val reset_current_rules : unit -> unit

@ -89,7 +89,7 @@ val mark_vars_as_undefined :
-> Prop.normal Prop.t
-> ret_exp:Exp.t
-> undefined_actuals_by_ref:Exp.t list
-> Typ.Procname.t
-> Procname.t
-> Annot.Item.t
-> Location.t
-> PredSymb.path_pos

@ -18,7 +18,7 @@ type args =
; path: Paths.Path.t
; ret_id_typ: Ident.t * Typ.t
; args: (Exp.t * Typ.t) list
; proc_name: Typ.Procname.t
; proc_name: Procname.t
; loc: Location.t
; exe_env: Exe_env.t }
@ -29,32 +29,32 @@ type t = args -> ret_typ
type registered = t
(** builtin function names for which we do symbolic execution *)
let builtin_functions = Typ.Procname.Hash.create 4
let builtin_functions = Procname.Hash.create 4
let check_register_populated () =
(* check if BuiltinDefn were loaded before accessing register *)
if Int.equal (Typ.Procname.Hash.length builtin_functions) 0 then
if Int.equal (Procname.Hash.length builtin_functions) 0 then
L.(die InternalError) "Builtins were not initialized"
(** get the symbolic execution handler associated to the builtin function name *)
let get name : t option =
try Some (Typ.Procname.Hash.find builtin_functions name)
try Some (Procname.Hash.find builtin_functions name)
with Caml.Not_found -> check_register_populated () ; None
(** register a builtin [Typ.Procname.t] and symbolic execution handler *)
(** register a builtin [Procname.t] and symbolic execution handler *)
let register proc_name sym_exe_fun : registered =
Typ.Procname.Hash.replace builtin_functions proc_name sym_exe_fun ;
Procname.Hash.replace builtin_functions proc_name sym_exe_fun ;
sym_exe_fun
(** print the functions registered *)
let pp_registered fmt () =
let builtin_names = ref [] in
Typ.Procname.Hash.iter (fun name _ -> builtin_names := name :: !builtin_names) builtin_functions ;
builtin_names := List.sort ~compare:Typ.Procname.compare !builtin_names ;
let pp pname = Format.fprintf fmt "%a@\n" Typ.Procname.pp pname in
Procname.Hash.iter (fun name _ -> builtin_names := name :: !builtin_names) builtin_functions ;
builtin_names := List.sort ~compare:Procname.compare !builtin_names ;
let pp pname = Format.fprintf fmt "%a@\n" Procname.pp pname in
Format.fprintf fmt "Registered builtins:@\n @[" ;
List.iter ~f:pp !builtin_names ;
Format.fprintf fmt "@]@."

@ -17,7 +17,7 @@ type args =
; path: Paths.Path.t
; ret_id_typ: Ident.t * Typ.t
; args: (Exp.t * Typ.t) list
; proc_name: Typ.Procname.t
; proc_name: Procname.t
; loc: Location.t
; exe_env: Exe_env.t }
@ -27,10 +27,10 @@ type t = args -> ret_typ
type registered
val register : Typ.Procname.t -> t -> registered
(** Register a builtin [Typ.Procname.t] and symbolic execution handler *)
val register : Procname.t -> t -> registered
(** Register a builtin [Procname.t] and symbolic execution handler *)
val get : Typ.Procname.t -> t option
val get : Procname.t -> t option
(** Get the symbolic execution handler associated to the builtin function name *)
val print_and_exit : unit -> 'a

@ -647,7 +647,7 @@ let execute_pthread_create ({Builtin.tenv; summary; prop_; path; args; exe_env}
| Exp.Lvar pvar, _ ->
let fun_name = Pvar.get_name pvar in
let fun_string = Mangled.to_string fun_name in
Some (Typ.Procname.from_string_c_fun fun_string)
Some (Procname.from_string_c_fun fun_string)
| Exp.Const (Cfun pname), _ ->
Some pname
| _ ->
@ -660,7 +660,7 @@ let execute_pthread_create ({Builtin.tenv; summary; prop_; path; args; exe_env}
L.d_strln ", skipping call." ;
[(prop_, path)]
| Some pname -> (
L.d_printfln "pthread_create: calling function %a" Typ.Procname.pp pname ;
L.d_printfln "pthread_create: calling function %a" Procname.pp pname ;
match Ondemand.analyze_proc_name ~caller_summary:summary pname with
| None ->
(* no precondition to check, skip *)

@ -13,11 +13,7 @@ open! IStd
(** {2 Join Operators} *)
val pathset_join :
Typ.Procname.t
-> Tenv.t
-> Paths.PathSet.t
-> Paths.PathSet.t
-> Paths.PathSet.t * Paths.PathSet.t
Procname.t -> Tenv.t -> Paths.PathSet.t -> Paths.PathSet.t -> Paths.PathSet.t * Paths.PathSet.t
(** Join two pathsets *)
val proplist_collapse_pre :

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save