[tenv] change interface to take `SourceFile.t` instead of `DB.filename`

Summary:
Also, make it explicit when we load the global tenv instead of the per-file tenv.

This allows for some nice simplifications in some places, notably:
- `tenv_file` is gone from `Exe_env.file_data`
- `DB.global_tenv_fname` is no more

This will help moving the tenv from the capture/source_file/ directories on the
filesystem to the database, as keys for the relevant table are `SourceFile.t`.

Reviewed By: mbouaziz

Differential Revision: D6796594

fbshipit-source-id: 1ffd5b0
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent ac92e13292
commit 7396a613bb

@ -89,28 +89,40 @@ let tenv_serializer : t Serialization.serializer =
let global_tenv : t option ref = ref None
(** Load a type environment from a file *)
let load_from_file (filename: DB.filename) : t option =
if DB.equal_filename filename DB.global_tenv_fname then (
if is_none !global_tenv then
global_tenv := Serialization.read_from_file tenv_serializer DB.global_tenv_fname ;
!global_tenv )
else Serialization.read_from_file tenv_serializer filename
let tenv_filename_of_source_file source_file =
DB.source_dir_get_internal_file (DB.source_dir_from_source_file source_file) ".tenv"
(** Save a type environment into a file *)
let store_to_file (filename: DB.filename) (tenv: t) =
(* update in-memory global tenv for later uses by this process, e.g. in single-core mode the
frontend and backend run in the same process *)
if DB.equal_filename filename DB.global_tenv_fname then global_tenv := Some tenv ;
Serialization.write_to_file tenv_serializer filename ~data:tenv ;
let load source_file : t option =
tenv_filename_of_source_file source_file |> Serialization.read_from_file tenv_serializer
let global_tenv_path = Config.(captured_dir ^/ global_tenv_filename) |> DB.filename_from_string
let load_global () : t option =
if is_none !global_tenv then
global_tenv := Serialization.read_from_file tenv_serializer global_tenv_path ;
!global_tenv
let store_to_filename tenv tenv_filename =
Serialization.write_to_file tenv_serializer tenv_filename ~data:tenv ;
if Config.debug_mode then
let debug_filename = DB.filename_to_string (DB.filename_add_suffix filename ".debug") in
let debug_filename = DB.filename_to_string (DB.filename_add_suffix tenv_filename ".debug") in
let out_channel = Out_channel.create debug_filename in
let fmt = Format.formatter_of_out_channel out_channel in
Format.fprintf fmt "%a" pp tenv ; Out_channel.close out_channel
let store source_file tenv = tenv_filename_of_source_file source_file |> store_to_filename tenv
let store_global tenv =
(* update in-memory global tenv for later uses by this process, e.g. in single-core mode the
frontend and backend run in the same process *)
global_tenv := Some tenv ;
store_to_filename tenv global_tenv_path
exception Found of Typ.Name.t
let language_is tenv lang =

@ -17,8 +17,17 @@ type t
val create : unit -> t
(** Create a new type environment. *)
val load_from_file : DB.filename -> t option
(** Load a type environment from a file *)
val load : SourceFile.t -> t option
(** Load a type environment for a source file *)
val load_global : unit -> t option
(** load the global type environment (Java) *)
val store : SourceFile.t -> t -> unit
(** Save a type environment into a file *)
val store_global : t -> unit
(** save a global type environment (Java) *)
val lookup : t -> Typ.Name.t -> Typ.Struct.t option
(** Look up a name in the global type environment. *)
@ -37,8 +46,5 @@ val sort_fields_tenv : t -> unit
val pp : Format.formatter -> t -> unit [@@warning "-32"]
(** print a type environment *)
val store_to_file : DB.filename -> t -> unit
(** Save a type environment into a file *)
val language_is : t -> Config.language -> bool
(** Test the language from which the types in the tenv were translated *)

@ -18,28 +18,13 @@ module L = Logging
module F = Format
(** per-file data: type environment and cfg *)
type file_data =
{ source: SourceFile.t
; tenv_file: DB.filename
; mutable tenv: Tenv.t option
; 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_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
type file_data = {source: SourceFile.t; mutable tenv: Tenv.t option; mutable cfg: Cfg.t option}
(** create a new file_data *)
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
; tenv_file
; tenv= None (* Sil.load_tenv_from_file tenv_file *)
; cfg= None (* Cfg.load_cfg_from_file cfg_file *) }
@ -81,7 +66,7 @@ let get_file_data exe_env pname =
let file_data_to_tenv file_data =
if is_none file_data.tenv then file_data.tenv <- Tenv.load_from_file file_data.tenv_file ;
if is_none file_data.tenv then file_data.tenv <- Tenv.load file_data.source ;
file_data.tenv
@ -92,11 +77,9 @@ let file_data_to_cfg file_data =
let java_global_tenv =
lazy
( match Tenv.load_from_file DB.global_tenv_fname with
( match Tenv.load_global () with
| None ->
L.(die InternalError)
"Could not load the global tenv at path '%s'"
(DB.filename_to_string DB.global_tenv_fname)
L.(die InternalError) "Could not load the global tenv"
| Some tenv ->
tenv )
@ -114,8 +97,8 @@ let get_tenv exe_env proc_name =
tenv
| None ->
L.(die InternalError)
"get_tenv: tenv not found for %a in file '%s'" Typ.Procname.pp proc_name
(DB.filename_to_string file_data.tenv_file) )
"get_tenv: tenv not found for %a in file '%a'" Typ.Procname.pp proc_name SourceFile.pp
exe_env.source_file )
| None ->
L.(die InternalError) "get_tenv: file_data not found for %a" Typ.Procname.pp proc_name

@ -231,11 +231,6 @@ module Results_dir = struct
Unix.openfile full_fname ~mode:Unix.([O_WRONLY; O_CREAT; O_TRUNC]) ~perm:0o777
end
let global_tenv_fname =
let basename = Config.global_tenv_filename in
Config.captured_dir ^/ basename
let is_source_file path =
List.exists ~f:(fun ext -> Filename.check_suffix path ext) Config.source_file_extentions

@ -109,9 +109,6 @@ val update_file_with_lock : string -> string -> (string -> string) -> unit
If the file does not exist, it is created, and update is given the empty string.
A lock is used to allow write attempts in parallel. *)
val global_tenv_fname : filename
(** get the path of the global type environment (only used in Java) *)
val is_source_file : string -> bool
(** Check if a path is a Java, C, C++ or Objectve C source file according to the file extention *)

@ -51,11 +51,10 @@ let do_source_file (translation_unit_context: CFrontend_config.translation_unit_
(* 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
NullabilityPreanalysis.analysis cfg tenv ;
Cfg.store source_file cfg ;
Tenv.sort_fields_tenv tenv ;
Tenv.store_to_file tenv_file tenv ;
Tenv.store source_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

@ -65,23 +65,20 @@ let capture_libs linereader program tenv =
(* load a stored global tenv if the file is found, and create a new one otherwise *)
let load_tenv () =
match Tenv.load_from_file DB.global_tenv_fname with
match Tenv.load_global () with
| None ->
Tenv.create ()
| Some _ when Config.models_mode ->
L.(die InternalError)
"Unexpected tenv file %s found while generating the models"
(DB.filename_to_string DB.global_tenv_fname)
"Unexpected global tenv file found in '%s' while generating the models" Config.captured_dir
| Some tenv ->
tenv
(* Store to a file the type environment containing all the types required to perform the analysis *)
(** Store to a file the type environment containing all the types required to perform the analysis *)
let save_tenv tenv =
(* TODO: this prevents per compilation step incremental analysis at this stage *)
if DB.file_exists DB.global_tenv_fname then DB.file_remove DB.global_tenv_fname ;
L.(debug Capture Medium) "writing new tenv %s@." (DB.filename_to_string DB.global_tenv_fname) ;
Tenv.store_to_file DB.global_tenv_fname tenv
L.(debug Capture Medium) "writing new global tenv@." ;
Tenv.store_global tenv
(* The program is loaded and translated *)

Loading…
Cancel
Save