[exe_env] do not record the call graph in the execution environment

Summary:
Last piece of significant logic relying on the call graph: the execution
environment. Mostly carve out the logic to detect duplicate symbols to not rely
on the call graph.

Also make the keys of the `file_map` be source files, because not having the
"cg filename" makes it harder otherwise.

Reviewed By: sblackshear

Differential Revision: D6621196

fbshipit-source-id: cab50ba
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 1d3e0741ac
commit f2029af50a

@ -9,6 +9,7 @@
open! IStd
open! PVariant
module F = Format
module L = Logging
(** Module to register and invoke callbacks *)
@ -86,13 +87,42 @@ let iterate_cluster_callbacks all_procs exe_env get_proc_desc =
!cluster_callbacks
let dump_duplicate_procs (exe_env: Exe_env.t) procs =
let duplicate_procs =
List.filter_map procs ~f:(fun pname ->
match Exe_env.get_proc_desc exe_env pname with
| Some pdesc when (* defined in the current file *) Procdesc.is_defined pdesc -> (
match Attributes.load pname with
| Some {source_file_captured; loc}
when (* defined in another file *)
not (SourceFile.equal exe_env.source_file source_file_captured)
&& (* really defined in the current file and not in an include *)
SourceFile.equal exe_env.source_file loc.file ->
Some (pname, source_file_captured)
| _ ->
None )
| _ ->
None )
in
let output_to_file duplicate_procs =
Out_channel.with_file (Config.results_dir ^/ Config.duplicates_filename)
~append:true ~perm:0o666 ~f:(fun outc ->
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@."
SourceFile.pp exe_env.source_file SourceFile.pp source_captured Typ.Procname.pp pname
) )
in
if not (List.is_empty duplicate_procs) then output_to_file duplicate_procs
(** Invoke all procedure and cluster callbacks on a given environment. *)
let iterate_callbacks (exe_env: Exe_env.t) =
let saved_language = !Config.curr_language in
let get_proc_desc proc_name =
match Exe_env.get_proc_desc exe_env proc_name with
| Some pdesc ->
Some pdesc
| Some _ as pdesc_opt ->
pdesc_opt
| None ->
Option.map ~f:Specs.get_proc_desc (Specs.get_summary proc_name)
in
@ -105,6 +135,7 @@ let iterate_callbacks (exe_env: Exe_env.t) =
(* analyze all the currently defined procedures *)
SourceFiles.proc_names_of_source exe_env.source_file
in
if Config.dump_duplicate_symbols then dump_duplicate_procs exe_env procs_to_analyze ;
let analyze_proc_name pname =
Option.iter
~f:(fun pdesc -> ignore (Ondemand.analyze_proc_desc pdesc pdesc))

@ -25,25 +25,17 @@ type file_data =
; mutable cfg: Cfg.t option }
(** get the path to the tenv file, which either one tenv file per source file or a global tenv file *)
let tenv_filename file_base =
let per_source_tenv_filename = DB.filename_add_suffix file_base ".tenv" in
let tenv_of_source source =
let source_dir = DB.source_dir_from_source_file source in
let per_source_tenv_filename = DB.source_dir_get_internal_file source_dir ".tenv" in
if Sys.file_exists (DB.filename_to_string per_source_tenv_filename) = `Yes then
per_source_tenv_filename
else DB.global_tenv_fname
module FilenameHash = Hashtbl.Make (struct
type t = DB.filename
let equal file1 file2 = DB.equal_filename file1 file2
let hash = Hashtbl.hash
end)
(** create a new file_data *)
let new_file_data source cg_fname =
let file_base = DB.chop_extension cg_fname in
let tenv_file = tenv_filename file_base in
let new_file_data source =
let tenv_file = tenv_of_source source in
(* Do not fill in tenv and cfg as they can be quite large. This makes calls to fork() cheaper
until we start filling out these fields. *)
{ source
@ -52,52 +44,21 @@ let new_file_data source cg_fname =
; cfg= None (* Cfg.load_cfg_from_file cfg_file *) }
let create_file_data table source cg_fname =
match FilenameHash.find table cg_fname with
let create_file_data table source =
match SourceFile.Hash.find table source with
| file_data ->
file_data
| exception Not_found ->
let file_data = new_file_data source cg_fname in
FilenameHash.add table cg_fname file_data ;
let file_data = new_file_data source in
SourceFile.Hash.add table source file_data ;
file_data
type t =
{ cg: Cg.t (** global call graph *)
; proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *)
; file_map: file_data FilenameHash.t (** map from cg fname to file data *)
{ proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *)
; file_map: file_data SourceFile.Hash.t (** map from source files to file data *)
; source_file: SourceFile.t (** source file being analyzed *) }
(** add call graph from fname in the spec db,
with relative tenv and cfg, to the execution environment *)
let add_cg exe_env source =
let cg_fname = DB.source_dir_get_internal_file (DB.source_dir_from_source_file source) ".cg" in
match Cg.load_from_file cg_fname with
| None ->
L.internal_error "Error: cannot load %s@." (DB.filename_to_string cg_fname)
| Some cg ->
let defined_procs = Cg.get_defined_nodes cg in
let duplicate_procs_to_print =
List.filter_map defined_procs ~f:(fun pname ->
match Attributes.find_file_capturing_procedure pname with
| None ->
None
| Some (source_captured, origin) ->
let multiply_defined = SourceFile.compare source source_captured <> 0 in
if multiply_defined then Cg.remove_node_defined cg pname ;
if multiply_defined && origin <> `Include then Some (pname, source_captured)
else None )
in
if Config.dump_duplicate_symbols then
Out_channel.with_file (Config.results_dir ^/ Config.duplicates_filename)
~append:true ~perm:0o666 ~f:(fun outc ->
let fmt = F.formatter_of_out_channel outc in
List.iter duplicate_procs_to_print ~f:(fun (pname, source_captured) ->
F.fprintf fmt "@.DUPLICATE_SYMBOLS source: %a source_captured:%a pname:%a@."
SourceFile.pp source SourceFile.pp source_captured Typ.Procname.pp pname ) ) ;
Cg.extend exe_env.cg cg
let get_file_data exe_env pname =
try Some (Typ.Procname.Hash.find exe_env.proc_map pname) with Not_found ->
let source_file_opt =
@ -112,9 +73,7 @@ let get_file_data exe_env pname =
Some proc_attributes.ProcAttributes.source_file_captured
in
let get_file_data_for_source source_file =
let source_dir = DB.source_dir_from_source_file source_file in
let cg_fname = DB.source_dir_get_internal_file source_dir ".cg" in
let file_data = create_file_data exe_env.file_map source_file cg_fname in
let file_data = create_file_data exe_env.file_map source_file in
Typ.Procname.Hash.replace exe_env.proc_map pname file_data ;
file_data
in
@ -184,13 +143,7 @@ let get_proc_desc exe_env pname =
let mk source_file =
let exe_env =
{ cg= Cg.create (SourceFile.invalid __FILE__)
; proc_map= Typ.Procname.Hash.create 17
; file_map= FilenameHash.create 1
; source_file }
in
add_cg exe_env source_file ; exe_env
{proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1; source_file}
(** [iter_files f exe_env] applies [f] to the filename and tenv and cfg for each file in [exe_env] *)

@ -14,12 +14,9 @@ open! IStd
type file_data
module FilenameHash : Caml.Hashtbl.S
type t = private
{ cg: Cg.t (** global call graph *)
; proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *)
; file_map: file_data FilenameHash.t (** map from cg fname to file data *)
{ proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *)
; file_map: file_data SourceFile.Hash.t (** map from source files to file data *)
; source_file: SourceFile.t (** source file being analyzed *) }
val mk : SourceFile.t -> t

@ -37,6 +37,14 @@ end
module Map = Caml.Map.Make (OrderedSourceFile)
module Set = Caml.Set.Make (OrderedSourceFile)
module Hash = Caml.Hashtbl.Make (struct
type nonrec t = t
let equal = equal
let hash = Caml.Hashtbl.hash
end)
let from_abs_path ?(warn_on_error= true) fname =
if Filename.is_relative fname then
L.(die InternalError) "Path '%s' is relative, when absolute path was expected." fname ;

@ -17,6 +17,8 @@ module Map : Caml.Map.S with type key = t
(** Set of source files *)
module Set : Caml.Set.S with type elt = t
module Hash : Caml.Hashtbl.S with type key = t
val is_invalid : t -> bool
(** Is the source file the invalid source file? *)

Loading…
Cancel
Save