From daa5154399a36a813714f591abf21fb4b4b91590 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Wed, 24 Jan 2018 07:25:40 -0800 Subject: [PATCH] [capture] get rid of call graphs Summary: They were constructed for each source file, and then joined into a global call graph, only to get per-file lists of procedures. A tad wasteful. Get this list from cfgs instead. Still record them in `exe_env` for now as changing that code is a whole other beast. One test falls victim of the flakiness of the analysis of recursive functions. Reviewed By: jeremydubreil, mbouaziz Differential Revision: D6324268 fbshipit-source-id: d5ff58f --- infer/src/IR/Cg.ml | 281 ------------------------------ infer/src/IR/Cg.mli | 52 ------ infer/src/IR/Typ.ml | 3 + infer/src/IR/Typ.mli | 2 + infer/src/backend/InferAnalyze.ml | 1 + infer/src/base/DB.ml | 2 +- infer/src/base/DB.mli | 2 +- infer/src/clang/cContext.ml | 6 +- infer/src/clang/cContext.mli | 5 +- infer/src/clang/cFrontend.ml | 13 +- infer/src/clang/cFrontend_decl.ml | 65 ++++--- infer/src/clang/cModule_type.ml | 4 +- infer/src/clang/cTrans.ml | 18 +- infer/src/integration/Driver.ml | 4 +- infer/src/java/jContext.ml | 4 +- infer/src/java/jContext.mli | 5 +- infer/src/java/jFrontend.ml | 13 +- infer/src/java/jFrontend.mli | 6 +- infer/src/java/jMain.ml | 19 +- infer/src/java/jTrans.ml | 10 -- 20 files changed, 68 insertions(+), 447 deletions(-) delete mode 100644 infer/src/IR/Cg.ml delete mode 100644 infer/src/IR/Cg.mli diff --git a/infer/src/IR/Cg.ml b/infer/src/IR/Cg.ml deleted file mode 100644 index 6c39bfbc1..000000000 --- a/infer/src/IR/Cg.ml +++ /dev/null @@ -1,281 +0,0 @@ -(* - * Copyright (c) 2009 - 2013 Monoidics ltd. - * Copyright (c) 2013 - present Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - *) - -(** Module for call graphs *) - -open! IStd -module Hashtbl = Caml.Hashtbl -module L = Logging -module F = Format - -type node = Typ.Procname.t - -type in_out_calls = - { in_calls: int (** total number of in calls transitively *) - ; out_calls: int (** total number of out calls transitively *) } - -type node_info = - { mutable defined: bool (** defined procedure as opposed to just declared *) - ; mutable parents: Typ.Procname.Set.t - ; mutable children: Typ.Procname.Set.t - ; mutable ancestors: Typ.Procname.Set.t option (** ancestors are computed lazily *) - ; mutable heirs: Typ.Procname.Set.t option (** heirs are computed lazily *) - ; mutable recursive_dependents: Typ.Procname.Set.t option - (** recursive dependents are computed lazily *) - ; mutable in_out_calls: in_out_calls option (** calls are computed lazily *) } - -(** Type for call graph *) -type t = - { source: SourceFile.t (** path for the source file *) - ; node_map: node_info Typ.Procname.Hash.t (** map from node to node_info *) } - -let create source = {source; node_map= Typ.Procname.Hash.create 3} - -let add_node g n ~defined = - try - let info = Typ.Procname.Hash.find g.node_map n in - (* defined and disabled only go from false to true - to avoid accidental overwrite to false by calling add_edge *) - if defined then info.defined <- true - with Not_found -> - let info = - { defined - ; parents= Typ.Procname.Set.empty - ; children= Typ.Procname.Set.empty - ; ancestors= None - ; heirs= None - ; recursive_dependents= None - ; in_out_calls= None } - in - Typ.Procname.Hash.add g.node_map n info - - -let remove_node_defined g n = - try - let info = Typ.Procname.Hash.find g.node_map n in - info.defined <- false - with Not_found -> () - - -let add_defined_node g n = add_node g n ~defined:true - -(** Compute the ancestors of the node, if not already computed *) -let compute_ancestors g node = - let todo = ref (Typ.Procname.Set.singleton node) in - let seen = ref Typ.Procname.Set.empty in - let result = ref Typ.Procname.Set.empty in - while not (Typ.Procname.Set.is_empty !todo) do - let current = Typ.Procname.Set.choose !todo in - todo := Typ.Procname.Set.remove current !todo ; - if not (Typ.Procname.Set.mem current !seen) then ( - seen := Typ.Procname.Set.add current !seen ; - let info = Typ.Procname.Hash.find g current in - match info.ancestors with - | Some ancestors -> - result := Typ.Procname.Set.union !result ancestors - | None -> - result := Typ.Procname.Set.union !result info.parents ; - todo := Typ.Procname.Set.union !todo info.parents ) - done ; - !result - - -(** Compute the heirs of the node, if not already computed *) -let compute_heirs g node = - let todo = ref (Typ.Procname.Set.singleton node) in - let seen = ref Typ.Procname.Set.empty in - let result = ref Typ.Procname.Set.empty in - while not (Typ.Procname.Set.is_empty !todo) do - let current = Typ.Procname.Set.choose !todo in - todo := Typ.Procname.Set.remove current !todo ; - if not (Typ.Procname.Set.mem current !seen) then ( - seen := Typ.Procname.Set.add current !seen ; - let info = Typ.Procname.Hash.find g current in - match info.heirs with - | Some heirs -> - result := Typ.Procname.Set.union !result heirs - | None -> - result := Typ.Procname.Set.union !result info.children ; - todo := Typ.Procname.Set.union !todo info.children ) - done ; - !result - - -(** Compute the ancestors of the node, if not pre-computed already *) -let get_ancestors (g: t) node = - let info = Typ.Procname.Hash.find g.node_map node in - match info.ancestors with - | None -> - let ancestors = compute_ancestors g.node_map node in - info.ancestors <- Some ancestors ; - let size = Typ.Procname.Set.cardinal ancestors in - if size > 1000 then - L.(debug Analysis Medium) "%a has %d ancestors@." Typ.Procname.pp node size ; - ancestors - | Some ancestors -> - ancestors - - -(** Compute the heirs of the node, if not pre-computed already *) -let get_heirs (g: t) node = - let info = Typ.Procname.Hash.find g.node_map node in - match info.heirs with - | None -> - let heirs = compute_heirs g.node_map node in - info.heirs <- Some heirs ; - let size = Typ.Procname.Set.cardinal heirs in - if size > 1000 then L.(debug Analysis Medium) "%a has %d heirs@." Typ.Procname.pp node size ; - heirs - | Some heirs -> - heirs - - -let node_defined (g: t) n = - try - let info = Typ.Procname.Hash.find g.node_map n in - info.defined - with Not_found -> false - - -let add_edge g nfrom nto = - add_node g nfrom ~defined:false ; - add_node g nto ~defined:false ; - let info_from = Typ.Procname.Hash.find g.node_map nfrom in - let info_to = Typ.Procname.Hash.find g.node_map nto in - info_from.children <- Typ.Procname.Set.add nto info_from.children ; - info_to.parents <- Typ.Procname.Set.add nfrom info_to.parents - - -(** iterate over the elements of a node_map in node order *) -let node_map_iter f g = - let table = ref [] in - Typ.Procname.Hash.iter (fun node info -> table := (node, info) :: !table) g.node_map ; - let cmp ((n1: Typ.Procname.t), _) ((n2: Typ.Procname.t), _) = Typ.Procname.compare n1 n2 in - List.iter ~f:(fun (n, info) -> f n info) (List.sort ~cmp !table) - - -let get_nodes (g: t) = - let nodes = ref Typ.Procname.Set.empty in - let f node _ = nodes := Typ.Procname.Set.add node !nodes in - node_map_iter f g ; !nodes - - -let compute_calls g node = - { in_calls= Typ.Procname.Set.cardinal (get_ancestors g node) - ; out_calls= Typ.Procname.Set.cardinal (get_heirs g node) } - - -(** Compute the calls of the node, if not pre-computed already *) -let get_calls (g: t) node = - let info = Typ.Procname.Hash.find g.node_map node in - match info.in_out_calls with - | None -> - let calls = compute_calls g node in - info.in_out_calls <- Some calls ; - calls - | Some calls -> - calls - - -let get_all_nodes (g: t) = - let nodes = Typ.Procname.Set.elements (get_nodes g) in - List.map ~f:(fun node -> (node, get_calls g node)) nodes - - -let node_get_num_ancestors g n = (n, Typ.Procname.Set.cardinal (get_ancestors g n)) - -let get_edges (g: t) : ((node * int) * (node * int)) list = - let edges = ref [] in - let f node info = - Typ.Procname.Set.iter - (fun nto -> edges := (node_get_num_ancestors g node, node_get_num_ancestors g nto) :: !edges) - info.children - in - node_map_iter f g ; !edges - - -(** nodes with defined flag, and edges *) -type nodes_and_edges = (node * bool) list * (node * node) list - -(** Return the list of nodes, with defined+disabled flags, and the list of edges *) -let get_nodes_and_edges (g: t) : nodes_and_edges = - let nodes = ref [] in - let edges = ref [] in - let do_children node nto = edges := (node, nto) :: !edges in - let f node info = - nodes := (node, info.defined) :: !nodes ; - Typ.Procname.Set.iter (do_children node) info.children - in - node_map_iter f g ; (!nodes, !edges) - - -(** Return the list of nodes which are defined *) -let get_defined_nodes (g: t) = - let nodes, _ = get_nodes_and_edges g in - let get_node (node, _) = node in - List.map ~f:get_node (List.filter ~f:(fun (_, defined) -> defined) nodes) - - -(** [extend cg1 gc2] extends [cg1] in place with nodes and edges from [gc2]; - undefined nodes become defined if at least one side is. *) -let extend cg_old cg_new = - let nodes, edges = get_nodes_and_edges cg_new in - List.iter ~f:(fun (node, defined) -> add_node cg_old node ~defined) nodes ; - List.iter ~f:(fun (nfrom, nto) -> add_edge cg_old nfrom nto) edges - - -(** Begin support for serialization *) -let callgraph_serializer : (SourceFile.t * nodes_and_edges) Serialization.serializer = - Serialization.create_serializer Serialization.Key.cg - - -(** Load a call graph from a file *) -let load_from_file (filename: DB.filename) : t option = - match Serialization.read_from_file callgraph_serializer filename with - | None -> - None - | Some (source, (nodes, edges)) -> - let g = create source in - List.iter ~f:(fun (node, defined) -> if defined then add_defined_node g node) nodes ; - List.iter ~f:(fun (nfrom, nto) -> add_edge g nfrom nto) edges ; - Some g - - -(** Save a call graph into a file *) -let store_to_file (filename: DB.filename) (call_graph: t) = - Serialization.write_to_file callgraph_serializer filename - ~data:(call_graph.source, get_nodes_and_edges call_graph) - - -let pp_graph_dotty (g: t) fmt = - let nodes_with_calls = get_all_nodes g in - let get_shape (n, _) = if node_defined g n then "box" else "diamond" in - let pp_node fmt (n, _) = F.fprintf fmt "\"%s\"" (Typ.Procname.to_filename n) in - let pp_node_label fmt (n, calls) = - F.fprintf fmt "\"%a | calls=%d %d)\"" Typ.Procname.pp n calls.in_calls calls.out_calls - in - F.fprintf fmt "digraph {@\n" ; - List.iter - ~f:(fun nc -> - F.fprintf fmt "%a [shape=box,label=%a,color=%s,shape=%s]@\n" pp_node nc pp_node_label nc - "red" (get_shape nc) ) - nodes_with_calls ; - List.iter ~f:(fun (s, d) -> F.fprintf fmt "%a -> %a@\n" pp_node s pp_node d) (get_edges g) ; - F.fprintf fmt "}@." - - -(** Print the call graph as a dotty file. *) -let save_call_graph_dotty source (g: t) = - let fname_dot = - DB.Results_dir.path_to_filename (DB.Results_dir.Abs_source_dir source) ["call_graph.dot"] - in - let outc = Out_channel.create (DB.filename_to_string fname_dot) in - let fmt = F.formatter_of_out_channel outc in - pp_graph_dotty g fmt ; Out_channel.close outc diff --git a/infer/src/IR/Cg.mli b/infer/src/IR/Cg.mli deleted file mode 100644 index 298b8de24..000000000 --- a/infer/src/IR/Cg.mli +++ /dev/null @@ -1,52 +0,0 @@ -(* - * Copyright (c) 2009 - 2013 Monoidics ltd. - * Copyright (c) 2013 - present Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - *) - -open! IStd - -(** Module for call graphs *) - -(** the type of a call graph *) -type t - -(** A call graph consists of a set of nodes (Typ.Procname.t), and edges between them. - A node can be defined or undefined (to represent whether we have code for it). - In an edge from [n1] to [n2], indicating that [n1] calls [n2], - [n1] is the parent and [n2] is the child. - Node [n1] is dependent on [n2] if there is a path from [n1] to [n2] - using the child relationship. *) - -val add_edge : t -> Typ.Procname.t -> Typ.Procname.t -> unit -(** [add_edge cg f t] adds an edge from [f] to [t] in the call graph [cg]. - The nodes are also added as undefined, unless already present. *) - -val add_defined_node : t -> Typ.Procname.t -> unit -(** Add a node to the call graph as defined *) - -val create : SourceFile.t -> t -(** Create an empty call graph *) - -val extend : t -> t -> unit -(** [extend cg1 gc2] extends [cg1] in place with nodes and edges from [gc2]; - undefined nodes become defined if at least one side is. *) - -val get_defined_nodes : t -> Typ.Procname.t list -(** Return the list of nodes which are defined *) - -val load_from_file : DB.filename -> t option -(** Load a call graph from a file *) - -val remove_node_defined : t -> Typ.Procname.t -> unit -(** Remove the defined flag from a node, if it exists. *) - -val save_call_graph_dotty : SourceFile.t -> t -> unit -(** Print the call graph as a dotty file. *) - -val store_to_file : DB.filename -> t -> unit -(** Save a call graph into a file *) diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index 28f88a15a..5f502c7da 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -1109,6 +1109,9 @@ module Procname = struct let serialize pname = let default () = Sqlite3.Data.TEXT (to_filename pname) in Base.Hashtbl.find_or_add pname_to_key pname ~default + + + let clear_cache () = Base.Hashtbl.clear pname_to_key end module SQLiteList = SqliteUtils.MarshalledData (struct diff --git a/infer/src/IR/Typ.mli b/infer/src/IR/Typ.mli index d585d3356..dfed755bc 100644 --- a/infer/src/IR/Typ.mli +++ b/infer/src/IR/Typ.mli @@ -392,6 +392,8 @@ module Procname : sig module SQLite : sig val serialize : t -> Sqlite3.Data.t + + val clear_cache : unit -> unit end module SQLiteList : SqliteUtils.Data with type t = t list diff --git a/infer/src/backend/InferAnalyze.ml b/infer/src/backend/InferAnalyze.ml index a571f86b9..a9e45cfbd 100644 --- a/infer/src/backend/InferAnalyze.ml +++ b/infer/src/backend/InferAnalyze.ml @@ -17,6 +17,7 @@ module F = Format let analyze_exe_env_tasks cluster exe_env : Tasks.t = L.progressbar_file () ; Specs.clear_spec_tbl () ; + Typ.Procname.SQLite.clear_cache () ; Random.self_init () ; Tasks.create [ (fun () -> diff --git a/infer/src/base/DB.ml b/infer/src/base/DB.ml index 23bf9b5b8..a9775f945 100644 --- a/infer/src/base/DB.ml +++ b/infer/src/base/DB.ml @@ -60,7 +60,7 @@ type source_dir = string [@@deriving compare] (** expose the source dir as a string *) let source_dir_to_string source_dir = source_dir -(** get the path to an internal file with the given extention (.cg, .tenv) *) +(** get the path to an internal file with the given extention (.tenv, ...) *) let source_dir_get_internal_file source_dir extension = let source_dir_name = append_crc_cutoff (Caml.Filename.remove_extension (Filename.basename source_dir)) diff --git a/infer/src/base/DB.mli b/infer/src/base/DB.mli index b40a12491..a54a00c0a 100644 --- a/infer/src/base/DB.mli +++ b/infer/src/base/DB.mli @@ -95,7 +95,7 @@ val source_dir_to_string : source_dir -> string (** expose the source dir as a string *) val source_dir_get_internal_file : source_dir -> string -> filename -(** get the path to an internal file with the given extention (.cg, .tenv) *) +(** get the path to an internal file with the given extention (.tenv, ...) *) val source_dir_from_source_file : SourceFile.t -> source_dir (** get the source directory corresponding to a source file *) diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index f62628f1e..cfcdc61fe 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -28,7 +28,6 @@ type str_node_map = (string, Procdesc.Node.t) Hashtbl.t type t = { translation_unit_context: CFrontend_config.translation_unit_context ; tenv: Tenv.t - ; cg: Cg.t ; cfg: Cfg.t ; procdesc: Procdesc.t ; is_objc_method: bool @@ -41,11 +40,10 @@ type t = ; label_map: str_node_map ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t } -let create_context translation_unit_context tenv cg cfg procdesc curr_class return_param_typ +let create_context translation_unit_context tenv cfg procdesc curr_class return_param_typ is_objc_method outer_context vars_to_destroy = { translation_unit_context ; tenv - ; cg ; cfg ; procdesc ; curr_class @@ -57,8 +55,6 @@ let create_context translation_unit_context tenv cg cfg procdesc curr_class retu ; vars_to_destroy } -let get_cg context = context.cg - let get_procdesc context = context.procdesc let rec is_objc_method context = diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index f3eece739..34a9d47aa 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -22,7 +22,6 @@ type str_node_map = (string, Procdesc.Node.t) Caml.Hashtbl.t type t = { translation_unit_context: CFrontend_config.translation_unit_context ; tenv: Tenv.t - ; cg: Cg.t ; cfg: Cfg.t ; procdesc: Procdesc.t ; is_objc_method: bool @@ -39,8 +38,6 @@ type t = val get_procdesc : t -> Procdesc.t -val get_cg : t -> Cg.t - val get_curr_class : t -> curr_class val get_curr_class_typename : t -> Typ.Name.t @@ -50,7 +47,7 @@ val get_curr_class_decl_ptr : curr_class -> Clang_ast_t.pointer val is_objc_method : t -> bool val create_context : - CFrontend_config.translation_unit_context -> Tenv.t -> Cg.t -> Cfg.t -> Procdesc.t -> curr_class + CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.t -> Procdesc.t -> curr_class -> Typ.t option -> bool -> t option -> Clang_ast_t.decl list StmtMap.t -> t val add_block_static_var : t -> Typ.Procname.t -> Pvar.t * Typ.t -> unit diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index 5be5da6b5..38b8c7bb4 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -20,13 +20,12 @@ let compute_icfg trans_unit_ctx tenv ast = | Clang_ast_t.TranslationUnitDecl (_, decl_list, _, _) -> CFrontend_config.global_translation_unit_decls := decl_list ; L.(debug Capture Verbose) "@\n Start creating icfg@\n" ; - let cg = Cg.create trans_unit_ctx.CFrontend_config.source_file in let cfg = Cfg.create () in List.iter - ~f:(CFrontend_declImpl.translate_one_declaration trans_unit_ctx tenv cg cfg `DeclTraversal) + ~f:(CFrontend_declImpl.translate_one_declaration trans_unit_ctx tenv cfg `DeclTraversal) decl_list ; L.(debug Capture Verbose) "@\n Finished creating icfg@\n" ; - (cg, cfg) + cfg | _ -> assert false @@ -46,25 +45,21 @@ let do_source_file (translation_unit_context: CFrontend_config.translation_unit_ let source_file = translation_unit_context.CFrontend_config.source_file in L.(debug Capture Verbose) "@\n Start building call/cfg graph for '%a'....@\n" SourceFile.pp source_file ; - let call_graph, cfg = compute_icfg translation_unit_context tenv ast in + let cfg = compute_icfg translation_unit_context tenv ast in L.(debug Capture Verbose) "@\n End building call/cfg graph for '%a'.@\n" SourceFile.pp source_file ; (* This part below is a boilerplate in every frontends. *) (* This could be moved in the cfg_infer module *) let source_dir = DB.source_dir_from_source_file source_file in let tenv_file = DB.source_dir_get_internal_file source_dir ".tenv" in - let cg_file = DB.source_dir_get_internal_file source_dir ".cg" in NullabilityPreanalysis.analysis cfg tenv ; - Cg.store_to_file cg_file call_graph ; Cfg.store source_file cfg ; Tenv.sort_fields_tenv tenv ; Tenv.store_to_file tenv_file tenv ; if Config.debug_mode then Cfg.check_cfg_connectedness cfg ; if Config.debug_mode || Config.testing_mode || Config.frontend_tests || Option.is_some Config.icfg_dotty_outfile - then ( - Dotty.print_icfg_dotty source_file cfg ; - Cg.save_call_graph_dotty source_file call_graph ) ; + then Dotty.print_icfg_dotty source_file cfg ; L.(debug Capture Verbose) "%a" Cfg.pp_proc_signatures cfg ; let procedures_translated_summary = EventLogger.ProceduresTranslatedSummary diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 0859e4023..065d0b0cd 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -68,8 +68,8 @@ let protect ~f ~recover ~pp_context (trans_unit_ctx: CFrontend_config.translatio module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFrontend = struct let model_exists procname = Specs.summary_exists_in_models procname && not Config.models_mode - (* Translates the method/function's body into nodes of the cfg. *) - let add_method ?(is_destructor_wrapper= false) trans_unit_ctx tenv cg cfg class_decl_opt procname + (** Translates the method/function's body into nodes of the cfg. *) + let add_method ?(is_destructor_wrapper= false) trans_unit_ctx tenv cfg class_decl_opt procname body has_return_param is_objc_method outer_context_opt extra_instrs = L.(debug Capture Verbose) "@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Typ.Procname.pp procname ; @@ -86,7 +86,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron | procdesc when Procdesc.is_defined procdesc && not (model_exists procname) -> let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in let context = - CContext.create_context trans_unit_ctx tenv cg cfg procdesc class_decl_opt + CContext.create_context trans_unit_ctx tenv cfg procdesc class_decl_opt has_return_param is_objc_method outer_context_opt vars_to_destroy in let start_node = Procdesc.get_start_node procdesc in @@ -100,8 +100,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron let proc_attributes = Procdesc.get_attributes procdesc in Procdesc.Node.add_locals_ret_declaration start_node proc_attributes (Procdesc.get_locals procdesc) ; - Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ; - Cg.add_defined_node (CContext.get_cg context) (Procdesc.get_proc_name procdesc) + Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] | _ -> () | exception Not_found -> @@ -110,7 +109,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron protect ~f ~recover ~pp_context trans_unit_ctx - let function_decl trans_unit_ctx tenv cfg cg func_decl block_data_opt = + let function_decl trans_unit_ctx tenv cfg func_decl block_data_opt = let captured_vars, outer_context_opt = match block_data_opt with | Some (outer_context, _, _, captured_vars) -> @@ -129,14 +128,14 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron if CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] captured_vars false then - add_method trans_unit_ctx tenv cg cfg CContext.ContextNoCls procname body + add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body return_param_typ_opt false outer_context_opt extra_instrs | None -> () let process_method_decl ?(set_objc_accessor_attr= false) ?(is_destructor= false) trans_unit_ctx - tenv cg cfg curr_class meth_decl ~is_objc = + tenv cfg curr_class meth_decl ~is_objc = let ms, body_opt, extra_instrs = CMethod_trans.method_signature_of_decl trans_unit_ctx tenv meth_decl None in @@ -154,7 +153,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron if CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv ms [body] [] is_objc_inst_method then - add_method trans_unit_ctx tenv cg cfg curr_class procname body return_param_typ_opt + add_method trans_unit_ctx tenv cfg curr_class procname body return_param_typ_opt is_objc None extra_instrs ~is_destructor_wrapper:true ; let new_method_name = Config.clang_inner_destructor_prefix ^ Typ.Procname.get_method procname @@ -170,8 +169,8 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron if CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx cfg tenv ms' [body] [] is_objc_inst_method then - add_method trans_unit_ctx tenv cg cfg curr_class procname' body return_param_typ_opt - is_objc None extra_instrs ~is_destructor_wrapper:false + add_method trans_unit_ctx tenv cfg curr_class procname' body return_param_typ_opt is_objc + None extra_instrs ~is_destructor_wrapper:false | None -> if set_objc_accessor_attr then ignore @@ -179,7 +178,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron [] [] is_objc_inst_method) - let process_property_implementation trans_unit_ctx tenv cg cfg curr_class + let process_property_implementation trans_unit_ctx tenv cfg curr_class obj_c_property_impl_decl_info = let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in match CAst_utils.get_decl_opt_with_decl_ref property_decl_opt with @@ -187,8 +186,8 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron let process_accessor pointer = match CAst_utils.get_decl_opt_with_decl_ref pointer with | Some (ObjCMethodDecl _ as dec) -> - process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cg cfg - curr_class dec ~is_objc:true + process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cfg curr_class + dec ~is_objc:true | _ -> () in @@ -198,18 +197,18 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron () - let process_one_method_decl trans_unit_ctx tenv cg cfg curr_class dec = + let process_one_method_decl trans_unit_ctx tenv cfg curr_class dec = let open Clang_ast_t in match dec with | CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _ -> - process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:false + process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_objc:false | CXXDestructorDecl _ -> - process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:false + process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_objc:false ~is_destructor:true | ObjCMethodDecl _ -> - process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:true + process_method_decl trans_unit_ctx tenv cfg curr_class dec ~is_objc:true | ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) -> - process_property_implementation trans_unit_ctx tenv cg cfg curr_class + process_property_implementation trans_unit_ctx tenv cfg curr_class obj_c_property_impl_decl_info | EmptyDecl _ | ObjCIvarDecl _ | ObjCPropertyDecl _ -> () @@ -220,8 +219,8 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron () - let process_methods trans_unit_ctx tenv cg cfg curr_class decl_list = - List.iter ~f:(process_one_method_decl trans_unit_ctx tenv cg cfg curr_class) decl_list + let process_methods trans_unit_ctx tenv cfg curr_class decl_list = + List.iter ~f:(process_one_method_decl trans_unit_ctx tenv cfg curr_class) decl_list (** Given REVERSED list of method qualifiers (method_name::class_name::rest_quals), return @@ -287,40 +286,38 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron (* Translate one global declaration *) - let rec translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context dec = + let rec translate_one_declaration trans_unit_ctx tenv cfg decl_trans_context dec = let open Clang_ast_t in (* each procedure has different scope: start names from id 0 *) Ident.NameGenerator.reset () ; - let translate dec = - translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context dec - in + let translate dec = translate_one_declaration trans_unit_ctx tenv cfg decl_trans_context dec in ( if should_translate_decl trans_unit_ctx dec decl_trans_context then let dec_ptr = (Clang_ast_proj.get_decl_tuple dec).di_pointer in match dec with | FunctionDecl (_, _, _, _) -> - function_decl trans_unit_ctx tenv cfg cg dec None + function_decl trans_unit_ctx tenv cfg dec None | ObjCInterfaceDecl (_, _, decl_list, _, _) -> let curr_class = CContext.ContextClsDeclPtr dec_ptr in ignore (ObjcInterface_decl.interface_declaration CType_decl.qual_type_to_sil_type tenv dec) ; - process_methods trans_unit_ctx tenv cg cfg curr_class decl_list + process_methods trans_unit_ctx tenv cfg curr_class decl_list | ObjCProtocolDecl (_, _, decl_list, _, _) -> let curr_class = CContext.ContextClsDeclPtr dec_ptr in ignore (ObjcProtocol_decl.protocol_decl CType_decl.qual_type_to_sil_type tenv dec) ; - process_methods trans_unit_ctx tenv cg cfg curr_class decl_list + process_methods trans_unit_ctx tenv cfg curr_class decl_list | ObjCCategoryDecl (_, _, decl_list, _, _) -> let curr_class = CContext.ContextClsDeclPtr dec_ptr in ignore (ObjcCategory_decl.category_decl CType_decl.qual_type_to_sil_type tenv dec) ; - process_methods trans_unit_ctx tenv cg cfg curr_class decl_list + process_methods trans_unit_ctx tenv cfg curr_class decl_list | ObjCCategoryImplDecl (_, _, decl_list, _, _) -> let curr_class = CContext.ContextClsDeclPtr dec_ptr in ignore (ObjcCategory_decl.category_impl_decl CType_decl.qual_type_to_sil_type tenv dec) ; - process_methods trans_unit_ctx tenv cg cfg curr_class decl_list + process_methods trans_unit_ctx tenv cfg curr_class decl_list | ObjCImplementationDecl (_, _, decl_list, _, _) -> let curr_class = CContext.ContextClsDeclPtr dec_ptr in let qual_type_to_sil_type = CType_decl.qual_type_to_sil_type in ignore (ObjcInterface_decl.interface_impl_declaration qual_type_to_sil_type tenv dec) ; - process_methods trans_unit_ctx tenv cg cfg curr_class decl_list + process_methods trans_unit_ctx tenv cfg curr_class decl_list | CXXMethodDecl (decl_info, _, _, _, _) | CXXConstructorDecl (decl_info, _, _, _, _) | CXXConversionDecl (decl_info, _, _, _, _) @@ -332,7 +329,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron match class_decl with | (Some CXXRecordDecl _ | Some ClassTemplateSpecializationDecl _) when Config.cxx -> let curr_class = CContext.ContextClsDeclPtr parent_ptr in - process_methods trans_unit_ctx tenv cg cfg curr_class [dec] + process_methods trans_unit_ctx tenv cfg curr_class [dec] | Some dec -> L.(debug Capture Verbose) "Methods of %s skipped@\n" @@ -364,8 +361,8 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron in let body = Clang_ast_t.DeclStmt (stmt_info, [], [dec]) in ignore (CMethod_trans.create_local_procdesc trans_unit_ctx cfg tenv ms [body] [] false) ; - add_method trans_unit_ctx tenv cg cfg CContext.ContextNoCls procname body None false - None [] + add_method trans_unit_ctx tenv cfg CContext.ContextNoCls procname body None false None + [] (* Note that C and C++ records are treated the same way Skip translating implicit struct declarations, unless they have full definition (which happens with C++ lambdas) *) diff --git a/infer/src/clang/cModule_type.ml b/infer/src/clang/cModule_type.ml index 706555d44..68fa4724d 100644 --- a/infer/src/clang/cModule_type.ml +++ b/infer/src/clang/cModule_type.ml @@ -29,10 +29,10 @@ end module type CFrontend = sig val function_decl : - CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.t -> Cg.t -> Clang_ast_t.decl + CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.t -> Clang_ast_t.decl -> block_data option -> unit val translate_one_declaration : - CFrontend_config.translation_unit_context -> Tenv.t -> Cg.t -> Cfg.t -> decl_trans_context + CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.t -> decl_trans_context -> Clang_ast_t.decl -> unit end diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index d0ee5afa7..94dad9aba 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -190,8 +190,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let open CContext in (* translation will reset Ident counter, save it's state and restore it afterwards *) let ident_state = Ident.NameGenerator.get_current () in - F.translate_one_declaration context.translation_unit_context context.tenv context.cg - context.cfg `Translation decl ; + F.translate_one_declaration context.translation_unit_context context.tenv context.cfg + `Translation decl ; Ident.NameGenerator.set_current ident_state @@ -1009,16 +1009,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let res_trans_to_parent = PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si all_res_trans in - let add_cg_edge callee_pname = Cg.add_edge context.CContext.cg procname callee_pname in - Option.iter ~f:add_cg_edge callee_pname_opt ; {res_trans_to_parent with exps= res_trans_call.exps} and cxx_method_construct_call_trans trans_state_pri result_trans_callee params_stmt si function_type is_cpp_call_virtual extra_res_trans = - let open CContext in let context = trans_state_pri.context in - let procname = Procdesc.get_proc_name context.procdesc in let sil_loc = CLocation.get_sil_location si context in (* first for method address, second for 'this' expression and other parameters *) assert (List.length result_trans_callee.exps >= 1) ; @@ -1056,7 +1052,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let result_trans_to_parent = PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname si all_res_trans in - Cg.add_edge context.CContext.cg procname callee_pname ; {result_trans_to_parent with exps= res_trans_call.exps} @@ -1244,7 +1239,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let is_virtual = CMethod_trans.equal_method_call_type method_call_type CMethod_trans.MCVirtual in - Cg.add_edge context.CContext.cg procname callee_name ; let call_flags = {CallFlags.default with CallFlags.cf_virtual= is_virtual} in let method_sil = Exp.Const (Const.Cfun callee_name) in let res_trans_call = @@ -2607,9 +2601,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let qual_type = expr_info.Clang_ast_t.ei_qual_type in let block_pname = CProcname.mk_fresh_block_procname procname in let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in - (* We need to set the explicit dependency between the newly created block and the *) - (* defining procedure. We add an edge in the call graph.*) - Cg.add_edge context.cg procname block_pname ; let captured_block_vars = block_decl_info.Clang_ast_t.bdi_captured_variables in let captureds = CVar_decl.captured_vars_from_block_info context stmt_info.Clang_ast_t.si_source_range @@ -2618,7 +2609,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let ids_instrs = List.map ~f:assign_captured_var captureds in let ids, instrs = List.unzip ids_instrs in let block_data = (context, qual_type, block_pname, captureds) in - F.function_decl context.translation_unit_context context.tenv context.cfg context.cg decl + F.function_decl context.translation_unit_context context.tenv context.cfg decl (Some block_data) ; let captured_vars = List.map2_exn ~f:(fun id (pvar, typ) -> (Exp.Var id, pvar, typ)) ids captureds @@ -2637,9 +2628,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let procname = Procdesc.get_proc_name context.procdesc in let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl in let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in - (* We need to set the explicit dependency between the newly created lambda and the *) - (* defining procedure. We add an edge in the call graph.*) - Cg.add_edge context.cg procname lambda_pname ; let make_captured_tuple (pvar, typ) = (Exp.Lvar pvar, pvar, typ) in let get_captured_pvar_typ decl_ref = CVar_decl.sil_var_of_captured_var decl_ref context stmt_info.Clang_ast_t.si_source_range diff --git a/infer/src/integration/Driver.ml b/infer/src/integration/Driver.ml index ba4c22b0c..bfa8e6dd2 100644 --- a/infer/src/integration/Driver.ml +++ b/infer/src/integration/Driver.ml @@ -90,9 +90,7 @@ let clean_results_dir () = ResultsDatabase.database_filename ^ "-shm" ; ResultsDatabase.database_filename ^ "-wal" ] in - let suffixes_to_delete = - ".txt" :: ".csv" :: ".json" :: (if Config.flavors then [] else [".cg"]) - in + let suffixes_to_delete = [".txt"; ".csv"; ".json"] in fun name -> (* Keep the JSON report *) not (String.equal (Filename.basename name) Config.report_json) diff --git a/infer/src/java/jContext.ml b/infer/src/java/jContext.ml index acdc80c3c..9d2f4d084 100644 --- a/infer/src/java/jContext.ml +++ b/infer/src/java/jContext.ml @@ -17,7 +17,7 @@ module NodeTbl = Procdesc.NodeHash type jump_kind = Next | Jump of int | Exit (** Translation data *) -type icfg = {tenv: Tenv.t; cg: Cg.t; cfg: Cfg.t} +type icfg = {tenv: Tenv.t; cfg: Cfg.t} type t = { icfg: icfg @@ -42,8 +42,6 @@ let create_context icfg procdesc impl cn source_file program = ; program } -let get_cg context = context.icfg.cg - let get_tenv context = context.icfg.tenv let set_var_map context var_map = context.var_map <- var_map diff --git a/infer/src/java/jContext.mli b/infer/src/java/jContext.mli index e9cd5cfd8..c84b86c7a 100644 --- a/infer/src/java/jContext.mli +++ b/infer/src/java/jContext.mli @@ -22,7 +22,7 @@ module NodeTbl : Caml.Hashtbl.S with type key = Procdesc.Node.t (** data structure for saving the three structures tht contain the intermediate representation of a file: the type environment, the control graph and the control flow graph *) -type icfg = {tenv: Tenv.t; cg: Cg.t; cfg: Cfg.t} +type icfg = {tenv: Tenv.t; cfg: Cfg.t} (** data structure for storing the context elements. *) type t = private @@ -43,9 +43,6 @@ val create_context : val get_tenv : t -> Tenv.t (** returns the type environment that corresponds to the current file. *) -val get_cg : t -> Cg.t -(** returns the control graph that corresponds to the current file. *) - val add_if_jump : t -> Procdesc.Node.t -> int -> unit (** adds to the context the line that an if-node will jump to *) diff --git a/infer/src/java/jFrontend.ml b/infer/src/java/jFrontend.ml index 524f20c93..0682ae323 100644 --- a/infer/src/java/jFrontend.ml +++ b/infer/src/java/jFrontend.ml @@ -150,14 +150,13 @@ let create_icfg source_file linereader program icfg cn node = try (* each procedure has different scope: start names from id 0 *) Ident.NameGenerator.reset () ; - ( match m with + match m with | Javalib.AbstractMethod am -> ignore (JTrans.create_am_procdesc source_file program icfg am proc_name) | Javalib.ConcreteMethod cm when JTrans.is_java_native cm -> ignore (JTrans.create_native_procdesc source_file program icfg cm proc_name) | Javalib.ConcreteMethod cm -> - add_cmethod source_file program linereader icfg cm proc_name ) ; - Cg.add_defined_node icfg.JContext.cg proc_name + add_cmethod source_file program linereader icfg cm proc_name with JBasics.Class_structure_error _ -> L.internal_error "create_icfg raised JBasics.Class_structure_error on %a@." Typ.Procname.pp proc_name @@ -192,7 +191,7 @@ let should_capture classes package_opt source_basename node = In the standard - mode, it translated all the classes that correspond to this source file. *) let compute_source_icfg linereader classes program tenv source_basename package_opt source_file = - let icfg = {JContext.cg= Cg.create source_file; JContext.cfg= Cfg.create (); JContext.tenv} in + let icfg = {JContext.cfg= Cfg.create (); tenv} in let select test procedure cn node = if test node then try procedure cn node with Bir.Subroutine -> () in @@ -203,11 +202,11 @@ let compute_source_icfg linereader classes program tenv source_basename package_ (create_icfg source_file linereader program icfg)) (JClasspath.get_classmap program) in - (icfg.JContext.cg, icfg.JContext.cfg) + icfg.JContext.cfg let compute_class_icfg source_file linereader program tenv node = - let icfg = {JContext.cg= Cg.create source_file; JContext.cfg= Cfg.create (); JContext.tenv} in + let icfg = {JContext.cfg= Cfg.create (); tenv} in ( try create_icfg source_file linereader program icfg (Javalib.get_name node) node with Bir.Subroutine -> () ) ; - (icfg.JContext.cg, icfg.JContext.cfg) + icfg.JContext.cfg diff --git a/infer/src/java/jFrontend.mli b/infer/src/java/jFrontend.mli index 8967e44bf..1eb9b2f45 100644 --- a/infer/src/java/jFrontend.mli +++ b/infer/src/java/jFrontend.mli @@ -22,10 +22,10 @@ val is_classname_cached : JBasics.class_name -> bool val compute_source_icfg : Printer.LineReader.t -> JBasics.ClassSet.t -> JClasspath.program -> Tenv.t -> string - -> string option -> SourceFile.t -> Cg.t * Cfg.t -(** [compute_icfg linereader classes program tenv source_basename source_file] create the call graph and control flow graph for the file [source_file] by translating all the classes in [program] originating from [source_file] *) + -> string option -> SourceFile.t -> Cfg.t +(** [compute_cfg linereader classes program tenv source_basename source_file] create the control flow graph for the file [source_file] by translating all the classes in [program] originating from [source_file] *) val compute_class_icfg : SourceFile.t -> Printer.LineReader.t -> JClasspath.program -> Tenv.t - -> JCode.jcode Javalib.interface_or_class -> Cg.t * Cfg.t + -> JCode.jcode Javalib.interface_or_class -> Cfg.t (** Compute the CFG for a class *) diff --git a/infer/src/java/jMain.ml b/infer/src/java/jMain.ml index b4d30cd71..ad799cfb6 100644 --- a/infer/src/java/jMain.ml +++ b/infer/src/java/jMain.ml @@ -28,14 +28,10 @@ let init_global_state source_file = JContext.reset_exn_node_table () -let store_icfg source_file cg cfg = +let store_icfg source_file cfg = let source_dir = DB.source_dir_from_source_file source_file in - let cg_file = DB.source_dir_get_internal_file source_dir ".cg" in - Cg.store_to_file cg_file cg ; Cfg.store source_file cfg ; - if Config.debug_mode || Config.frontend_tests then ( - Dotty.print_icfg_dotty source_file cfg ; - Cg.save_call_graph_dotty source_file cg ) ; + if Config.debug_mode || Config.frontend_tests then Dotty.print_icfg_dotty source_file cfg ; (* NOTE: nothing should be written to source_dir after this *) DB.mark_file_updated (DB.source_dir_to_string source_dir) @@ -44,11 +40,11 @@ let store_icfg source_file cg cfg = (* environment are obtained and saved. *) let do_source_file linereader classes program tenv source_basename package_opt source_file = L.(debug Capture Medium) "@\nfilename: %a (%s)@." SourceFile.pp source_file source_basename ; - let call_graph, cfg = + let cfg = JFrontend.compute_source_icfg linereader classes program tenv source_basename package_opt source_file in - store_icfg source_file call_graph cfg + store_icfg source_file cfg let capture_libs linereader program tenv = @@ -61,11 +57,8 @@ let capture_libs linereader program tenv = | Javalib.JClass _ -> let fake_source_file = SourceFile.from_abs_path (JFrontend.path_of_cached_classname cn) in init_global_state fake_source_file ; - let call_graph, cfg = - JFrontend.compute_class_icfg fake_source_file linereader program tenv node - in - store_icfg fake_source_file call_graph cfg ; - JFrontend.cache_classname cn + let cfg = JFrontend.compute_class_icfg fake_source_file linereader program tenv node in + store_icfg fake_source_file cfg ; JFrontend.cache_classname cn in JBasics.ClassMap.iter (capture_class tenv) (JClasspath.get_classmap program) diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 3bf81e5ce..72845469f 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -759,7 +759,6 @@ let assume_not_null loc sil_expr = let instruction (context: JContext.t) pc instr : translation = let tenv = JContext.get_tenv context in - let cg = JContext.get_cg context in let program = context.program in let proc_name = Procdesc.get_proc_name context.procdesc in let ret_var = Pvar.get_ret_pvar proc_name in @@ -904,8 +903,6 @@ let instruction (context: JContext.t) pc instr : translation = let instrs = new_instr :: call_instrs @ [set_instr] in let node_kind = create_node_kind constr_procname in let node = create_node node_kind instrs in - let caller_procname = Procdesc.get_proc_name context.procdesc in - Cg.add_edge cg caller_procname constr_procname ; Instr node | JBir.NewArray (var, vt, expr_list) -> let builtin_new_array = Exp.Const (Const.Cfun BuiltinDecl.__new_array) in @@ -939,12 +936,9 @@ let instruction (context: JContext.t) pc instr : translation = in let node_kind = create_node_kind callee_procname in let call_node = create_node node_kind (instrs @ call_instrs) in - let caller_procname = Procdesc.get_proc_name context.procdesc in - Cg.add_edge cg caller_procname callee_procname ; Instr call_node | JBir.InvokeVirtual (var_opt, obj, call_kind, ms, args) -> ( - let caller_procname = Procdesc.get_proc_name context.procdesc in let instrs, sil_obj_expr, sil_obj_type = expression context pc obj in let create_call_node cn invoke_kind = let callee_procname, call_instrs = @@ -954,7 +948,6 @@ let instruction (context: JContext.t) pc instr : translation = in let node_kind = create_node_kind callee_procname in let call_node = create_node node_kind (instrs @ call_instrs) in - Cg.add_edge cg caller_procname callee_procname ; call_node in let trans_virtual_call original_cn invoke_kind = @@ -988,9 +981,6 @@ let instruction (context: JContext.t) pc instr : translation = in let node_kind = create_node_kind callee_procname in let call_node = create_node node_kind (instrs @ call_instrs) in - let procdesc = context.procdesc in - let caller_procname = Procdesc.get_proc_name procdesc in - Cg.add_edge cg caller_procname callee_procname ; Instr call_node | JBir.Check JBir.CheckNullPointer expr when Config.tracing && is_this expr -> (* TODO #6509339: refactor the boilerplate code in the translation of JVM checks *)