[backend] remove source file from exe_env

Summary:
The execution environment is really just a cache. It happens to point to a
particular source file which is where the analysis was started from, but that
is not relevant, and in fact is confusing because it suggests that it is
somewhat tied to that file. In reality, exe_env caches information about any
procedure and source file encountered by the analysis.

This will make it easier to make further changes but I think it also brings a
bit more clarity to the code.

Reviewed By: jeremydubreil

Differential Revision: D8513735

fbshipit-source-id: f4b38ce
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 90c08e4596
commit 0914fee2cc

@ -17,13 +17,13 @@ let create_exe_env_tasks source_file exe_env : Tasks.t =
Typ.Procname.SQLite.clear_cache () ;
Random.self_init () ;
[ (fun () ->
Callbacks.iterate_callbacks exe_env ;
Callbacks.analyze_file exe_env source_file ;
if Config.write_html then Printer.write_all_html_files source_file ) ]
(** Create tasks to analyze a cluster *)
let create_source_file_tasks (source_file: SourceFile.t) : Tasks.t =
let exe_env = Exe_env.mk source_file in
let exe_env = Exe_env.mk () in
L.(debug Analysis Medium) "@\nProcessing '%a'@." SourceFile.pp source_file ;
create_exe_env_tasks source_file exe_env

@ -22,6 +22,7 @@ type proc_callback_t = proc_callback_args -> Summary.t
type cluster_callback_args =
{ procedures: (Tenv.t * Procdesc.t) list
; source_file: SourceFile.t
; get_proc_desc: Typ.Procname.t -> Procdesc.t option
; exe_env: Exe_env.t }
@ -75,10 +76,10 @@ let iterate_procedure_callbacks get_proc_desc exe_env summary proc_desc =
(** Invoke all registered cluster callbacks on a cluster of procedures. *)
let iterate_cluster_callbacks all_procs exe_env get_proc_desc =
let iterate_cluster_callbacks all_procs exe_env source_file get_proc_desc =
if !cluster_callbacks <> [] then
let procedures = List.filter_map ~f:(get_procedure_definition exe_env) all_procs in
let environment = {procedures; get_proc_desc; exe_env} in
let environment = {procedures; source_file; get_proc_desc; exe_env} in
let language_matches language =
match procedures with
| (_, pdesc) :: _ ->
@ -91,7 +92,7 @@ let iterate_cluster_callbacks all_procs exe_env get_proc_desc =
!cluster_callbacks
let dump_duplicate_procs (exe_env: Exe_env.t) procs =
let dump_duplicate_procs (exe_env: Exe_env.t) source_file procs =
let duplicate_procs =
List.filter_map procs ~f:(fun pname ->
match Exe_env.get_proc_desc exe_env pname with
@ -99,9 +100,9 @@ let dump_duplicate_procs (exe_env: Exe_env.t) procs =
match Attributes.load pname with
| Some {translation_unit; loc}
when (* defined in another file *)
not (SourceFile.equal exe_env.source_file translation_unit)
not (SourceFile.equal source_file translation_unit)
&& (* really defined in the current file and not in an include *)
SourceFile.equal exe_env.source_file loc.file ->
SourceFile.equal source_file loc.file ->
Some (pname, translation_unit)
| _ ->
None )
@ -114,8 +115,7 @@ let dump_duplicate_procs (exe_env: Exe_env.t) 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@."
SourceFile.pp exe_env.source_file SourceFile.pp source_captured Typ.Procname.pp pname
) )
SourceFile.pp source_file SourceFile.pp source_captured Typ.Procname.pp pname ) )
in
if not (List.is_empty duplicate_procs) then output_to_file duplicate_procs
@ -126,7 +126,7 @@ let create_perf_stats_report source_file =
(** Invoke all procedure and cluster callbacks on a given environment. *)
let iterate_callbacks (exe_env: Exe_env.t) =
let analyze_file (exe_env: Exe_env.t) source_file =
let saved_language = !Language.curr_language in
let get_proc_desc proc_name =
match Exe_env.get_proc_desc exe_env proc_name with
@ -142,15 +142,15 @@ let iterate_callbacks (exe_env: Exe_env.t) =
(* Invoke procedure callbacks using on-demand analysis schedulling *)
let procs_to_analyze =
(* analyze all the currently defined procedures *)
SourceFiles.proc_names_of_source exe_env.source_file
SourceFiles.proc_names_of_source source_file
in
if Config.dump_duplicate_symbols then dump_duplicate_procs exe_env procs_to_analyze ;
if Config.dump_duplicate_symbols then dump_duplicate_procs exe_env source_file procs_to_analyze ;
let analyze_proc_name pname = ignore (Ondemand.analyze_proc_name pname : Summary.t option) in
List.iter ~f:analyze_proc_name procs_to_analyze ;
(* Invoke cluster callbacks. *)
iterate_cluster_callbacks procs_to_analyze exe_env get_proc_desc ;
iterate_cluster_callbacks procs_to_analyze exe_env source_file get_proc_desc ;
(* Perf logging needs to remain at the end - after analysis work is complete *)
create_perf_stats_report exe_env.source_file ;
create_perf_stats_report source_file ;
(* Unregister callbacks *)
Ondemand.unset_callbacks () ;
Language.curr_language := saved_language

@ -26,6 +26,7 @@ type proc_callback_t = proc_callback_args -> Summary.t
type cluster_callback_args =
{ procedures: (Tenv.t * Procdesc.t) list
; source_file: SourceFile.t
; get_proc_desc: Typ.Procname.t -> Procdesc.t option
; exe_env: Exe_env.t }
@ -37,5 +38,5 @@ val register_procedure_callback : ?dynamic_dispatch:bool -> Language.t -> proc_c
val register_cluster_callback : Language.t -> cluster_callback_t -> unit
(** register a cluster callback *)
val iterate_callbacks : Exe_env.t -> unit
(** Invoke all the registered callbacks. *)
val analyze_file : Exe_env.t -> SourceFile.t -> unit
(** Invoke all the registered callbacks on the given file. *)

@ -8,7 +8,8 @@
open! IStd
(** Support for Execution environments *)
(** Execution environments: basically a cache of where procedures are and what is their CFG and type
environment *)
module L = Logging
@ -36,8 +37,7 @@ let create_file_data table source =
type t =
{ 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 *) }
; 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) with Caml.Not_found ->
@ -91,13 +91,14 @@ let get_tenv exe_env proc_name =
| Some tenv ->
tenv
| None ->
let loc = State.get_loc () in
L.(die InternalError)
"get_tenv: tenv not found for %a in file '%a'" Typ.Procname.pp proc_name SourceFile.pp
exe_env.source_file )
"get_tenv: tenv not found for %a in file '%a' at %a" Typ.Procname.pp proc_name
SourceFile.pp loc.Location.file Location.pp loc )
| None ->
let loc = State.get_loc () in
L.(die InternalError)
"get_tenv: file_data not found for %a in file %a at %a" Typ.Procname.pp proc_name
"get_tenv: file_data not found for %a in file '%a' at %a" Typ.Procname.pp proc_name
SourceFile.pp loc.Location.file Location.pp loc
@ -119,12 +120,4 @@ let get_proc_desc exe_env pname =
None
let mk source_file =
{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] *)
let iter_files f exe_env =
let source = exe_env.source_file in
let cfg = Cfg.load source in
Option.iter ~f:(f source) cfg
let mk () = {proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1}

@ -8,26 +8,23 @@
open! IStd
(** Support for Execution environments *)
(** Execution environments: basically a cache of where procedures are and what is their CFG and type
environment *)
type file_data
type t = private
{ 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 *) }
; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) }
val mk : SourceFile.t -> t
(** Create an exe_env from a source file *)
val mk : unit -> t
(** Create a new cache *)
val get_tenv : t -> Typ.Procname.t -> Tenv.t
(** return the type environment associated to the procedure *)
(** return the type environment associated with the procedure *)
val get_cfg : t -> Typ.Procname.t -> Cfg.t option
(** return the cfg associated to the procedure *)
(** return the cfg associated with the procedure *)
val get_proc_desc : t -> Typ.Procname.t -> Procdesc.t option
(** return the proc desc associated to the procedure *)
val iter_files : (SourceFile.t -> Cfg.t -> unit) -> t -> unit
(** [iter_files f exe_env] applies [f] to the source file and tenv and cfg for each file in [exe_env] *)
(** return the proc desc associated with the procedure *)

@ -366,7 +366,6 @@ let write_html_file linereader filename procs =
(** Create filename.ext.html for each file in the cluster. *)
let write_all_html_files cluster =
let exe_env = Exe_env.mk cluster in
let opt_whitelist_regex =
match Config.write_html_whitelist_regex with
| [] ->
@ -380,8 +379,8 @@ let write_all_html_files cluster =
Str.string_match regex fname 0 )
in
let linereader = LineReader.create () in
Exe_env.iter_files
(fun _ cfg ->
let cfg = Cfg.load cluster in
Option.iter cfg ~f:(fun cfg ->
let source_files_in_cfg, pdescs_in_cfg =
Typ.Procname.Hash.fold
(fun _ proc_desc (files, pdescs) ->
@ -397,4 +396,3 @@ let write_all_html_files cluster =
SourceFile.Set.iter
(fun file -> write_html_file linereader file pdescs_in_cfg)
source_files_in_cfg )
exe_env

@ -1483,7 +1483,7 @@ let aggregate_by_class file_env =
(* Gathers results by analyzing all the methods in a file, then
post-processes the results to check an (approximation of) thread
safety *)
let file_analysis {Callbacks.procedures; exe_env} =
let file_analysis {Callbacks.procedures; source_file} =
String.Map.iter
~f:(fun class_env ->
let tenv = fst (List.hd_exn class_env) in
@ -1493,5 +1493,4 @@ let file_analysis {Callbacks.procedures; exe_env} =
else (module MayAliasQuotientedAccessListMap) )
class_env) )
(aggregate_by_class procedures) ;
let sourcefile = exe_env.Exe_env.source_file in
IssueLog.store Config.racerd_issues_dir_name sourcefile
IssueLog.store Config.racerd_issues_dir_name source_file

@ -436,7 +436,7 @@ let report_starvation env get_proc_desc {StarvationDomain.events; ui} report_map
EventDomain.fold (report_on_current_elem ui_explain) events report_map'
let reporting {Callbacks.procedures; get_proc_desc; exe_env} =
let reporting {Callbacks.procedures; source_file; get_proc_desc} =
let report_procedure ((_, proc_desc) as env) =
die_if_not_java proc_desc ;
if should_report proc_desc then
@ -446,5 +446,4 @@ let reporting {Callbacks.procedures; get_proc_desc; exe_env} =
|> report_starvation env get_proc_desc summary |> ReportMap.log )
in
List.iter procedures ~f:report_procedure ;
let sourcefile = exe_env.Exe_env.source_file in
IssueLog.store Config.starvation_issues_dir_name sourcefile
IssueLog.store Config.starvation_issues_dir_name source_file

Loading…
Cancel
Save