[clang] do not depend on Config.clang_lang and Config.source_file

Summary:
This is needed for later: InferClang will no longer be started once for each
source file to be analysed. Instead, it will be called to analyse several files
at once, and will analyse them one by one. Thus, `clang_lang` and `source_file`
are moved to `cFrontend_config` as references.

The biggest change this entailed was the new logging infrastructure, which was
depending on `Config.source_file`. This diff moves the logic entirely to
`Logging`, and changes the API so that executables wishing to log into files
have to set it up using `Logging.set_log_file_identifier`. This can be called
several times during the execution, allowing to dynamically change the log file
(eg, when analysing several source files one by one!).

Reviewed By: jberdine

Differential Revision: D3944148

fbshipit-source-id: 6129090
master
Jules Villard 8 years ago committed by Facebook Github Bot
parent 7d49e16d63
commit d9f83094b5

@ -17,6 +17,7 @@ let module L = Logging;
let module F = Format;
let () = {
Logging.set_log_file_identifier (Option.map Filename.basename Config.cluster_cmdline);
if Config.print_builtins {
Builtin.print_and_exit ()
};
@ -119,8 +120,8 @@ let register_perf_stats_report () => {
};
let stats_base = Config.perf_stats_prefix ^ "_" ^ Filename.basename cluster ^ ".json";
let stats_file = Filename.concat stats_dir stats_base;
DB.create_dir Config.results_dir;
DB.create_dir stats_dir;
create_dir Config.results_dir;
create_dir stats_dir;
PerfStats.register_report_at_exit stats_file
};

@ -1263,8 +1263,8 @@ let compute_top_procedures = ref false;
let register_perf_stats_report () => {
let stats_dir = Filename.concat Config.results_dir Config.reporting_stats_dir_name;
let stats_file = Filename.concat stats_dir (Config.perf_stats_prefix ^ ".json");
DB.create_dir Config.results_dir;
DB.create_dir stats_dir;
create_dir Config.results_dir;
create_dir stats_dir;
PerfStats.register_report_at_exit stats_file
};

@ -21,8 +21,8 @@ let print_unix_error cmd e =
found in that file, and exits, with default code 1 or a given code. *)
let print_error_and_exit ?(exit_code=1) f el =
Logging.do_err f el;
let log_file = snd (Config.tmp_log_files_of_current_exe ()) in
Logging.stderr "\nAn error occured. Please, find details in %s\n\n%!" log_file;
let log_file = snd (Logging.log_file_names ()) in
Logging.stderr "@\nAn error occured. Please find details in %s@\n@\n%!" log_file;
exit exit_code
(** Executes a command and catches a potential exeption and prints it. *)

@ -83,7 +83,7 @@ let collect_all_summaries root_summaries_dir stacktrace_file stacktraces_dir =
| None -> None
| Some file ->
let crashcontext_dir = Config.results_dir // "crashcontext" in
DB.create_dir crashcontext_dir;
create_dir crashcontext_dir;
Some (file, crashcontext_dir // "crashcontext.json") in
let trace_file_regexp = Str.regexp "\\(.*\\)\\.json" in
let pairs_for_stactrace_dir = match stacktraces_dir with

@ -1540,64 +1540,6 @@ let patterns_suppress_warnings =
if CLOpt.(current_exe <> Java) then []
else error ("Error: The option " ^ suppress_warnings_annotations_long ^ " was not provided")
(** Name of dir for logging the output in the specific executable *)
let log_dir_of_current_exe =
match CLOpt.current_exe with
| Analyze -> "analyze"
| BuckCompilationDatabase -> "buck_compilation_database"
| Clang -> "clang"
| ClangWrapper -> "clang_wrapper"
| Interactive -> "interactive"
| Java -> "java"
| Llvm -> "llvm"
| Print -> "print"
| StatsAggregator -> "stats_agregator"
| Toplevel -> "top_level"
let log_identifier_of_current_exe =
match CLOpt.current_exe with
| Analyze -> Option.map Filename.basename cluster_cmdline
| Clang -> Option.map Filename.basename source_file
| ClangWrapper
| Interactive
| Java
| Llvm
| Print
| StatsAggregator
| Toplevel
| BuckCompilationDatabase -> None
(** Name of files for logging the output in the specific executable *)
let log_files_of_current_exe =
let name_prefix =
match log_identifier_of_current_exe with
| Some name -> name ^ "_"
| None -> "" in
let prefix = log_dir_of_current_exe in
name_prefix ^ prefix ^ "_out_", name_prefix ^ prefix ^ "_err_"
(** should_log_exe exe = true means that files for logging in the log folder will be created
and uses of Logging.out or Logging.err will log in those files *)
let should_log_current_exe =
match CLOpt.current_exe with
| Analyze
| Clang
| ClangWrapper -> debug_mode || stats_mode
| BuckCompilationDatabase -> true
| _ -> false
let tmp_log_files_of_current_exe () =
let out_name, err_name = log_files_of_current_exe in
let log_dir = results_dir // log_dir_name // log_dir_of_current_exe in
let out_file =
if out_file_cmdline = "" then
Filename.temp_file ~temp_dir:log_dir out_name ".log"
else out_file_cmdline in
let err_file =
if err_file_cmdline = "" then
Filename.temp_file ~temp_dir:log_dir err_name ".log"
else err_file_cmdline in
out_file, err_file
(** Global variables *)

@ -310,13 +310,3 @@ val curr_language : language ref
(** Command Line Interface Documentation *)
val print_usage_exit : unit -> 'a
(** Name of dir for logging the output in the specific executable *)
val log_dir_of_current_exe : string
(** Name of current temporary files for logging the output in the current executable *)
val tmp_log_files_of_current_exe : unit -> string * string
(** should_log_exe = true means that files for logging in the log dir will be created
and uses of Logging.out or Logging.err will log in those files *)
val should_log_current_exe : bool

@ -189,38 +189,11 @@ let file_modified_time ?(symlink=false) fname =
Logging.do_err "File %s does not exist." fname;
exit 1
(** Create a directory if it does not exist already. *)
let create_dir dir =
try
if (Unix.stat dir).Unix.st_kind != Unix.S_DIR then
(L.err "@.ERROR: file %s exists and is not a directory@." dir;
assert false)
with Unix.Unix_error _ ->
(try Unix.mkdir dir 0o700 with
Unix.Unix_error _ ->
let created_concurrently = (* check if another process created it meanwhile *)
try (Unix.stat dir).Unix.st_kind = Unix.S_DIR
with Unix.Unix_error _ -> false in
if not created_concurrently then
(L.err "@.ERROR: cannot create directory %s@." dir;
assert false))
let filename_create_dir fname =
let dirname = Filename.dirname fname in
if not (Sys.file_exists dirname)
then create_dir dirname
let rec create_path path =
try
Unix.mkdir path 0o700
with
| Unix.Unix_error (Unix.EEXIST, _, _) -> ()
| Unix.Unix_error (Unix.ENOENT, _, _) ->
create_path (Filename.dirname path);
create_path path
let read_whole_file fd =
let stats = Unix.fstat fd in
let size = stats.Unix.st_size in

@ -143,13 +143,6 @@ val filename_create_dir : filename -> unit
(** Find the source directories in the current results dir *)
val find_source_dirs : unit -> source_dir list
(** create a directory if it does not exist already *)
val create_dir : string -> unit
(** [make_directory path] will create a directory [path] creating all the
sub directories if non-existing *)
val create_path : string -> unit
(** Read a file using a lock to allow write attempts in parallel. *)
val read_file_with_lock : string -> string -> bytes option

@ -14,6 +14,73 @@ open! Utils
module F = Format
(** Name of dir for logging the output in the specific executable *)
let log_dir_of_current_exe =
match CommandLineOption.current_exe with
| Analyze -> "analyze"
| BuckCompilationDatabase -> "buck_compilation_database"
| Clang -> "clang"
| ClangWrapper -> "clang_wrapper"
| Interactive -> "interactive"
| Java -> "java"
| Llvm -> "llvm"
| Print -> "print"
| StatsAggregator -> "stats_agregator"
| Toplevel -> "top_level"
let out_file = ref "<BUG: logging to a file not setup, what you're looking for was emitted on \
stdout and may have been swallowed>"
let err_file = ref "<BUG: logging to a file not setup, what you're looking for was emitted on \
stderr and may have been swallowed>"
let out_formatter = ref F.std_formatter
let err_formatter = ref F.err_formatter
let set_log_file_identifier string_opt =
let should_setup_log_files =
match CommandLineOption.current_exe with
| Analyze
| Clang
| ClangWrapper -> Config.debug_mode || Config.stats_mode
| BuckCompilationDatabase -> true
| _ -> false in
if should_setup_log_files then (
let name_prefix = (match string_opt with
| Some name -> name ^ "_"
| None -> "") ^ string_of_int (Unix.getpid ()) ^ "_" in
let exe_log_dir =
let log_dir = Config.results_dir // Config.log_dir_name in
log_dir // log_dir_of_current_exe in
create_path exe_log_dir;
let log_file config_opt suffix =
(* the command-line option takes precedence if specified *)
if config_opt <> "" then config_opt
else Filename.temp_file ~temp_dir:exe_log_dir name_prefix suffix in
out_file := log_file Config.out_file_cmdline "-out.log";
err_file := log_file Config.err_file_cmdline "-err.log";
let open_output_file fname =
try
let cout = open_out fname in
let fmt = F.formatter_of_out_channel cout in
(fmt, cout)
with Sys_error _ ->
failwithf "@.ERROR: cannot open output file %s@." fname
in
let out_fmt, out_chan = open_output_file !out_file in
let err_fmt, err_chan = open_output_file !err_file in
Pervasives.at_exit (fun () ->
F.pp_print_flush out_fmt () ;
F.pp_print_flush err_fmt () ;
close_out out_chan ;
close_out err_chan
);
out_formatter := out_fmt;
err_formatter := err_fmt;
)
let log_file_names () = (!out_file, !err_file)
(** type of printable elements *)
type print_type =
| PTatom
@ -64,52 +131,10 @@ let delayed_actions = ref []
(** hook for the current printer of delayed print actions *)
let printer_hook = ref (Obj.magic ())
let out_formatter, err_formatter =
(* Create a directory if it does not exist already. *)
(* This is the same as DB.create_dir, except for logging to stderr *)
let create_dir dir =
try
if (Unix.stat dir).Unix.st_kind != Unix.S_DIR then
failwithf "@.ERROR: file %s exists and is not a directory@." dir
with Unix.Unix_error _ ->
try Unix.mkdir dir 0o700
with Unix.Unix_error _ ->
let created_concurrently = (* check if another process created it meanwhile *)
(Unix.stat dir).Unix.st_kind = Unix.S_DIR in
if not created_concurrently then
failwithf "@.ERROR: cannot create directory %s@." dir
in
let open_output_file fname =
try
let cout = open_out fname in
let fmt = F.formatter_of_out_channel cout in
(fmt, cout)
with Sys_error _ ->
failwithf "@.ERROR: cannot open output file %s@." fname
in
if Config.should_log_current_exe then
let log_dir = Config.results_dir // Config.log_dir_name in
let exe_log_dir = log_dir // Config.log_dir_of_current_exe in
create_dir Config.results_dir;
create_dir log_dir;
create_dir exe_log_dir;
let out_file, err_file = Config.tmp_log_files_of_current_exe () in
let out_fmt, out_chan = open_output_file out_file in
let err_fmt, err_chan = open_output_file err_file in
Pervasives.at_exit (fun () ->
F.pp_print_flush out_fmt () ;
F.pp_print_flush err_fmt () ;
close_out out_chan ;
close_out err_chan
);
(out_fmt, err_fmt)
else
(F.std_formatter, F.err_formatter)
(** extend the current print log *)
let add_print_action pact =
if Config.write_html then delayed_actions := pact :: !delayed_actions
else if not Config.test then !printer_hook out_formatter pact
else if not Config.test then !printer_hook !out_formatter pact
(** reset the delayed print actions *)
let reset_delayed_prints () =
@ -123,50 +148,41 @@ let get_delayed_prints () =
let set_delayed_prints new_delayed_actions =
delayed_actions := new_delayed_actions
let do_print fmt fmt_string =
F.fprintf fmt fmt_string
let do_print = F.fprintf
let do_print_in_debug_or_stats_mode fmt fmt_string =
let do_print_in_debug_or_stats_mode =
if Config.debug_mode || Config.stats_mode then
F.fprintf fmt fmt_string
F.fprintf
else
F.ifprintf fmt fmt_string
F.ifprintf
let do_print_in_debug_mode fmt fmt_string =
let do_print_in_debug_mode =
if Config.debug_mode then
F.fprintf fmt fmt_string
F.fprintf
else
F.ifprintf fmt fmt_string
F.ifprintf
(** print to the current out stream (note: only prints in debug or stats mode) *)
let out fmt_string =
do_print_in_debug_or_stats_mode out_formatter fmt_string
do_print_in_debug_or_stats_mode !out_formatter fmt_string
(** print to the current out stream (note: only prints in debug mode) *)
let out_debug fmt_string =
do_print_in_debug_mode out_formatter fmt_string
do_print_in_debug_mode !out_formatter fmt_string
(** print to the current out stream *)
let do_out fmt_string =
do_print out_formatter fmt_string
do_print !out_formatter fmt_string
(** print to the current err stream (note: only prints in debug or stats mode) *)
let err fmt_string =
do_print_in_debug_or_stats_mode err_formatter fmt_string
do_print_in_debug_or_stats_mode !err_formatter fmt_string
(** print to the current err stream *)
let do_err fmt_string =
do_print err_formatter fmt_string
do_print !err_formatter fmt_string
(** print to the current out stream (note: only prints in debug mode) *)
let err_debug fmt_string =
do_print_in_debug_mode err_formatter fmt_string
do_print_in_debug_mode !err_formatter fmt_string
(** print immediately to standard error *)
let stderr fmt_string =
do_print F.err_formatter fmt_string
(** print immediately to standard output *)
let stdout fmt_string =
do_print F.std_formatter fmt_string

@ -72,25 +72,29 @@ val set_delayed_prints : print_action list -> unit
(** reset the delayed print actions *)
val reset_delayed_prints : unit -> unit
(** print to the current out stream
(** Set a custom identifier to be part of the filename of the current logfiles. *)
val set_log_file_identifier : string option -> unit
(** print to the current out stream, as specified in set_log_file_identifier
(note: only prints in debug or in stats mode) *)
val out : ('a, Format.formatter, unit) format -> 'a
(** print to the current out stream
(** print to the current out stream, as specified in set_log_file_identifier
(note: only prints in debug mode) *)
val out_debug : ('a, Format.formatter, unit) format -> 'a
(** print to the current error stream
(** print to the current error stream, as specified in set_log_file_identifier
(note: only prints in debug or stats mode) *)
val err : ('a, Format.formatter, unit) format -> 'a
(** print to the current error stream (note: only prints in debug mode) *)
(** print to the current error stream, as specified in set_log_file_identifier
(note: only prints in debug mode) *)
val err_debug : ('a, Format.formatter, unit) format -> 'a
(** print to the current out stream *)
(** print to the current out stream, as specified in set_log_file_identifier *)
val do_out : ('a, Format.formatter, unit) format -> 'a
(** print to the current err stream *)
(** print to the current err stream, as specified in set_log_file_identifier *)
val do_err : ('a, Format.formatter, unit) format -> 'a
(** print immediately to standard error *)
@ -156,3 +160,6 @@ val log_progress_procedure : unit -> unit
(** Progress bar: log a timeout event if in developer mode. *)
val log_progress_timeout_event : SymOp.failure_kind -> unit
(** Name of current temporary files for logging the output in the current executable *)
val log_file_names : unit -> string * string

@ -630,3 +630,29 @@ let failwithf fmt =
let invalid_argf fmt =
Format.kfprintf (fun _ -> invalid_arg (Format.flush_str_formatter ()))
Format.str_formatter fmt
(** Create a directory if it does not exist already. *)
let create_dir dir =
try
if (Unix.stat dir).Unix.st_kind != Unix.S_DIR then
failwithf "@.ERROR: file %s exists and is not a directory@." dir
with Unix.Unix_error _ ->
try Unix.mkdir dir 0o700 with
Unix.Unix_error _ ->
let created_concurrently = (* check if another process created it meanwhile *)
try (Unix.stat dir).Unix.st_kind = Unix.S_DIR
with Unix.Unix_error _ -> false in
if not created_concurrently then
failwithf "@.ERROR: cannot create directory %s@." dir
(** [create_path path] will create a directory at [path], creating all the parent directories if
non-existing *)
let rec create_path path =
try
Unix.mkdir path 0o700
with
| Unix.Unix_error (Unix.EEXIST, _, _) -> ()
| Unix.Unix_error (Unix.ENOENT, _, _) ->
create_path (Filename.dirname path);
create_dir path

@ -287,3 +287,10 @@ val with_process_full: string -> (in_channel -> 'a) -> (in_channel -> 'b) ->
val failwithf : ('a, Format.formatter, unit, 'b) format4 -> 'a
val invalid_argf : ('a, Format.formatter, unit, 'b) format4 -> 'a
(** create a directory if it does not exist already *)
val create_dir : string -> unit
(** [create_path path] will create a directory at [path], creating all the parent directories if
non-existing *)
val create_path : string -> unit

@ -23,7 +23,7 @@ let load_from_cache serializer zip_path cache_dir zip_library =
let extract to_path =
if not (Sys.file_exists to_path) then
begin
DB.create_path (Filename.dirname to_path);
create_path (Filename.dirname to_path);
let lazy zip_channel = zip_library.Config.zip_channel in
let entry = Zip.find_entry zip_channel zip_path in
Zip.copy_entry_to_file zip_channel entry to_path

@ -104,7 +104,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(Procname.to_filename caller)
suffix in
let fpath = Filename.concat dir fname in
DB.create_dir dir;
create_dir dir;
Ag_util.Json.to_file Stacktree_j.write_stacktree fpath stacktree
let exec_instr astate proc_data _ = function

@ -8,6 +8,7 @@
*)
type context = {
translation_unit_context : CFrontend_config.translation_unit_context;
current_method : Clang_ast_t.decl option;
in_synchronized_block: bool;
is_ck_translation_unit: bool;
@ -15,8 +16,9 @@ type context = {
of CKComponent or CKComponentController. *)
}
let empty = {
let empty translation_unit_context = {
current_method = None;
translation_unit_context;
in_synchronized_block = false;
is_ck_translation_unit = false;
}

@ -10,10 +10,11 @@
open CFrontend_utils
open !Utils
let is_ck_context context decl =
context.CLintersContext.is_ck_translation_unit
&& Ast_utils.is_in_main_file decl
&& General_utils.is_objc_extension
let is_ck_context {CLintersContext.is_ck_translation_unit; translation_unit_context} decl =
is_ck_translation_unit
&& Ast_utils.is_in_main_file translation_unit_context decl
&& General_utils.is_objc_extension translation_unit_context
(** Recursively go up the inheritance hierarchy of a given ObjCInterfaceDecl.
(Returns false on decls other than that one.) *)
@ -101,7 +102,7 @@ let mutable_local_vars_advice context decl =
CIssue.description = "Local variables should be const to avoid reassignment";
CIssue.suggestion = Some "Add a const (after the asterisk for pointer types). \
http://componentkit.org/docs/avoid-local-variables.html";
CIssue.loc = CFrontend_checkers.location_from_dinfo decl_info
CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info
}
else None
| _ -> assert false (* Should only be called with a VarDecl *)
@ -130,7 +131,7 @@ let component_factory_function_advice context decl =
that return a CKComponent subclass. \
http://componentkit.org/docs/break-out-composites.html"
);
CIssue.loc = CFrontend_checkers.location_from_dinfo decl_info
CIssue.loc = CFrontend_checkers.location_from_dinfo context decl_info
}
else None
| _ -> assert false (* Should only be called with FunctionDecl *)

@ -136,7 +136,7 @@ let binary_operation_instruction boi e1 typ e2 loc rhs_owning_method =
(Clang_ast_j.string_of_binary_operator_kind bok);
(Exp.minus_one, [])
let unary_operation_instruction uoi e typ loc =
let unary_operation_instruction translation_unit_context uoi e typ loc =
let uok = Clang_ast_j.string_of_unary_operator_kind (uoi.Clang_ast_t.uoi_kind) in
let un_exp op =
Exp.UnOp(op, e, Some typ) in
@ -150,7 +150,7 @@ let unary_operation_instruction uoi e typ loc =
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in
let e_plus_1 = Exp.BinOp(Binop.PlusA, Exp.Var id, Exp.Const(Const.Cint (IntLit.one))) in
let exp = if General_utils.is_cpp_translation then
let exp = if General_utils.is_cpp_translation translation_unit_context then
e
else
e_plus_1 in
@ -164,7 +164,7 @@ let unary_operation_instruction uoi e typ loc =
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in
let e_minus_1 = Exp.BinOp(Binop.MinusA, Exp.Var id, Exp.Const(Const.Cint (IntLit.one))) in
let exp = if General_utils.is_cpp_translation then
let exp = if General_utils.is_cpp_translation translation_unit_context then
e
else
e_minus_1 in

@ -17,7 +17,7 @@ val binary_operation_instruction :
Clang_ast_t.binary_operator_info -> Exp.t -> Typ.t -> Exp.t ->
Location.t -> bool -> Exp.t * Sil.instr list
val unary_operation_instruction :
val unary_operation_instruction : CFrontend_config.translation_unit_context ->
Clang_ast_t.unary_operator_info -> Exp.t -> Typ.t -> Location.t -> Exp.t * Sil.instr list
val assignment_arc_mode :

@ -26,6 +26,7 @@ type str_node_map = (string, Cfg.Node.t) Hashtbl.t
type t =
{
translation_unit_context : CFrontend_config.translation_unit_context;
tenv : Tenv.t;
cg : Cg.t;
cfg : Cfg.cfg;
@ -33,20 +34,16 @@ type t =
is_objc_method : bool;
curr_class: curr_class;
return_param_typ : Typ.t option;
outer_context : t option; (* in case of objc blocks, the context of the method containing the block *)
outer_context : t option; (** in case of objc blocks, the context of the method containing the
block *)
mutable blocks_static_vars : ((Pvar.t * Typ.t) list) Procname.Map.t;
label_map : str_node_map;
}
let create_context tenv cg cfg procdesc curr_class return_param_typ is_objc_method context_opt =
{ tenv = tenv;
cg = cg;
cfg = cfg;
procdesc = procdesc;
curr_class = curr_class;
return_param_typ = return_param_typ;
is_objc_method = is_objc_method;
outer_context = context_opt;
let create_context translation_unit_context tenv cg cfg procdesc curr_class return_param_typ
is_objc_method outer_context =
{ translation_unit_context; tenv; cg; cfg; procdesc; curr_class; return_param_typ;
is_objc_method; outer_context;
blocks_static_vars = Procname.Map.empty;
label_map = Hashtbl.create 17;
}

@ -24,6 +24,7 @@ type str_node_map = (string, Cfg.Node.t) Hashtbl.t
type t =
{
translation_unit_context : CFrontend_config.translation_unit_context;
tenv : Tenv.t;
cg : Cg.t;
cfg : Cfg.cfg;
@ -31,7 +32,8 @@ type t =
is_objc_method : bool;
curr_class: curr_class;
return_param_typ : Typ.t option;
outer_context : t option; (* in case of objc blocks, the context of the method containing the block *)
outer_context : t option; (** in case of objc blocks, the context of the method containing the
block *)
mutable blocks_static_vars : ((Pvar.t * Typ.t) list) Procname.Map.t;
label_map : str_node_map;
}
@ -58,8 +60,8 @@ val is_objc_method : t -> bool
val get_tenv : t -> Tenv.t
val create_context : Tenv.t -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t ->
curr_class -> Typ.t option -> bool -> t option -> t
val create_context : CFrontend_config.translation_unit_context -> Tenv.t -> Cg.t -> Cfg.cfg ->
Cfg.Procdesc.t -> curr_class -> Typ.t option -> bool -> t option -> t
val create_curr_class : Tenv.t -> string -> Csu.class_kind -> curr_class

@ -20,14 +20,15 @@ and CFrontend_declImpl : CModule_type.CFrontend =
CFrontend_decl.CFrontend_decl_funct(CTransImpl)
(* Translates a file by translating the ast into a cfg. *)
let compute_icfg source tenv ast =
let compute_icfg trans_unit_ctx tenv ast =
match ast with
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) ->
CFrontend_config.global_translation_unit_decls := decl_list;
Logging.out_debug "@\n Start creating icfg@\n";
let cg = Cg.create (Some source) in
let cg = Cg.create (Some trans_unit_ctx.CFrontend_config.source_file) in
let cfg = Cfg.Node.create_cfg () in
IList.iter (CFrontend_declImpl.translate_one_declaration tenv cg cfg `DeclTraversal)
IList.iter
(CFrontend_declImpl.translate_one_declaration trans_unit_ctx tenv cg cfg `DeclTraversal)
decl_list;
Logging.out_debug "\n Finished creating icfg\n";
(cg, cfg)
@ -38,14 +39,15 @@ let init_global_state_capture () =
CFrontend_config.global_translation_unit_decls := [];
CFrontend_utils.General_utils.reset_block_counter ()
let do_source_file source_file ast =
let do_source_file translation_unit_context ast =
let tenv = Tenv.create () in
CTypes_decl.add_predefined_types tenv;
init_global_state_capture ();
let source_file = translation_unit_context.CFrontend_config.source_file in
Config.nLOC := FileLOC.file_get_loc (DB.source_file_to_string source_file);
Logging.out_debug "@\n Start building call/cfg graph for '%s'....@\n"
(DB.source_file_to_string source_file);
let call_graph, cfg = compute_icfg source_file tenv ast in
let call_graph, cfg = compute_icfg translation_unit_context tenv ast in
Logging.out_debug "@\n End building call/cfg graph for '%s'.@\n"
(DB.source_file_to_string source_file);
(* This part below is a boilerplate in every frontends. *)

@ -13,4 +13,4 @@ open! Utils
json format. Translate the json file into a cfg by adding all the type and class declarations to
the tenv, adding all the functions and methods declarations as procdescs to the cfg, and adding
the control flow graph of all the code of those functions and methods to the cfg. *)
val do_source_file : DB.source_file -> Clang_ast_t.decl -> unit
val do_source_file : CFrontend_config.translation_unit_context -> Clang_ast_t.decl -> unit

@ -22,16 +22,19 @@ open CFrontend_utils
(* - If it is a declaration invoke it from run_frontend_checkers_on_decl *)
(* Helper functions *)
let location_from_stmt stmt =
let location_from_stmt lctx stmt =
let info, _ = Clang_ast_proj.get_stmt_tuple stmt in
CLocation.get_sil_location_from_range info.Clang_ast_t.si_source_range true
CLocation.get_sil_location_from_range lctx.CLintersContext.translation_unit_context
info.Clang_ast_t.si_source_range true
let location_from_dinfo info =
CLocation.get_sil_location_from_range info.Clang_ast_t.di_source_range true
let location_from_dinfo lctx info =
CLocation.get_sil_location_from_range lctx.CLintersContext.translation_unit_context
info.Clang_ast_t.di_source_range true
let location_from_decl dec =
let location_from_decl lctx dec =
let info = Clang_ast_proj.get_decl_tuple dec in
CLocation.get_sil_location_from_range info.Clang_ast_t.di_source_range true
CLocation.get_sil_location_from_range lctx.CLintersContext.translation_unit_context
info.Clang_ast_t.di_source_range true
let decl_name dec =
match Clang_ast_proj.get_named_decl_tuple dec with
@ -73,7 +76,7 @@ let ctl_makes_an_expensive_call () =
ET([ObjCMethodDecl][->Body] EF remove_observer) Or
EH([ObjCImplementationDecl, ObjCProtocolDecl] EF remove_observer)
*)
let ctl_ns_notification decl =
let ctl_ns_notification lctx decl =
let open CTL in
let exists_method_calling_addObserver =
EF (Atomic ("call_method", ["addObserver:selector:name:object:"])) in
@ -102,13 +105,13 @@ let ctl_ns_notification decl =
Localise.registered_observer_being_deallocated_str CFrontend_config.self;
CIssue.suggestion =
Some "Consider removing the object from the notification center before its deallocation.";
CIssue.loc = location_from_decl decl;
CIssue.loc = location_from_decl lctx decl;
} in
condition, issue_desc
(* BAD_POINTER_COMPARISON: Fires whenever a NSNumber is dangerously coerced to
a boolean in a comparison *)
let ctl_bad_pointer_comparison_warning stmt =
let ctl_bad_pointer_comparison_warning lctx stmt =
let open CTL in
let is_binop = Atomic ("is_stmt", ["BinaryOperator"]) in
let is_binop_eq = Atomic ("is_binop_with_kind", ["EQ"]) in
@ -134,12 +137,12 @@ let ctl_bad_pointer_comparison_warning stmt =
Some ("Did you mean to compare against the unboxed value instead? " ^
"Please either explicitly compare the NSNumber instance to nil, " ^
"or use one of the NSNumber accessors before the comparison.");
loc = location_from_stmt stmt
loc = location_from_stmt lctx stmt
} in
condition, issue_desc
(* name_contains_delegate AND not name_contains_queue AND is_strong_property *)
let ctl_strong_delegate dec =
let ctl_strong_delegate lctx dec =
let open CTL in
let name_contains_delegate =
Atomic ("property_name_contains_word", ["delegate"]) in
@ -155,14 +158,14 @@ let ctl_strong_delegate dec =
CIssue.description = Printf.sprintf
"Property or ivar %s declared strong" (decl_name dec);
CIssue.suggestion = Some "In general delegates should be declared weak or assign";
CIssue.loc = location_from_decl dec
CIssue.loc = location_from_decl lctx dec
} in
condition, issue_desc
(* (is_ObjC || is_Objc++) /\ is_global_var /\ not is_const_var /\
ET([VarDecl][->InitExpr] EF ctl_makes_an_expensive_call)
*)
let ctl_global_var_init_with_calls_warning decl =
let ctl_global_var_init_with_calls_warning lctx decl =
let open CTL in
let ctl_is_global_var =
And (And (Atomic ("is_objc_extension", []), Atomic ("is_global_var", [])),
@ -177,12 +180,12 @@ let ctl_global_var_init_with_calls_warning decl =
(decl_name decl);
CIssue.suggestion = Some
"If the function/method call is expensive, it can affect the starting time of the app.";
CIssue.loc = location_from_decl decl
CIssue.loc = location_from_decl lctx decl
} in
condition, issue_desc
(* is_assign_property AND is_property_pointer_type *)
let ctl_assign_pointer_warning decl =
let ctl_assign_pointer_warning lctx decl =
let open CTL in
let condition =
And (Atomic("is_assign_property", []), Atomic("is_property_pointer_type", [])) in
@ -193,7 +196,7 @@ let ctl_assign_pointer_warning decl =
"Property `%s` is a pointer type marked with the `assign` attribute"
(decl_name decl);
CIssue.suggestion = Some "Use a different attribute like `strong` or `weak`.";
CIssue.loc = location_from_decl decl
CIssue.loc = location_from_decl lctx decl
} in
condition, issue_desc
@ -201,7 +204,7 @@ let ctl_assign_pointer_warning decl =
not context_in_synchronized_block /\ not is_method_property_accessor_of_ivar
/\ not is_objc_constructor /\ not is_objc_dealloc
*)
let ctl_direct_atomic_property_access_warning stmt =
let ctl_direct_atomic_property_access_warning lctx stmt =
let open CTL in
let condition =
And (And (And (And (Not (Atomic ("context_in_synchronized_block", [])),
@ -215,11 +218,11 @@ let ctl_direct_atomic_property_access_warning stmt =
"Direct access to ivar %s of an atomic property" (ivar_name stmt);
CIssue.suggestion =
Some "Accessing an ivar of an atomic property makes the property nonatomic";
CIssue.loc = location_from_stmt stmt
CIssue.loc = location_from_stmt lctx stmt
} in
condition, issue_desc
let ctl_captured_cxx_ref_in_objc_block_warning stmt =
let ctl_captured_cxx_ref_in_objc_block_warning lctx stmt =
(* Fire if the list of captured references is not empty *)
let condition = CTL.Atomic ("captures_cxx_references", []) in
let issue_desc = {
@ -229,24 +232,24 @@ let ctl_captured_cxx_ref_in_objc_block_warning stmt =
(Predicates.var_descs_name stmt);
CIssue.suggestion = Some ("C++ References are unmanaged and may be invalid " ^
"by the time the block executes.");
CIssue.loc = location_from_stmt stmt
CIssue.loc = location_from_stmt lctx stmt
} in
condition, issue_desc
(* === Warnings on properties === *)
(* Assing Pointer Warning: a property with a pointer type should not be declared `assign` *)
let assign_pointer_warning lcxt decl =
let assign_pointer_warning lctx decl =
let open CTL in
let condition, issue_desc = ctl_assign_pointer_warning decl in
if CTL.eval_formula condition (Decl decl) lcxt then
let condition, issue_desc = ctl_assign_pointer_warning lctx decl in
if CTL.eval_formula condition (Decl decl) lctx then
Some issue_desc
else None
(* Strong Delegate Warning: a property with name delegate should not be declared strong *)
let strong_delegate_warning lcxt decl =
let condition, issue_desc = ctl_strong_delegate decl in
if CTL.eval_formula condition (Decl decl) lcxt then
let strong_delegate_warning lctx decl =
let condition, issue_desc = ctl_strong_delegate lctx decl in
if CTL.eval_formula condition (Decl decl) lctx then
Some issue_desc
else None
@ -254,36 +257,36 @@ let strong_delegate_warning lcxt decl =
(* a global variable initialization should not *)
(* contain calls to functions or methods as these can be expensive an delay the starting time *)
(* of an app *)
let global_var_init_with_calls_warning lcxt decl =
let condition, issue_desc = ctl_global_var_init_with_calls_warning decl in
if CTL.eval_formula condition (CTL.Decl decl) lcxt then
let global_var_init_with_calls_warning lctx decl =
let condition, issue_desc = ctl_global_var_init_with_calls_warning lctx decl in
if CTL.eval_formula condition (CTL.Decl decl) lctx then
Some issue_desc
else None
(* Direct Atomic Property access:
a property declared atomic should not be accessed directly via its ivar *)
let direct_atomic_property_access_warning context stmt =
let condition, issue_desc = ctl_direct_atomic_property_access_warning stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) context then
let direct_atomic_property_access_warning lctx stmt =
let condition, issue_desc = ctl_direct_atomic_property_access_warning lctx stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lctx then
Some issue_desc
else None
(* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references
should not be captured in blocks. *)
let captured_cxx_ref_in_objc_block_warning lcxt stmt =
let condition, issue_desc = ctl_captured_cxx_ref_in_objc_block_warning stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lcxt then
let captured_cxx_ref_in_objc_block_warning lctx stmt =
let condition, issue_desc = ctl_captured_cxx_ref_in_objc_block_warning lctx stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lctx then
Some issue_desc
else None
let checker_NSNotificationCenter lcxt dec =
let condition, issue_desc = ctl_ns_notification dec in
if CTL.eval_formula condition (CTL.Decl dec) lcxt then
let checker_NSNotificationCenter lctx dec =
let condition, issue_desc = ctl_ns_notification lctx dec in
if CTL.eval_formula condition (CTL.Decl dec) lctx then
Some issue_desc
else None
let bad_pointer_comparison_warning lcxt stmt =
let condition, issue_desc = ctl_bad_pointer_comparison_warning stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lcxt then
let bad_pointer_comparison_warning lctx stmt =
let condition, issue_desc = ctl_bad_pointer_comparison_warning lctx stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lctx then
Some issue_desc
else None

@ -44,4 +44,4 @@ val global_var_init_with_calls_warning :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option
val location_from_dinfo :
Clang_ast_t.decl_info -> Location.t
CLintersContext.context -> Clang_ast_t.decl_info -> Location.t

@ -27,7 +27,7 @@ let rec do_frontend_checks_stmt (context:CLintersContext.context) stmt =
and do_frontend_checks_decl context decl =
let open Clang_ast_t in
let info = Clang_ast_proj.get_decl_tuple decl in
CLocation.update_curr_file info;
CLocation.update_curr_file context.CLintersContext.translation_unit_context info;
let context' =
(match decl with
| FunctionDecl(_, _, _, fdi)
@ -74,20 +74,22 @@ let context_with_ck_set context decl_list =
let store_issues source_file =
let abbrev_source_file = DB.source_file_encoding source_file in
let lint_issues_dir = Config.results_dir // Config.lint_issues_dir_name in
DB.create_dir lint_issues_dir;
create_dir lint_issues_dir;
let lint_issues_file =
DB.filename_from_string (Filename.concat lint_issues_dir (abbrev_source_file ^ ".issue")) in
LintIssues.store_issues lint_issues_file !LintIssues.errLogMap
let do_frontend_checks source_file ast =
let do_frontend_checks trans_unit_ctx ast =
try
let source_file = trans_unit_ctx.CFrontend_config.source_file in
Logging.out "Start linting file %s@\n" (DB.source_file_to_string source_file);
match ast with
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) ->
let context = context_with_ck_set CLintersContext.empty decl_list in
let context =
context_with_ck_set (CLintersContext.empty trans_unit_ctx) decl_list in
let is_decl_allowed decl =
let decl_info = Clang_ast_proj.get_decl_tuple decl in
CLocation.should_do_frontend_check decl_info.Clang_ast_t.di_source_range in
CLocation.should_do_frontend_check trans_unit_ctx decl_info.Clang_ast_t.di_source_range in
let allowed_decls = IList.filter is_decl_allowed decl_list in
IList.iter (do_frontend_checks_decl context) allowed_decls;
if (LintIssues.exists_issues ()) then

@ -7,4 +7,4 @@
* of patent rights can be found in the PATENTS file in the same directory.
*)
val do_frontend_checks : DB.source_file -> Clang_ast_t.decl -> unit
val do_frontend_checks : CFrontend_config.translation_unit_context -> Clang_ast_t.decl -> unit

@ -11,6 +11,11 @@ open! Utils
(** Module that contains constants and global state used in the frontend *)
type translation_unit_context = {
lang : Config.clang_lang;
source_file : DB.source_file
}
(** Constants *)
let alloc = "alloc"
@ -78,7 +83,6 @@ let modeled_function_attributes = [replace_with_deref_first_arg_attr]
(** Global state *)
let current_source = ref DB.source_file_empty
let enum_map = ref Clang_ast_main.PointerMap.empty
let global_translation_unit_decls : Clang_ast_t.decl list ref = ref []
let ivar_to_property_index = ref Clang_ast_main.PointerMap.empty

@ -11,6 +11,11 @@ open! Utils
(** Module that contains constants and global state used in the frontend *)
type translation_unit_context = {
lang : Config.clang_lang;
source_file : DB.source_file
}
(** Constants *)
val alloc : string
@ -79,8 +84,6 @@ val modeled_function_attributes : string list
(** Global state *)
val current_source : DB.source_file ref
(** Map from enum constants pointers to their predecesor and their sil value *)
val enum_map : (Clang_ast_t.pointer option * Exp.t option) Clang_ast_main.PointerMap.t ref
val global_translation_unit_decls : Clang_ast_t.decl list ref

@ -21,8 +21,8 @@ struct
Specs.summary_exists_in_models procname && not Config.models_mode
(* Translates the method/function's body into nodes of the cfg. *)
let add_method tenv cg cfg class_decl_opt procname body has_return_param is_objc_method
outer_context_opt extra_instrs =
let add_method trans_unit_ctx tenv cg cfg class_decl_opt procname body has_return_param
is_objc_method outer_context_opt extra_instrs =
Logging.out_debug
"@\n@\n>>---------- ADDING METHOD: '%s' ---------<<@\n@." (Procname.to_string procname);
try
@ -30,7 +30,7 @@ struct
| Some procdesc ->
if (Cfg.Procdesc.is_defined procdesc && not (model_exists procname)) then
(let context =
CContext.create_context tenv cg cfg procdesc class_decl_opt
CContext.create_context trans_unit_ctx tenv cg cfg procdesc class_decl_opt
has_return_param is_objc_method outer_context_opt in
let start_node = Cfg.Procdesc.get_start_node procdesc in
let exit_node = Cfg.Procdesc.get_exit_node procdesc in
@ -45,44 +45,49 @@ struct
with
| Not_found -> ()
| CTrans_utils.Self.SelfClassException _ ->
assert false (* this shouldn't happen, because self or [a class] should always be arguments of functions. This is to make sure I'm not wrong. *)
(* this shouldn't happen, because self or [a class] should always be arguments of
functions. This is to make sure I'm not wrong. *)
assert false
| Assert_failure (file, line, column) ->
Logging.out "Fatal error: exception Assert_failure(%s, %d, %d)\n%!" file line column;
Cfg.Procdesc.remove cfg procname true;
CMethod_trans.create_external_procdesc cfg procname is_objc_method None;
()
let function_decl tenv cfg cg func_decl block_data_opt =
let function_decl trans_unit_ctx tenv cfg cg func_decl block_data_opt =
let captured_vars, outer_context_opt =
match block_data_opt with
| Some (outer_context, _, _, captured_vars) -> captured_vars, Some outer_context
| None -> [], None in
let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl tenv func_decl block_data_opt in
CMethod_trans.method_signature_of_decl trans_unit_ctx tenv func_decl block_data_opt in
match body_opt with
| Some body -> (* Only in the case the function declaration has a defined body we create a procdesc *)
| Some body ->
(* Only in the case the function declaration has a defined body we create a procdesc *)
let procname = CMethod_signature.ms_get_name ms in
let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ ms in
if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then
add_method tenv cg cfg CContext.ContextNoCls procname body return_param_typ_opt false
outer_context_opt extra_instrs
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
return_param_typ_opt false outer_context_opt extra_instrs
| None -> ()
let process_method_decl tenv cg cfg curr_class meth_decl ~is_objc =
let process_method_decl trans_unit_ctx tenv cg cfg curr_class meth_decl ~is_objc =
let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl tenv meth_decl None in
CMethod_trans.method_signature_of_decl trans_unit_ctx tenv meth_decl None in
match body_opt with
| Some body ->
let is_instance = CMethod_signature.ms_is_instance ms in
let procname = CMethod_signature.ms_get_name ms in
let is_objc_inst_method = is_instance && is_objc in
let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ ms in
if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_objc_inst_method then
add_method tenv cg cfg curr_class procname body return_param_typ_opt is_objc
None extra_instrs
if CMethod_trans.create_local_procdesc
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
| None -> ()
let process_property_implementation obj_c_property_impl_decl_info =
let process_property_implementation trans_unit_ctx obj_c_property_impl_decl_info =
let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in
match Ast_utils.get_decl_opt_with_decl_ref property_decl_opt with
| Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) ->
@ -94,13 +99,14 @@ struct
(match Ast_utils.get_decl_opt_with_decl_ref pointer with
| Some (ObjCMethodDecl (decl_info, _, _) as d) ->
let source_range = decl_info.Clang_ast_t.di_source_range in
let loc = CLocation.get_sil_location_from_range source_range true in
let loc =
CLocation.get_sil_location_from_range trans_unit_ctx source_range true in
let property_accessor =
if getter then
Some (ProcAttributes.Objc_getter field_name)
else
Some (ProcAttributes.Objc_setter field_name) in
let procname = General_utils.procname_of_decl d in
let procname = General_utils.procname_of_decl trans_unit_ctx d in
let attrs = { (ProcAttributes.default procname Config.Clang) with
loc = loc;
objc_accessor = property_accessor; } in
@ -111,15 +117,15 @@ struct
| _ -> ())
| _ -> ()
let process_one_method_decl tenv cg cfg curr_class dec =
let process_one_method_decl trans_unit_ctx tenv cg cfg curr_class dec =
let open Clang_ast_t in
match dec with
| CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _ | CXXDestructorDecl _ ->
process_method_decl tenv cg cfg curr_class dec ~is_objc:false
process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:false
| ObjCMethodDecl _ ->
process_method_decl tenv cg cfg curr_class dec ~is_objc:true
process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:true
| ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) ->
process_property_implementation obj_c_property_impl_decl_info
process_property_implementation trans_unit_ctx obj_c_property_impl_decl_info
| EmptyDecl _
| ObjCIvarDecl _ | ObjCPropertyDecl _ -> ()
| _ ->
@ -127,12 +133,12 @@ struct
"\nWARNING: found Method Declaration '%s' skipped. NEED TO BE FIXED\n\n" (Ast_utils.string_of_decl dec);
()
let process_methods tenv cg cfg curr_class decl_list =
IList.iter (process_one_method_decl tenv cg cfg curr_class) decl_list
let process_methods trans_unit_ctx tenv cg cfg curr_class decl_list =
IList.iter (process_one_method_decl trans_unit_ctx tenv cg cfg curr_class) decl_list
let should_translate_decl dec decl_trans_context =
let should_translate_decl trans_unit_ctx dec decl_trans_context =
let info = Clang_ast_proj.get_decl_tuple dec in
CLocation.update_curr_file info;
CLocation.update_curr_file trans_unit_ctx info;
let source_range = info.Clang_ast_t.di_source_range in
let translate_when_used = match dec with
| Clang_ast_t.FunctionDecl (_, name_info, _, _)
@ -144,7 +150,8 @@ struct
AttributesTable.is_whitelisted_cpp_method name
| _ -> false in
let translate_location =
CLocation.should_translate_lib source_range decl_trans_context ~translate_when_used in
CLocation.should_translate_lib trans_unit_ctx source_range decl_trans_context
~translate_when_used in
let never_translate_decl = match dec with
| Clang_ast_t.FunctionDecl (_, name_info, _, _)
| Clang_ast_t.CXXMethodDecl (_, name_info, _, _, _) ->
@ -154,49 +161,49 @@ struct
(not never_translate_decl) && translate_location
(* Translate one global declaration *)
let rec translate_one_declaration tenv cg cfg decl_trans_context dec =
let rec translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context dec =
let open Clang_ast_t in
(* each procedure has different scope: start names from id 0 *)
Ident.NameGenerator.reset ();
(if should_translate_decl dec decl_trans_context then
(if should_translate_decl trans_unit_ctx dec decl_trans_context then
match dec with
| FunctionDecl(_, _, _, _) ->
function_decl tenv cfg cg dec None
function_decl trans_unit_ctx tenv cfg cg dec None
| ObjCInterfaceDecl(_, name_info, decl_list, _, oi_decl_info) ->
let name = Ast_utils.get_qualified_name name_info in
let curr_class = ObjcInterface_decl.get_curr_class name oi_decl_info in
ignore
(ObjcInterface_decl.interface_declaration CTypes_decl.type_ptr_to_sil_type tenv dec);
process_methods tenv cg cfg curr_class decl_list
process_methods trans_unit_ctx tenv cg cfg curr_class decl_list
| ObjCProtocolDecl(_, name_info, decl_list, _, _) ->
let name = Ast_utils.get_qualified_name name_info in
let curr_class = CContext.ContextProtocol name in
ignore (ObjcProtocol_decl.protocol_decl CTypes_decl.type_ptr_to_sil_type tenv dec);
process_methods tenv cg cfg curr_class decl_list
process_methods trans_unit_ctx tenv cg cfg curr_class decl_list
| ObjCCategoryDecl(_, name_info, decl_list, _, ocdi) ->
let name = Ast_utils.get_qualified_name name_info in
let curr_class = ObjcCategory_decl.get_curr_class_from_category_decl name ocdi in
ignore (ObjcCategory_decl.category_decl CTypes_decl.type_ptr_to_sil_type tenv dec);
process_methods tenv cg cfg curr_class decl_list
process_methods trans_unit_ctx tenv cg cfg curr_class decl_list
| ObjCCategoryImplDecl(_, name_info, decl_list, _, ocidi) ->
let name = Ast_utils.get_qualified_name name_info in
let curr_class = ObjcCategory_decl.get_curr_class_from_category_impl name ocidi in
ignore (ObjcCategory_decl.category_impl_decl CTypes_decl.type_ptr_to_sil_type tenv dec);
process_methods tenv cg cfg curr_class decl_list;
process_methods trans_unit_ctx tenv cg cfg curr_class decl_list;
| ObjCImplementationDecl(decl_info, _, decl_list, _, idi) ->
let curr_class = ObjcInterface_decl.get_curr_class_impl idi in
let class_name = CContext.get_curr_class_name curr_class in
let type_ptr_to_sil_type = CTypes_decl.type_ptr_to_sil_type in
ignore (ObjcInterface_decl.interface_impl_declaration type_ptr_to_sil_type tenv dec);
CMethod_trans.add_default_method_for_class class_name decl_info;
process_methods tenv cg cfg curr_class decl_list;
CMethod_trans.add_default_method_for_class trans_unit_ctx class_name decl_info;
process_methods trans_unit_ctx tenv cg cfg curr_class decl_list;
| CXXMethodDecl (decl_info, _, _, _, _)
| CXXConstructorDecl (decl_info, _, _, _, _)
@ -210,11 +217,12 @@ struct
| Some (ClassTemplateSpecializationDecl _) ->
let curr_class = CContext.ContextClsDeclPtr parent_ptr in
if Config.cxx_experimental then
process_methods tenv cg cfg curr_class [dec]
process_methods trans_unit_ctx tenv cg cfg curr_class [dec]
| Some dec ->
Logging.out "Methods of %s skipped\n" (Ast_utils.string_of_decl dec)
| None -> ())
| _ -> ());
let translate = translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context in
match dec with
(* Note that C and C++ records are treated the same way
Skip translating implicit struct declarations, unless they have
@ -229,19 +237,19 @@ struct
true
| _ -> false in
let method_decls, no_method_decls = IList.partition is_method_decl decl_list in
IList.iter (translate_one_declaration tenv cg cfg decl_trans_context) no_method_decls;
IList.iter translate no_method_decls;
ignore (CTypes_decl.add_types_from_decl_to_tenv tenv dec);
IList.iter (translate_one_declaration tenv cg cfg decl_trans_context) method_decls
IList.iter translate method_decls
| EnumDecl _ -> ignore (CEnum_decl.enum_decl dec)
| LinkageSpecDecl (_, decl_list, _) ->
Logging.out_debug "ADDING: LinkageSpecDecl decl list\n";
IList.iter (translate_one_declaration tenv cg cfg decl_trans_context) decl_list
Logging.out_debug "ADDING: LinkageSpecDecl decl list@\n";
IList.iter translate decl_list
| NamespaceDecl (_, _, decl_list, _, _) ->
IList.iter (translate_one_declaration tenv cg cfg decl_trans_context) decl_list
IList.iter translate decl_list
| ClassTemplateDecl (_, _, template_decl_info)
| FunctionTemplateDecl (_, _, template_decl_info) ->
let decl_list = template_decl_info.Clang_ast_t.tdi_specializations in
IList.iter (translate_one_declaration tenv cg cfg decl_trans_context) decl_list
IList.iter translate decl_list
| _ -> ()
end

@ -81,17 +81,17 @@ let function_decl_checker_list = [ComponentKit.component_factory_function_advice
let checker_for_function_decl decl checker context =
checker context decl
let get_err_log method_decl_opt =
let get_err_log translation_unit_context method_decl_opt =
let procname = match method_decl_opt with
| Some method_decl -> General_utils.procname_of_decl method_decl
| Some method_decl -> General_utils.procname_of_decl translation_unit_context method_decl
| None -> Procname.Linters_dummy_method in
LintIssues.get_err_log procname
(* Add a frontend warning with a description desc at location loc to the errlog of a proc desc *)
let log_frontend_issue method_decl_opt key issue_desc =
let log_frontend_issue translation_unit_context method_decl_opt key issue_desc =
let issue = issue_desc.CIssue.issue in
let loc = issue_desc.CIssue.loc in
let errlog = get_err_log method_decl_opt in
let errlog = get_err_log translation_unit_context method_decl_opt in
let err_desc = Errdesc.explain_frontend_warning issue_desc.CIssue.description
issue_desc.CIssue.suggestion loc in
let name = CIssue.to_string issue in
@ -116,7 +116,8 @@ let invoke_set_of_checkers f context key checkers =
IList.iter (fun checker ->
match f checker context with
| Some issue_desc ->
log_frontend_issue context.CLintersContext.current_method key issue_desc
log_frontend_issue context.CLintersContext.translation_unit_context
context.CLintersContext.current_method key issue_desc
| None -> ()) checkers
let run_frontend_checkers_on_stmt context instr =

@ -437,10 +437,15 @@ struct
| Clang_ast_t.ObjCImplementationDecl (_, _, _, _, idi) -> Some idi
| _ -> None
let is_in_main_file decl =
let is_in_main_file translation_unit_context decl =
let decl_info = Clang_ast_proj.get_decl_tuple decl in
let file_opt = (fst decl_info.Clang_ast_t.di_source_range).Clang_ast_t.sl_file in
opt_equal string_equal file_opt Config.source_file && Option.is_some file_opt
match file_opt with
| None -> false
| Some file ->
DB.source_file_equal
(CLocation.source_file_from_path file)
translation_unit_context.CFrontend_config.source_file
let default_blacklist =
let open CFrontend_config in
@ -632,11 +637,13 @@ struct
| None -> file)
| None -> ""
let is_cpp_translation =
Config.clang_lang = Config.CPP || Config.clang_lang = Config.OBJCPP
let is_cpp_translation translation_unit_context =
let lang = translation_unit_context.CFrontend_config.lang in
lang = Config.CPP || lang = Config.OBJCPP
let is_objc_extension =
Config.clang_lang = Config.OBJC || Config.clang_lang = Config.OBJCPP
let is_objc_extension translation_unit_context =
let lang = translation_unit_context.CFrontend_config.lang in
lang = Config.OBJC || lang = Config.OBJCPP
let rec get_mangled_method_name function_decl_info method_decl_info =
(* For virtual methods return mangled name of the method from most base class
@ -658,7 +665,7 @@ struct
get_mangled_method_name fdi mdi
| _ -> assert false)
let mk_procname_from_function name function_decl_info_opt =
let mk_procname_from_function translation_unit_context name function_decl_info_opt =
let file =
match function_decl_info_opt with
| Some (decl_info, function_decl_info) ->
@ -673,7 +680,7 @@ struct
| _ -> None in
let mangled_name =
match mangled_opt with
| Some m when is_cpp_translation -> m
| Some m when is_cpp_translation translation_unit_context -> m
| _ -> "" in
let mangled = (string_crc_hex32 file) ^ mangled_name in
if String.length file == 0 && String.length mangled_name == 0 then
@ -700,13 +707,13 @@ struct
let method_kind = Procname.objc_method_kind_of_bool is_instance in
mk_procname_from_objc_method class_name method_name method_kind
let procname_of_decl meth_decl =
let procname_of_decl translation_unit_context meth_decl =
let open Clang_ast_t in
match meth_decl with
| FunctionDecl (decl_info, name_info, _, fdi) ->
let name = Ast_utils.get_qualified_name name_info in
let function_info = Some (decl_info, fdi) in
mk_procname_from_function name function_info
mk_procname_from_function translation_unit_context name function_info
| CXXMethodDecl (_, name_info, _, fdi, mdi)
| CXXConstructorDecl (_, name_info, _, fdi, mdi)
| CXXConversionDecl (_, name_info, _, fdi, mdi)

@ -158,7 +158,7 @@ sig
(** Returns true if the declaration or statement is inside the main source
file, as opposed to an imported header file. For statements, this refers
to the parent decl. *)
val is_in_main_file : Clang_ast_t.decl -> bool
val is_in_main_file : CFrontend_config.translation_unit_context -> Clang_ast_t.decl -> bool
(** Recursively go up the inheritance hierarchy of a given ObjCInterfaceDecl.
Returns true if the passed in decl is an objc interface decl that's an
@ -224,8 +224,8 @@ sig
val mk_procname_from_objc_method : string -> string -> Procname.objc_cpp_method_kind -> Procname.t
val mk_procname_from_function : string -> (Clang_ast_t.decl_info * Clang_ast_t.function_decl_info)
option -> Procname.t
val mk_procname_from_function : CFrontend_config.translation_unit_context -> string
-> (Clang_ast_t.decl_info * Clang_ast_t.function_decl_info) option -> Procname.t
val get_mangled_method_name : Clang_ast_t.function_decl_info ->
Clang_ast_t.cxx_method_decl_info -> string option
@ -233,7 +233,7 @@ sig
val mk_procname_from_cpp_method :
string -> string -> ?meth_decl:Clang_ast_t.decl -> string option -> Procname.t
val procname_of_decl : Clang_ast_t.decl -> Procname.t
val procname_of_decl : CFrontend_config.translation_unit_context -> Clang_ast_t.decl -> Procname.t
val mk_class_field_name : Clang_ast_t.named_decl_info -> Ident.fieldname
@ -244,9 +244,9 @@ sig
Pvar.t
(** true if Config.clang_lang is C++ or ObjC++ *)
val is_cpp_translation : bool
val is_cpp_translation : CFrontend_config.translation_unit_context -> bool
(** true if Config.clang_lang is ObjC or ObjC++ *)
val is_objc_extension : bool
val is_objc_extension : CFrontend_config.translation_unit_context -> bool
end

@ -11,9 +11,8 @@ open! Utils
(** Module for function to retrieve the location (file, line, etc) of instructions *)
(* Inside the json there may be code or type definitions from other files *)
(* than the one passed as an argument. That current file in the translation is saved*)
(* in this variable. *)
(** Inside the AST there may be code or type definitions from other files than the one passed as an
argument. That current file in the translation is saved in this variable. *)
let curr_file = ref DB.source_file_empty
let source_file_from_path path =
@ -36,20 +35,21 @@ let choose_sloc sloc1 sloc2 =
| Some f when not (DB.source_file_equal (source_file_from_path f) !curr_file) -> sloc2
| _ -> sloc1
let choose_sloc_to_update_curr_file sloc1 sloc2 =
let choose_sloc_to_update_curr_file trans_unit_ctx sloc1 sloc2 =
match sloc2.Clang_ast_t.sl_file with
| Some f when DB.source_file_equal (source_file_from_path f) !CFrontend_config.current_source ->
| Some f when DB.source_file_equal (source_file_from_path f)
trans_unit_ctx.CFrontend_config.source_file ->
sloc2
| _ -> sloc1
let update_curr_file di =
let update_curr_file trans_unit_ctx di =
let loc_start, loc_end = di.Clang_ast_t.di_source_range in
let loc = choose_sloc_to_update_curr_file loc_start loc_end in
let loc = choose_sloc_to_update_curr_file trans_unit_ctx loc_start loc_end in
match loc.Clang_ast_t.sl_file with
| Some f -> curr_file := source_file_from_path f
| None -> ()
let clang_to_sil_location clang_loc procdesc_opt =
let clang_to_sil_location trans_unit_ctx clang_loc procdesc_opt =
let line = match clang_loc.Clang_ast_t.sl_line with
| Some l -> l
| None -> -1 in
@ -68,7 +68,7 @@ let clang_to_sil_location clang_loc procdesc_opt =
| Some f ->
let file_db = source_file_from_path f in
let nloc =
if (DB.source_file_equal file_db !CFrontend_config.current_source) then
if (DB.source_file_equal file_db trans_unit_ctx.CFrontend_config.source_file) then
!Config.nLOC
else -1 in
file_db, nloc
@ -87,22 +87,20 @@ let file_in_project file =
file_in_project && not (file_should_be_skipped)
| None -> false
let should_do_frontend_check (loc_start, _) =
let should_do_frontend_check trans_unit_ctx (loc_start, _) =
match loc_start.Clang_ast_t.sl_file with
| Some file ->
let equal_current_source file =
DB.source_file_equal (source_file_from_path file) !CFrontend_config.current_source in
let equal_current_source file = DB.source_file_equal (source_file_from_path file)
trans_unit_ctx.CFrontend_config.source_file in
equal_current_source file ||
(file_in_project file && not Config.testing_mode)
| None -> false
(* We translate by default the instructions in the current file.*)
(* In C++ development, we also translate the headers that are part *)
(* of the project. However, in testing mode, we don't want to translate *)
(* the headers because the dot files in the frontend tests should contain nothing *)
(* else than the source file to avoid conflicts between different versions of the *)
(* libraries in the CI *)
let should_translate (loc_start, loc_end) decl_trans_context ~translate_when_used =
(** We translate by default the instructions in the current file. In C++ development, we also
translate the headers that are part of the project. However, in testing mode, we don't want to
translate the headers because the dot files in the frontend tests should contain nothing else
than the source file to avoid conflicts between different versions of the libraries. *)
let should_translate trans_unit_ctx (loc_start, loc_end) decl_trans_context ~translate_when_used =
let map_path_of pred loc =
match loc.Clang_ast_t.sl_file with
| Some f -> pred f
@ -112,8 +110,7 @@ let should_translate (loc_start, loc_end) decl_trans_context ~translate_when_use
let path_pred path = pred (source_file_from_path path) in
map_path_of path_pred loc
in
let equal_current_source file =
DB.source_file_equal file !CFrontend_config.current_source
let equal_current_source = DB.source_file_equal trans_unit_ctx.CFrontend_config.source_file
in
let file_in_project = map_path_of file_in_project loc_end
|| map_path_of file_in_project loc_start in
@ -127,9 +124,9 @@ let should_translate (loc_start, loc_end) decl_trans_context ~translate_when_use
|| (Config.cxx_experimental && decl_trans_context = `Translation && translate_on_demand
&& not Config.testing_mode)
let should_translate_lib source_range decl_trans_context ~translate_when_used =
let should_translate_lib trans_unit_ctx source_range decl_trans_context ~translate_when_used =
not Config.no_translate_libs
|| should_translate source_range decl_trans_context ~translate_when_used
|| should_translate trans_unit_ctx source_range decl_trans_context ~translate_when_used
let is_file_blacklisted file =
let paths = Config.skip_clang_analysis_in_path in
@ -139,15 +136,16 @@ let is_file_blacklisted file =
paths in
is_file_blacklisted
let get_sil_location_from_range source_range prefer_first =
let get_sil_location_from_range trans_unit_ctx source_range prefer_first =
let sloc1, sloc2 = source_range in
let sloc = if not prefer_first then sloc2 else choose_sloc sloc1 sloc2 in
clang_to_sil_location sloc None
clang_to_sil_location trans_unit_ctx sloc None
let get_sil_location stmt_info context =
let sloc1, sloc2 = stmt_info.Clang_ast_t.si_source_range in
let sloc = choose_sloc sloc1 sloc2 in
clang_to_sil_location sloc (Some (CContext.get_procdesc context))
clang_to_sil_location context.CContext.translation_unit_context sloc
(Some (CContext.get_procdesc context))
let check_source_file source_file =
if is_file_blacklisted source_file then

@ -11,25 +11,27 @@ open! Utils
(** Module for function to retrieve the location (file, line, etc) of instructions *)
(* Inside the json there may be code or type definitions from other files *)
(* than the one passed as an argument. That current file in the translation is saved*)
(* in this variable. *)
(** Inside the AST there may be code or type definitions from other files than the one passed as an
argument. That current file in the translation is saved in this variable. *)
val curr_file : DB.source_file ref
val clang_to_sil_location : Clang_ast_t.source_location -> Cfg.Procdesc.t option ->
val clang_to_sil_location : CFrontend_config.translation_unit_context ->
Clang_ast_t.source_location -> Cfg.Procdesc.t option ->
Location.t
val get_sil_location : Clang_ast_t.stmt_info -> CContext.t -> Location.t
val should_translate_lib : Clang_ast_t.source_range -> CModule_type.decl_trans_context ->
translate_when_used:bool -> bool
val should_translate_lib : CFrontend_config.translation_unit_context -> Clang_ast_t.source_range ->
CModule_type.decl_trans_context -> translate_when_used:bool -> bool
val should_do_frontend_check : Clang_ast_t.source_range -> bool
val should_do_frontend_check : CFrontend_config.translation_unit_context ->
Clang_ast_t.source_range -> bool
val update_curr_file : Clang_ast_t.decl_info -> unit
val update_curr_file : CFrontend_config.translation_unit_context -> Clang_ast_t.decl_info -> unit
val check_source_file : string -> unit
val source_file_from_path : string -> DB.source_file
val get_sil_location_from_range : Clang_ast_t.source_range -> bool -> Location.t
val get_sil_location_from_range : CFrontend_config.translation_unit_context ->
Clang_ast_t.source_range -> bool -> Location.t

@ -37,17 +37,15 @@ let register_perf_stats_report source_file =
let stats_dir = Filename.concat Config.results_dir Config.frontend_stats_dir_name in
let abbrev_source_file = DB.source_file_encoding source_file in
let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in
DB.create_dir Config.results_dir ;
DB.create_dir stats_dir ;
create_dir Config.results_dir ;
create_dir stats_dir ;
PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file)
let init_global_state_for_capture_and_linters source_file =
register_perf_stats_report source_file;
Config.curr_language := Config.Clang;
CFrontend_config.current_source := source_file;
DB.Results_dir.init source_file
let do_run source_path ast_path =
let do_run source_file ast_path =
let init_time = Unix.gettimeofday () in
let print_elapsed () =
let elapsed = Unix.gettimeofday () -. init_time in
@ -58,8 +56,7 @@ let do_run source_path ast_path =
| Some path ->
path, validate_decl_from_file path
| None ->
"stdin of " ^ source_path, validate_decl_from_stdin () in
"stdin of " ^ DB.source_file_to_string source_file, validate_decl_from_stdin () in
let decl_index, stmt_index, type_index, ivar_to_property_index =
Clang_ast_main.index_node_pointers ast_decl in
CFrontend_config.pointer_decl_index := decl_index;
@ -67,16 +64,15 @@ let do_run source_path ast_path =
CFrontend_config.pointer_type_index := type_index;
CFrontend_config.ivar_to_property_index := ivar_to_property_index;
CFrontend_config.json := ast_filename;
CLocation.check_source_file source_path;
let source_file = CLocation.source_file_from_path source_path in
Logging.out "Clang frontend action is %s\n" Config.clang_frontend_action_string;
Logging.out "Start %s of AST from %s\n" Config.clang_frontend_action_string
!CFrontend_config.json;
init_global_state_for_capture_and_linters source_file;
let translation_unit_context = CFrontend_config.{source_file; lang=Config.clang_lang} in
if Config.clang_frontend_do_lint then
CFrontend_checkers_main.do_frontend_checks source_file ast_decl;
CFrontend_checkers_main.do_frontend_checks translation_unit_context ast_decl;
if Config.clang_frontend_do_capture then
CFrontend.do_source_file source_file ast_decl;
CFrontend.do_source_file translation_unit_context ast_decl;
Logging.out "End translation AST file %s... OK!@\n" !CFrontend_config.json;
print_elapsed ();
with
@ -86,9 +82,13 @@ let do_run source_path ast_path =
raise exc
let () =
match Config.source_file with
| Some path ->
do_run path Config.ast_file
| None ->
Logging.err_debug "Incorrect command line arguments\n";
Config.print_usage_exit ()
let source_file =
(match Config.source_file with
| Some path ->
Logging.set_log_file_identifier (Some (Filename.basename path));
CLocation.check_source_file path;
CLocation.source_file_from_path path
| None ->
Logging.err_debug "Incorrect command line arguments\n";
Config.print_usage_exit ()) in
do_run source_file Config.ast_file

@ -9,10 +9,8 @@
open! Utils
(** Main module of InferClang. Take as input AST files produced by clang during compilation *)
(** and their corresponding C/C++/ObjectiveC source files. *)
(** Parse the arguments, parse and validate the input AST into a data structure *)
(** and translates it into a cfg. *)
(** Main module of InferClang. Take as input AST files produced by clang during compilation and
their corresponding C/C++/ObjectiveC source files.
val do_run : string -> string option -> unit
Parse the arguments, parse and validate the input AST into a data structure and translates it
into a cfg. *)

@ -89,9 +89,9 @@ let get_param_decls function_method_decl_info =
| ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_parameters
| Block_decl_info (block_decl_info, _, _) -> block_decl_info.Clang_ast_t.bdi_parameters
let get_language function_method_decl_info =
let get_language trans_unit_ctx function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (_, _) -> Config.clang_lang
| Func_decl_info (_, _) -> trans_unit_ctx.CFrontend_config.lang
| Cpp_Meth_decl_info _ -> Config.CPP
| ObjC_Meth_decl_info _ -> Config.OBJC
| Block_decl_info _ -> Config.OBJC
@ -105,7 +105,7 @@ let is_cpp_virtual function_method_decl_info =
1. self/this parameter (optional, only for methods)
2. normal parameters
3. return parameter (optional) *)
let get_parameters tenv function_method_decl_info =
let get_parameters trans_unit_ctx tenv function_method_decl_info =
let par_to_ms_par par =
match par with
| Clang_ast_t.ParmVarDecl (_, name_info, qt, var_decl_info) ->
@ -113,7 +113,7 @@ let get_parameters tenv function_method_decl_info =
let param_typ = CTypes_decl.type_ptr_to_sil_type tenv qt.Clang_ast_t.qt_type_ptr in
let qt_type_ptr =
match param_typ with
| Typ.Tstruct _ when General_utils.is_cpp_translation ->
| Typ.Tstruct _ when General_utils.is_cpp_translation trans_unit_ctx ->
Ast_expressions.create_reference_type qt.Clang_ast_t.qt_type_ptr
| _ -> qt.Clang_ast_t.qt_type_ptr in
(mangled, {qt with qt_type_ptr})
@ -130,14 +130,14 @@ let get_return_val_and_param_types tenv function_method_decl_info =
Ast_expressions.create_void_type, Some (Typ.Tptr (return_typ, Typ.Pk_pointer))
else return_type_ptr, None
let build_method_signature tenv decl_info procname function_method_decl_info
let build_method_signature trans_unit_ctx tenv decl_info procname function_method_decl_info
parent_pointer pointer_to_property_opt =
let source_range = decl_info.Clang_ast_t.di_source_range in
let tp, return_param_type_opt = get_return_val_and_param_types tenv function_method_decl_info in
let is_instance_method = is_instance_method function_method_decl_info in
let parameters = get_parameters tenv function_method_decl_info in
let parameters = get_parameters trans_unit_ctx tenv function_method_decl_info in
let attributes = decl_info.Clang_ast_t.di_attributes in
let lang = get_language function_method_decl_info in
let lang = get_language trans_unit_ctx function_method_decl_info in
let is_cpp_virtual = is_cpp_virtual function_method_decl_info in
CMethod_signature.make_ms
procname parameters tp attributes source_range is_instance_method ~is_cpp_virtual:is_cpp_virtual
@ -157,29 +157,30 @@ let get_init_list_instrs method_decl_info =
let create_custom_instr construct_instr = `CXXConstructorInit construct_instr in
IList.map create_custom_instr method_decl_info.Clang_ast_t.xmdi_cxx_ctor_initializers
let method_signature_of_decl tenv meth_decl block_data_opt =
let method_signature_of_decl trans_unit_ctx tenv meth_decl block_data_opt =
let open Clang_ast_t in
match meth_decl, block_data_opt with
| FunctionDecl (decl_info, _, qt, fdi), _ ->
let func_decl = Func_decl_info (fdi, qt.Clang_ast_t.qt_type_ptr) in
let procname = General_utils.procname_of_decl meth_decl in
let ms = build_method_signature tenv decl_info procname func_decl None None in
let procname = General_utils.procname_of_decl trans_unit_ctx meth_decl in
let ms = build_method_signature trans_unit_ctx tenv decl_info procname func_decl None None in
let extra_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in
ms, fdi.Clang_ast_t.fdi_body, extra_instrs
| CXXMethodDecl (decl_info, _, qt, fdi, mdi), _
| CXXConstructorDecl (decl_info, _, qt, fdi, mdi), _
| CXXConversionDecl (decl_info, _, qt, fdi, mdi), _
| CXXDestructorDecl (decl_info, _, qt, fdi, mdi), _ ->
let procname = General_utils.procname_of_decl meth_decl in
let procname = General_utils.procname_of_decl trans_unit_ctx meth_decl in
let parent_ptr = Option.get decl_info.di_parent_pointer in
let method_decl = Cpp_Meth_decl_info (fdi, mdi, parent_ptr, qt.Clang_ast_t.qt_type_ptr) in
let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in
let ms = build_method_signature tenv decl_info procname method_decl parent_pointer None in
let ms = build_method_signature
trans_unit_ctx tenv decl_info procname method_decl parent_pointer None in
let non_null_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in
let init_list_instrs = get_init_list_instrs mdi in (* it will be empty for methods *)
ms, fdi.Clang_ast_t.fdi_body, (init_list_instrs @ non_null_instrs)
| ObjCMethodDecl (decl_info, _, mdi), _ ->
let procname = General_utils.procname_of_decl meth_decl in
let procname = General_utils.procname_of_decl trans_unit_ctx meth_decl in
let parent_ptr = Option.get decl_info.di_parent_pointer in
let method_decl = ObjC_Meth_decl_info (mdi, parent_ptr) in
let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in
@ -187,22 +188,22 @@ let method_signature_of_decl tenv meth_decl block_data_opt =
match mdi.Clang_ast_t.omdi_property_decl with
| Some decl_ref -> Some decl_ref.Clang_ast_t.dr_decl_pointer
| None -> None in
let ms = build_method_signature tenv decl_info procname method_decl
let ms = build_method_signature trans_unit_ctx tenv decl_info procname method_decl
parent_pointer pointer_to_property_opt in
let extra_instrs = get_assume_not_null_calls mdi.omdi_parameters in
ms, mdi.omdi_body, extra_instrs
| BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) ->
let func_decl = Block_decl_info (bdi, tp, outer_context) in
let ms = build_method_signature tenv decl_info procname func_decl None None in
let ms = build_method_signature trans_unit_ctx tenv decl_info procname func_decl None None in
let extra_instrs = get_assume_not_null_calls bdi.bdi_parameters in
ms, bdi.bdi_body, extra_instrs
| _ -> raise Invalid_declaration
let method_signature_of_pointer tenv pointer =
let method_signature_of_pointer trans_unit_ctx tenv pointer =
try
match Ast_utils.get_decl pointer with
| Some meth_decl ->
let ms, _, _ = method_signature_of_decl tenv meth_decl None in
let ms, _, _ = method_signature_of_decl trans_unit_ctx tenv meth_decl None in
Some ms
| None -> None
with Invalid_declaration -> None
@ -247,10 +248,10 @@ let get_superclass_curr_class_objc context =
| CContext.ContextProtocol _ -> assert false
(* Gets the class name from a method signature found by clang, if search is successful *)
let get_class_name_method_call_from_clang tenv obj_c_message_expr_info =
let get_class_name_method_call_from_clang trans_unit_ctx tenv obj_c_message_expr_info =
match obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer with
| Some pointer ->
(match method_signature_of_pointer tenv pointer with
(match method_signature_of_pointer trans_unit_ctx tenv pointer with
| Some ms ->
begin
match CMethod_signature.ms_get_name ms with
@ -377,7 +378,7 @@ let get_const_args_indices ~shift args =
aux [] args
(** Creates a procedure description. *)
let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method =
let create_local_procdesc trans_unit_ctx cfg tenv ms fbody captured is_objc_inst_method =
let defined = not ((IList.length fbody) == 0) in
let proc_name = CMethod_signature.ms_get_name ms in
let pname = Procname.to_string proc_name in
@ -397,8 +398,8 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method =
let source_range = CMethod_signature.ms_get_loc ms in
Logging.out_debug "\nCreating a new procdesc for function: '%s'\n@." pname;
Logging.out_debug "\nms = %s\n@." (CMethod_signature.ms_to_string ms);
let loc_start = CLocation.get_sil_location_from_range source_range true in
let loc_exit = CLocation.get_sil_location_from_range source_range false in
let loc_start = CLocation.get_sil_location_from_range trans_unit_ctx source_range true in
let loc_exit = CLocation.get_sil_location_from_range trans_unit_ctx source_range false in
let ret_type = get_return_type tenv ms in
if skip_property_accessor ms then ()
else
@ -452,9 +453,10 @@ let create_external_procdesc cfg proc_name is_objc_inst_method type_opt =
let create_procdesc_with_pointer context pointer class_name_opt name =
let open CContext in
match method_signature_of_pointer context.tenv pointer with
match method_signature_of_pointer context.translation_unit_context context.tenv pointer with
| Some callee_ms ->
ignore (create_local_procdesc context.cfg context.tenv callee_ms [] [] false);
ignore (create_local_procdesc context.translation_unit_context context.cfg context.tenv
callee_ms [] [] false);
CMethod_signature.ms_get_name callee_ms
| None ->
let callee_name =
@ -462,12 +464,13 @@ let create_procdesc_with_pointer context pointer class_name_opt name =
| Some class_name ->
General_utils.mk_procname_from_cpp_method class_name name None
| None ->
General_utils.mk_procname_from_function name None in
General_utils.mk_procname_from_function context.translation_unit_context name None in
create_external_procdesc context.cfg callee_name false None;
callee_name
let add_default_method_for_class class_name decl_info =
let loc = CLocation.get_sil_location_from_range decl_info.Clang_ast_t.di_source_range true in
let add_default_method_for_class trans_unit_ctx class_name decl_info =
let loc = CLocation.get_sil_location_from_range trans_unit_ctx
decl_info.Clang_ast_t.di_source_range true in
let proc_name = Procname.get_default_objc_class_method class_name in
let attrs = { (ProcAttributes.default proc_name Config.Clang) with loc = loc; } in
AttributesTable.store_attributes attrs

@ -23,8 +23,9 @@ type method_call_type =
val should_add_return_param : Typ.t -> is_objc_method:bool -> bool
val create_local_procdesc : Cfg.cfg -> Tenv.t -> CMethod_signature.method_signature ->
Clang_ast_t.stmt list -> (Pvar.t * Typ.t) list -> bool -> bool
val create_local_procdesc : CFrontend_config.translation_unit_context -> Cfg.cfg -> Tenv.t ->
CMethod_signature.method_signature -> Clang_ast_t.stmt list -> (Pvar.t * Typ.t) list -> bool ->
bool
val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Typ.t * Typ.t list) option -> unit
@ -34,21 +35,23 @@ val get_objc_method_data : Clang_ast_t.obj_c_message_expr_info ->
val get_class_name_method_call_from_receiver_kind : CContext.t ->
Clang_ast_t.obj_c_message_expr_info -> (Exp.t * Typ.t) list -> string
val get_class_name_method_call_from_clang : Tenv.t -> Clang_ast_t.obj_c_message_expr_info ->
string option
val get_class_name_method_call_from_clang : CFrontend_config.translation_unit_context -> Tenv.t ->
Clang_ast_t.obj_c_message_expr_info -> string option
val method_signature_of_decl : Tenv.t -> Clang_ast_t.decl -> CModule_type.block_data option ->
val method_signature_of_decl : CFrontend_config.translation_unit_context -> Tenv.t ->
Clang_ast_t.decl -> CModule_type.block_data option ->
CMethod_signature.method_signature * Clang_ast_t.stmt option * CModule_type.instr_type list
val method_signature_of_pointer : Tenv.t -> Clang_ast_t.pointer ->
CMethod_signature.method_signature option
val method_signature_of_pointer : CFrontend_config.translation_unit_context -> Tenv.t ->
Clang_ast_t.pointer -> CMethod_signature.method_signature option
val get_method_name_from_clang : Tenv.t -> CMethod_signature.method_signature option ->
CMethod_signature.method_signature option
val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string option ->
string -> Procname.t
val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string option -> string ->
Procname.t
val add_default_method_for_class : string -> Clang_ast_t.decl_info -> unit
val add_default_method_for_class : CFrontend_config.translation_unit_context -> string ->
Clang_ast_t.decl_info -> unit
val get_procname_from_cpp_lambda : CContext.t -> Clang_ast_t.decl -> Procname.t

@ -30,9 +30,9 @@ sig
end
module type CFrontend = sig
val function_decl : Tenv.t -> Cfg.cfg -> Cg.t -> Clang_ast_t.decl ->
block_data option -> unit
val function_decl : CFrontend_config.translation_unit_context -> Tenv.t -> Cfg.cfg -> Cg.t ->
Clang_ast_t.decl -> block_data option -> unit
val translate_one_declaration : Tenv.t -> Cg.t -> Cfg.cfg ->
decl_trans_context -> Clang_ast_t.decl -> unit
val translate_one_declaration : CFrontend_config.translation_unit_context -> Tenv.t -> Cg.t ->
Cfg.cfg -> decl_trans_context -> Clang_ast_t.decl -> unit
end

@ -100,7 +100,7 @@ let eval_Atomic pred_name params an lcxt =
match pred_name, params, an with
| "call_method", [p1], Stmt st -> Predicates.call_method p1 st
| "property_name_contains_word", [p1] , Decl d -> Predicates.property_name_contains_word d p1
| "is_objc_extension", [], _ -> Predicates.is_objc_extension
| "is_objc_extension", [], _ -> Predicates.is_objc_extension lcxt
| "is_global_var", [], Decl d -> Predicates.is_syntactically_global_var d
| "is_const_var", [], Decl d -> Predicates.is_const_expr_var d
| "call_function_named", _, Stmt st -> Predicates.call_function_named st params

@ -32,7 +32,9 @@ struct
let method_kind = Procname.objc_method_kind_of_bool is_instance in
let ms_opt =
match method_pointer_opt with
| Some pointer -> CMethod_trans.method_signature_of_pointer context.tenv pointer
| Some pointer ->
CMethod_trans.method_signature_of_pointer context.translation_unit_context context.tenv
pointer
| None -> None in
let proc_name =
match CMethod_trans.get_method_name_from_clang context.tenv ms_opt with
@ -51,10 +53,12 @@ struct
None in
match predefined_ms_opt, ms_opt with
| Some ms, _ ->
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance);
ignore (CMethod_trans.create_local_procdesc context.translation_unit_context context.cfg
context.tenv ms [] [] is_instance);
CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual
| None, Some ms ->
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance);
ignore (CMethod_trans.create_local_procdesc context.translation_unit_context context.cfg
context.tenv ms [] [] is_instance);
if CMethod_signature.ms_is_getter ms || CMethod_signature.ms_is_setter ms then
proc_name, CMethod_trans.MCNoVirtual
else
@ -235,7 +239,8 @@ struct
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.tenv context.cg context.cfg `Translation decl;
F.translate_one_declaration context.translation_unit_context context.tenv context.cg context.cfg
`Translation decl;
Ident.NameGenerator.set_current ident_state
let mk_temp_sil_var procdesc var_name_suffix =
@ -419,7 +424,7 @@ struct
let root_node' = GotoLabel.find_goto_label trans_state.context label_name sil_loc in
{ empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes }
let get_builtin_pname_opt name decl_opt type_ptr =
let get_builtin_pname_opt trans_unit_ctx name decl_opt type_ptr =
let get_deprecated_attr_arg decl =
let open Clang_ast_t in
let decl_info = Clang_ast_proj.get_decl_tuple decl in
@ -444,7 +449,7 @@ struct
| _ when CTrans_models.is_retain_builtin name type_ptr ->
Some ModelBuiltins.__objc_retain_cf
| _ when name = CFrontend_config.malloc &&
General_utils.is_objc_extension ->
General_utils.is_objc_extension trans_unit_ctx ->
Some ModelBuiltins.malloc_no_fail
| _ -> None
@ -457,7 +462,8 @@ struct
Option.may (call_translation context) decl_opt;
let name = Ast_utils.get_qualified_name name_info in
let typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in
let pname = match get_builtin_pname_opt name decl_opt type_ptr with
let pname =
match get_builtin_pname_opt context.translation_unit_context name decl_opt type_ptr with
| Some builtin_pname -> builtin_pname
| None -> CMethod_trans.create_procdesc_with_pointer context decl_ptr None name in
{ empty_res_trans with exps = [(Exp.Const (Const.Cfun pname), typ)] }
@ -510,7 +516,8 @@ struct
let class_name = Ast_utils.get_class_name_from_member name_info in
Logging.out_debug "!!!!! Dealing with method '%s' @." method_name;
let method_typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in
let ms_opt = CMethod_trans.method_signature_of_pointer context.tenv decl_ptr in
let ms_opt = CMethod_trans.method_signature_of_pointer
context.translation_unit_context context.tenv decl_ptr in
let is_instance_method = match ms_opt with
| Some ms -> CMethod_signature.ms_is_instance ms
| _ -> true (* might happen for methods that are not exported yet (some templates). *) in
@ -542,7 +549,9 @@ struct
(* use qualified method name for builtin matching, but use unqualified name elsewhere *)
let qual_method_name = Ast_utils.get_qualified_name name_info in
let pname = match get_builtin_pname_opt qual_method_name decl_opt type_ptr with
let pname =
match get_builtin_pname_opt context.translation_unit_context qual_method_name decl_opt
type_ptr with
| Some builtin_pname -> builtin_pname
| None ->
CMethod_trans.create_procdesc_with_pointer context decl_ptr (Some class_name)
@ -562,7 +571,8 @@ struct
cxx_record_info.xrdi_destructor
| _ -> None in
match destruct_decl_ref_opt with
| Some decl_ref -> method_deref_trans trans_state pvar_trans_result decl_ref si `CXXDestructor
| Some decl_ref ->
method_deref_trans trans_state pvar_trans_result decl_ref si `CXXDestructor
| None -> empty_res_trans
let this_expr_trans trans_state sil_loc class_type_ptr =
@ -599,7 +609,7 @@ struct
let typ =
match ast_typ with
| Tstruct _ when decl_ref.dr_kind = `ParmVar ->
if General_utils.is_cpp_translation then
if General_utils.is_cpp_translation context.translation_unit_context then
Typ.Tptr (ast_typ, Pk_reference)
else ast_typ
| _ -> ast_typ in
@ -617,7 +627,8 @@ struct
match Ast_utils.get_decl decl_ref.dr_decl_pointer with
| Some VarDecl (_, _, qual_type, vdi) -> (
match ast_typ with
| Tstruct _ when not General_utils.is_cpp_translation ->
| Tstruct _
when not (General_utils.is_cpp_translation context.translation_unit_context) ->
(* Do not convert a global struct to a local because SIL
values do not include structs, they must all be heap-allocated *)
false, None
@ -649,7 +660,8 @@ struct
match decl_kind with
| `EnumConstant -> enum_constant_trans trans_state decl_ref
| `Function -> function_deref_trans trans_state decl_ref
| `Var | `ImplicitParam | `ParmVar -> var_deref_trans trans_state stmt_info decl_ref
| `Var | `ImplicitParam | `ParmVar ->
var_deref_trans trans_state stmt_info decl_ref
| `Field | `ObjCIvar ->
field_deref_trans trans_state stmt_info pre_trans_result decl_ref ~is_constructor_init
| `CXXMethod | `CXXConversion | `CXXConstructor | `CXXDestructor ->
@ -790,7 +802,7 @@ struct
if (is_binary_assign_op binary_operator_info)
(* assignment operator result is lvalue in CPP, rvalue in C, *)
(* hence the difference *)
&& (not General_utils.is_cpp_translation)
&& (not (General_utils.is_cpp_translation context.translation_unit_context))
&& ((not creating_node) || (is_return_temp trans_state.continuation)) then (
(* We are in this case when an assignment is inside *)
(* another operator that creates a node. Eg. another *)
@ -1005,7 +1017,7 @@ struct
| `Class type_ptr ->
let class_opt =
CMethod_trans.get_class_name_method_call_from_clang
context.CContext.tenv obj_c_message_expr_info in
context.translation_unit_context context.CContext.tenv obj_c_message_expr_info in
Some (new_or_alloc_trans trans_state_pri sil_loc si type_ptr class_opt selector)
| _ -> None
(* assertions *)
@ -1850,7 +1862,8 @@ struct
CTypes_decl.type_ptr_to_sil_type
context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let exp_op, instr_op =
CArithmetic_trans.unary_operation_instruction unary_operator_info sil_e' ret_typ sil_loc in
CArithmetic_trans.unary_operation_instruction
context.translation_unit_context unary_operator_info sil_e' ret_typ sil_loc in
let unary_op_res_trans = { empty_res_trans with instrs = instr_op } in
let all_res_trans = [ res_trans_stmt; unary_op_res_trans ] in
let nname = "UnaryOperator" in
@ -2004,7 +2017,8 @@ struct
let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc in
let loc =
(match stmt_info.Clang_ast_t.si_source_range with (l1, _) ->
CLocation.clang_to_sil_location l1 (Some context.CContext.procdesc)) in
CLocation.clang_to_sil_location context.CContext.translation_unit_context l1
(Some context.CContext.procdesc)) in
(* Given a captured var, return the instruction to assign it to a temp *)
let assign_captured_var (cvar, typ) =
let id = Ident.create_fresh Ident.knormal in
@ -2024,7 +2038,8 @@ struct
let ids_instrs = IList.map assign_captured_var captureds in
let ids, instrs = IList.split ids_instrs in
let block_data = (context, type_ptr, block_pname, captureds) in
F.function_decl context.tenv context.cfg context.cg decl (Some block_data);
F.function_decl context.translation_unit_context context.tenv context.cfg context.cg decl
(Some block_data);
let captured_vars =
IList.map2 (fun id (pvar, typ) -> (Exp.Var id, pvar, typ)) ids captureds in
let closure = Exp.Closure { name=block_pname; captured_vars } in
@ -2622,13 +2637,14 @@ struct
(Ast_utils.string_of_stmt s);
assert false)
(* Function similar to instruction function, but it takes C++ constructor initializer as *)
(* an input parameter. *)
(* Function similar to instruction function, but it takes C++ constructor initializer as
an input parameter. *)
and cxx_constructor_init_trans ctor_init trans_state =
(*let tenv = trans_state.context.CContext.tenv in*)
let class_ptr = CContext.get_curr_class_decl_ptr trans_state.context.CContext.curr_class in
let context = trans_state.context in
let class_ptr = CContext.get_curr_class_decl_ptr context.CContext.curr_class in
let source_range = ctor_init.Clang_ast_t.xci_source_range in
let sil_loc = CLocation.get_sil_location_from_range source_range true in
let sil_loc = CLocation.get_sil_location_from_range context.CContext.translation_unit_context
source_range true in
(* its pointer will be used in PriorityNode *)
let this_stmt_info = Ast_expressions.dummy_stmt_info () in
(* this will be used to avoid creating node in init_expr_trans *)

@ -71,7 +71,8 @@ let property_name_contains_word decl word =
with Not_found -> false)
| _ -> false
let is_objc_extension = General_utils.is_objc_extension
let is_objc_extension lcxt =
General_utils.is_objc_extension lcxt.CLintersContext.translation_unit_context
let is_syntactically_global_var decl =
Ast_utils.is_syntactically_global_var decl

@ -15,7 +15,7 @@ val call_method : string -> Clang_ast_t.stmt -> bool
val property_name_contains_word : Clang_ast_t.decl -> string -> bool
val is_objc_extension : bool
val is_objc_extension : CLintersContext.context -> bool
val is_syntactically_global_var : Clang_ast_t.decl -> bool

@ -192,5 +192,5 @@ let get_compilation_database changed_files =
let () =
let changed_files = read_files_to_compile () in
let compilation_database = get_compilation_database changed_files in
DB.create_dir (Config.results_dir // Config.clang_build_output_dir_name);
create_dir (Config.results_dir // Config.clang_build_output_dir_name);
run_compilation_database compilation_database

@ -26,8 +26,8 @@ let register_perf_stats_report source_file =
let stats_dir = Filename.concat Config.results_dir Config.frontend_stats_dir_name in
let abbrev_source_file = DB.source_file_encoding source_file in
let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in
DB.create_dir Config.results_dir ;
DB.create_dir stats_dir ;
create_dir Config.results_dir ;
create_dir stats_dir ;
PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file)

@ -13,8 +13,8 @@ let register_perf_stats_report source_file =
let stats_dir = Filename.concat Config.results_dir Config.frontend_stats_dir_name in
let abbrev_source_file = DB.source_file_encoding source_file in
let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in
DB.create_dir Config.results_dir ;
DB.create_dir stats_dir ;
create_dir Config.results_dir ;
create_dir stats_dir ;
PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file)
let init_global_state source_file =

@ -180,9 +180,9 @@ let () = {
let aggregated_frontend_stats_dir = Filename.concat infer_out Config.frontend_stats_dir_name;
let aggregated_backend_stats_dir = Filename.concat infer_out Config.backend_stats_dir_name;
let aggregated_reporting_stats_dir = Filename.concat infer_out Config.reporting_stats_dir_name;
DB.create_dir aggregated_frontend_stats_dir;
DB.create_dir aggregated_backend_stats_dir;
DB.create_dir aggregated_reporting_stats_dir;
create_dir aggregated_frontend_stats_dir;
create_dir aggregated_backend_stats_dir;
create_dir aggregated_reporting_stats_dir;
let write_to_json_file_opt destfile json =>
switch json {
| Some j => Utils.write_json_to_file destfile j

Loading…
Cancel
Save