[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 module F = Format;
let () = { let () = {
Logging.set_log_file_identifier (Option.map Filename.basename Config.cluster_cmdline);
if Config.print_builtins { if Config.print_builtins {
Builtin.print_and_exit () 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_base = Config.perf_stats_prefix ^ "_" ^ Filename.basename cluster ^ ".json";
let stats_file = Filename.concat stats_dir stats_base; let stats_file = Filename.concat stats_dir stats_base;
DB.create_dir Config.results_dir; create_dir Config.results_dir;
DB.create_dir stats_dir; create_dir stats_dir;
PerfStats.register_report_at_exit stats_file PerfStats.register_report_at_exit stats_file
}; };

@ -1263,8 +1263,8 @@ let compute_top_procedures = ref false;
let register_perf_stats_report () => { let register_perf_stats_report () => {
let stats_dir = Filename.concat Config.results_dir Config.reporting_stats_dir_name; 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"); let stats_file = Filename.concat stats_dir (Config.perf_stats_prefix ^ ".json");
DB.create_dir Config.results_dir; create_dir Config.results_dir;
DB.create_dir stats_dir; create_dir stats_dir;
PerfStats.register_report_at_exit stats_file 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. *) found in that file, and exits, with default code 1 or a given code. *)
let print_error_and_exit ?(exit_code=1) f el = let print_error_and_exit ?(exit_code=1) f el =
Logging.do_err f el; Logging.do_err f el;
let log_file = snd (Config.tmp_log_files_of_current_exe ()) in let log_file = snd (Logging.log_file_names ()) in
Logging.stderr "\nAn error occured. Please, find details in %s\n\n%!" log_file; Logging.stderr "@\nAn error occured. Please find details in %s@\n@\n%!" log_file;
exit exit_code exit exit_code
(** Executes a command and catches a potential exeption and prints it. *) (** 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 | None -> None
| Some file -> | Some file ->
let crashcontext_dir = Config.results_dir // "crashcontext" in let crashcontext_dir = Config.results_dir // "crashcontext" in
DB.create_dir crashcontext_dir; create_dir crashcontext_dir;
Some (file, crashcontext_dir // "crashcontext.json") in Some (file, crashcontext_dir // "crashcontext.json") in
let trace_file_regexp = Str.regexp "\\(.*\\)\\.json" in let trace_file_regexp = Str.regexp "\\(.*\\)\\.json" in
let pairs_for_stactrace_dir = match stacktraces_dir with let pairs_for_stactrace_dir = match stacktraces_dir with

@ -1540,64 +1540,6 @@ let patterns_suppress_warnings =
if CLOpt.(current_exe <> Java) then [] if CLOpt.(current_exe <> Java) then []
else error ("Error: The option " ^ suppress_warnings_annotations_long ^ " was not provided") 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 *) (** Global variables *)

@ -310,13 +310,3 @@ val curr_language : language ref
(** Command Line Interface Documentation *) (** Command Line Interface Documentation *)
val print_usage_exit : unit -> 'a 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; Logging.do_err "File %s does not exist." fname;
exit 1 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 filename_create_dir fname =
let dirname = Filename.dirname fname in let dirname = Filename.dirname fname in
if not (Sys.file_exists dirname) if not (Sys.file_exists dirname)
then create_dir 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 read_whole_file fd =
let stats = Unix.fstat fd in let stats = Unix.fstat fd in
let size = stats.Unix.st_size 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 *) (** Find the source directories in the current results dir *)
val find_source_dirs : unit -> source_dir list 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. *) (** Read a file using a lock to allow write attempts in parallel. *)
val read_file_with_lock : string -> string -> bytes option val read_file_with_lock : string -> string -> bytes option

@ -14,6 +14,73 @@ open! Utils
module F = Format 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 of printable elements *)
type print_type = type print_type =
| PTatom | PTatom
@ -64,52 +131,10 @@ let delayed_actions = ref []
(** hook for the current printer of delayed print actions *) (** hook for the current printer of delayed print actions *)
let printer_hook = ref (Obj.magic ()) 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 *) (** extend the current print log *)
let add_print_action pact = let add_print_action pact =
if Config.write_html then delayed_actions := pact :: !delayed_actions 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 *) (** reset the delayed print actions *)
let reset_delayed_prints () = let reset_delayed_prints () =
@ -123,50 +148,41 @@ let get_delayed_prints () =
let set_delayed_prints new_delayed_actions = let set_delayed_prints new_delayed_actions =
delayed_actions := new_delayed_actions delayed_actions := new_delayed_actions
let do_print fmt fmt_string = let do_print = F.fprintf
F.fprintf fmt fmt_string
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 if Config.debug_mode || Config.stats_mode then
F.fprintf fmt fmt_string F.fprintf
else 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 if Config.debug_mode then
F.fprintf fmt fmt_string F.fprintf
else 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 = 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 = 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 = 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 = 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 = 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 = 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 = let stderr fmt_string =
do_print F.err_formatter fmt_string do_print F.err_formatter fmt_string
(** print immediately to standard output *)
let stdout fmt_string = let stdout fmt_string =
do_print F.std_formatter 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 *) (** reset the delayed print actions *)
val reset_delayed_prints : unit -> unit 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) *) (note: only prints in debug or in stats mode) *)
val out : ('a, Format.formatter, unit) format -> 'a 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) *) (note: only prints in debug mode) *)
val out_debug : ('a, Format.formatter, unit) format -> 'a 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) *) (note: only prints in debug or stats mode) *)
val err : ('a, Format.formatter, unit) format -> 'a 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 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 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 val do_err : ('a, Format.formatter, unit) format -> 'a
(** print immediately to standard error *) (** 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. *) (** Progress bar: log a timeout event if in developer mode. *)
val log_progress_timeout_event : SymOp.failure_kind -> unit 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 = let invalid_argf fmt =
Format.kfprintf (fun _ -> invalid_arg (Format.flush_str_formatter ())) Format.kfprintf (fun _ -> invalid_arg (Format.flush_str_formatter ()))
Format.str_formatter fmt 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 failwithf : ('a, Format.formatter, unit, 'b) format4 -> 'a
val invalid_argf : ('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 = let extract to_path =
if not (Sys.file_exists to_path) then if not (Sys.file_exists to_path) then
begin 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 lazy zip_channel = zip_library.Config.zip_channel in
let entry = Zip.find_entry zip_channel zip_path in let entry = Zip.find_entry zip_channel zip_path in
Zip.copy_entry_to_file zip_channel entry to_path Zip.copy_entry_to_file zip_channel entry to_path

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

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

@ -10,10 +10,11 @@
open CFrontend_utils open CFrontend_utils
open !Utils open !Utils
let is_ck_context context decl = let is_ck_context {CLintersContext.is_ck_translation_unit; translation_unit_context} decl =
context.CLintersContext.is_ck_translation_unit is_ck_translation_unit
&& Ast_utils.is_in_main_file decl && Ast_utils.is_in_main_file translation_unit_context decl
&& General_utils.is_objc_extension && General_utils.is_objc_extension translation_unit_context
(** Recursively go up the inheritance hierarchy of a given ObjCInterfaceDecl. (** Recursively go up the inheritance hierarchy of a given ObjCInterfaceDecl.
(Returns false on decls other than that one.) *) (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.description = "Local variables should be const to avoid reassignment";
CIssue.suggestion = Some "Add a const (after the asterisk for pointer types). \ CIssue.suggestion = Some "Add a const (after the asterisk for pointer types). \
http://componentkit.org/docs/avoid-local-variables.html"; 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 else None
| _ -> assert false (* Should only be called with a VarDecl *) | _ -> 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. \ that return a CKComponent subclass. \
http://componentkit.org/docs/break-out-composites.html" 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 else None
| _ -> assert false (* Should only be called with FunctionDecl *) | _ -> 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); (Clang_ast_j.string_of_binary_operator_kind bok);
(Exp.minus_one, []) (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 uok = Clang_ast_j.string_of_unary_operator_kind (uoi.Clang_ast_t.uoi_kind) in
let un_exp op = let un_exp op =
Exp.UnOp(op, e, Some typ) in 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 id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) 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 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 e
else else
e_plus_1 in 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 id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) 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 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 e
else else
e_minus_1 in e_minus_1 in

@ -17,7 +17,7 @@ val binary_operation_instruction :
Clang_ast_t.binary_operator_info -> Exp.t -> Typ.t -> Exp.t -> Clang_ast_t.binary_operator_info -> Exp.t -> Typ.t -> Exp.t ->
Location.t -> bool -> Exp.t * Sil.instr list 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 Clang_ast_t.unary_operator_info -> Exp.t -> Typ.t -> Location.t -> Exp.t * Sil.instr list
val assignment_arc_mode : val assignment_arc_mode :

@ -26,6 +26,7 @@ type str_node_map = (string, Cfg.Node.t) Hashtbl.t
type t = type t =
{ {
translation_unit_context : CFrontend_config.translation_unit_context;
tenv : Tenv.t; tenv : Tenv.t;
cg : Cg.t; cg : Cg.t;
cfg : Cfg.cfg; cfg : Cfg.cfg;
@ -33,20 +34,16 @@ type t =
is_objc_method : bool; is_objc_method : bool;
curr_class: curr_class; curr_class: curr_class;
return_param_typ : Typ.t option; 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; mutable blocks_static_vars : ((Pvar.t * Typ.t) list) Procname.Map.t;
label_map : str_node_map; label_map : str_node_map;
} }
let create_context tenv cg cfg procdesc curr_class return_param_typ is_objc_method context_opt = let create_context translation_unit_context tenv cg cfg procdesc curr_class return_param_typ
{ tenv = tenv; is_objc_method outer_context =
cg = cg; { translation_unit_context; tenv; cg; cfg; procdesc; curr_class; return_param_typ;
cfg = cfg; is_objc_method; outer_context;
procdesc = procdesc;
curr_class = curr_class;
return_param_typ = return_param_typ;
is_objc_method = is_objc_method;
outer_context = context_opt;
blocks_static_vars = Procname.Map.empty; blocks_static_vars = Procname.Map.empty;
label_map = Hashtbl.create 17; label_map = Hashtbl.create 17;
} }

@ -24,6 +24,7 @@ type str_node_map = (string, Cfg.Node.t) Hashtbl.t
type t = type t =
{ {
translation_unit_context : CFrontend_config.translation_unit_context;
tenv : Tenv.t; tenv : Tenv.t;
cg : Cg.t; cg : Cg.t;
cfg : Cfg.cfg; cfg : Cfg.cfg;
@ -31,7 +32,8 @@ type t =
is_objc_method : bool; is_objc_method : bool;
curr_class: curr_class; curr_class: curr_class;
return_param_typ : Typ.t option; 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; mutable blocks_static_vars : ((Pvar.t * Typ.t) list) Procname.Map.t;
label_map : str_node_map; label_map : str_node_map;
} }
@ -58,8 +60,8 @@ val is_objc_method : t -> bool
val get_tenv : t -> Tenv.t val get_tenv : t -> Tenv.t
val create_context : Tenv.t -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t -> val create_context : CFrontend_config.translation_unit_context -> Tenv.t -> Cg.t -> Cfg.cfg ->
curr_class -> Typ.t option -> bool -> t option -> t Cfg.Procdesc.t -> curr_class -> Typ.t option -> bool -> t option -> t
val create_curr_class : Tenv.t -> string -> Csu.class_kind -> curr_class 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) CFrontend_decl.CFrontend_decl_funct(CTransImpl)
(* Translates a file by translating the ast into a cfg. *) (* 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 match ast with
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> | Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) ->
CFrontend_config.global_translation_unit_decls := decl_list; CFrontend_config.global_translation_unit_decls := decl_list;
Logging.out_debug "@\n Start creating icfg@\n"; 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 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; decl_list;
Logging.out_debug "\n Finished creating icfg\n"; Logging.out_debug "\n Finished creating icfg\n";
(cg, cfg) (cg, cfg)
@ -38,14 +39,15 @@ let init_global_state_capture () =
CFrontend_config.global_translation_unit_decls := []; CFrontend_config.global_translation_unit_decls := [];
CFrontend_utils.General_utils.reset_block_counter () 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 let tenv = Tenv.create () in
CTypes_decl.add_predefined_types tenv; CTypes_decl.add_predefined_types tenv;
init_global_state_capture (); 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); 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" Logging.out_debug "@\n Start building call/cfg graph for '%s'....@\n"
(DB.source_file_to_string source_file); (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" Logging.out_debug "@\n End building call/cfg graph for '%s'.@\n"
(DB.source_file_to_string source_file); (DB.source_file_to_string source_file);
(* This part below is a boilerplate in every frontends. *) (* 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 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 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. *) 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 *) (* - If it is a declaration invoke it from run_frontend_checkers_on_decl *)
(* Helper functions *) (* Helper functions *)
let location_from_stmt stmt = let location_from_stmt lctx stmt =
let info, _ = Clang_ast_proj.get_stmt_tuple stmt in 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 = let location_from_dinfo lctx info =
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 location_from_decl dec = let location_from_decl lctx dec =
let info = Clang_ast_proj.get_decl_tuple dec in 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 = let decl_name dec =
match Clang_ast_proj.get_named_decl_tuple dec with 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 ET([ObjCMethodDecl][->Body] EF remove_observer) Or
EH([ObjCImplementationDecl, ObjCProtocolDecl] EF remove_observer) EH([ObjCImplementationDecl, ObjCProtocolDecl] EF remove_observer)
*) *)
let ctl_ns_notification decl = let ctl_ns_notification lctx decl =
let open CTL in let open CTL in
let exists_method_calling_addObserver = let exists_method_calling_addObserver =
EF (Atomic ("call_method", ["addObserver:selector:name:object:"])) in 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; Localise.registered_observer_being_deallocated_str CFrontend_config.self;
CIssue.suggestion = CIssue.suggestion =
Some "Consider removing the object from the notification center before its deallocation."; 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 } in
condition, issue_desc condition, issue_desc
(* BAD_POINTER_COMPARISON: Fires whenever a NSNumber is dangerously coerced to (* BAD_POINTER_COMPARISON: Fires whenever a NSNumber is dangerously coerced to
a boolean in a comparison *) 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 open CTL in
let is_binop = Atomic ("is_stmt", ["BinaryOperator"]) in let is_binop = Atomic ("is_stmt", ["BinaryOperator"]) in
let is_binop_eq = Atomic ("is_binop_with_kind", ["EQ"]) 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? " ^ Some ("Did you mean to compare against the unboxed value instead? " ^
"Please either explicitly compare the NSNumber instance to nil, " ^ "Please either explicitly compare the NSNumber instance to nil, " ^
"or use one of the NSNumber accessors before the comparison."); "or use one of the NSNumber accessors before the comparison.");
loc = location_from_stmt stmt loc = location_from_stmt lctx stmt
} in } in
condition, issue_desc condition, issue_desc
(* name_contains_delegate AND not name_contains_queue AND is_strong_property *) (* 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 open CTL in
let name_contains_delegate = let name_contains_delegate =
Atomic ("property_name_contains_word", ["delegate"]) in Atomic ("property_name_contains_word", ["delegate"]) in
@ -155,14 +158,14 @@ let ctl_strong_delegate dec =
CIssue.description = Printf.sprintf CIssue.description = Printf.sprintf
"Property or ivar %s declared strong" (decl_name dec); "Property or ivar %s declared strong" (decl_name dec);
CIssue.suggestion = Some "In general delegates should be declared weak or assign"; 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 } in
condition, issue_desc condition, issue_desc
(* (is_ObjC || is_Objc++) /\ is_global_var /\ not is_const_var /\ (* (is_ObjC || is_Objc++) /\ is_global_var /\ not is_const_var /\
ET([VarDecl][->InitExpr] EF ctl_makes_an_expensive_call) 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 open CTL in
let ctl_is_global_var = let ctl_is_global_var =
And (And (Atomic ("is_objc_extension", []), Atomic ("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); (decl_name decl);
CIssue.suggestion = Some CIssue.suggestion = Some
"If the function/method call is expensive, it can affect the starting time of the app."; "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 } in
condition, issue_desc condition, issue_desc
(* is_assign_property AND is_property_pointer_type *) (* 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 open CTL in
let condition = let condition =
And (Atomic("is_assign_property", []), Atomic("is_property_pointer_type", [])) in 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" "Property `%s` is a pointer type marked with the `assign` attribute"
(decl_name decl); (decl_name decl);
CIssue.suggestion = Some "Use a different attribute like `strong` or `weak`."; 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 } in
condition, issue_desc 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 context_in_synchronized_block /\ not is_method_property_accessor_of_ivar
/\ not is_objc_constructor /\ not is_objc_dealloc /\ 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 open CTL in
let condition = let condition =
And (And (And (And (Not (Atomic ("context_in_synchronized_block", [])), 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); "Direct access to ivar %s of an atomic property" (ivar_name stmt);
CIssue.suggestion = CIssue.suggestion =
Some "Accessing an ivar of an atomic property makes the property nonatomic"; 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 } in
condition, issue_desc 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 *) (* Fire if the list of captured references is not empty *)
let condition = CTL.Atomic ("captures_cxx_references", []) in let condition = CTL.Atomic ("captures_cxx_references", []) in
let issue_desc = { let issue_desc = {
@ -229,24 +232,24 @@ let ctl_captured_cxx_ref_in_objc_block_warning stmt =
(Predicates.var_descs_name stmt); (Predicates.var_descs_name stmt);
CIssue.suggestion = Some ("C++ References are unmanaged and may be invalid " ^ CIssue.suggestion = Some ("C++ References are unmanaged and may be invalid " ^
"by the time the block executes."); "by the time the block executes.");
CIssue.loc = location_from_stmt stmt CIssue.loc = location_from_stmt lctx stmt
} in } in
condition, issue_desc condition, issue_desc
(* === Warnings on properties === *) (* === Warnings on properties === *)
(* Assing Pointer Warning: a property with a pointer type should not be declared `assign` *) (* 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 open CTL in
let condition, issue_desc = ctl_assign_pointer_warning decl in let condition, issue_desc = ctl_assign_pointer_warning lctx decl in
if CTL.eval_formula condition (Decl decl) lcxt then if CTL.eval_formula condition (Decl decl) lctx then
Some issue_desc Some issue_desc
else None else None
(* Strong Delegate Warning: a property with name delegate should not be declared strong *) (* Strong Delegate Warning: a property with name delegate should not be declared strong *)
let strong_delegate_warning lcxt decl = let strong_delegate_warning lctx decl =
let condition, issue_desc = ctl_strong_delegate decl in let condition, issue_desc = ctl_strong_delegate lctx decl in
if CTL.eval_formula condition (Decl decl) lcxt then if CTL.eval_formula condition (Decl decl) lctx then
Some issue_desc Some issue_desc
else None else None
@ -254,36 +257,36 @@ let strong_delegate_warning lcxt decl =
(* a global variable initialization should not *) (* a global variable initialization should not *)
(* contain calls to functions or methods as these can be expensive an delay the starting time *) (* contain calls to functions or methods as these can be expensive an delay the starting time *)
(* of an app *) (* of an app *)
let global_var_init_with_calls_warning lcxt decl = let global_var_init_with_calls_warning lctx decl =
let condition, issue_desc = ctl_global_var_init_with_calls_warning decl in let condition, issue_desc = ctl_global_var_init_with_calls_warning lctx decl in
if CTL.eval_formula condition (CTL.Decl decl) lcxt then if CTL.eval_formula condition (CTL.Decl decl) lctx then
Some issue_desc Some issue_desc
else None else None
(* Direct Atomic Property access: (* Direct Atomic Property access:
a property declared atomic should not be accessed directly via its ivar *) a property declared atomic should not be accessed directly via its ivar *)
let direct_atomic_property_access_warning context stmt = let direct_atomic_property_access_warning lctx stmt =
let condition, issue_desc = ctl_direct_atomic_property_access_warning stmt in let condition, issue_desc = ctl_direct_atomic_property_access_warning lctx stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) context then if CTL.eval_formula condition (CTL.Stmt stmt) lctx then
Some issue_desc Some issue_desc
else None else None
(* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references (* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references
should not be captured in blocks. *) should not be captured in blocks. *)
let captured_cxx_ref_in_objc_block_warning lcxt stmt = let captured_cxx_ref_in_objc_block_warning lctx stmt =
let condition, issue_desc = ctl_captured_cxx_ref_in_objc_block_warning stmt in let condition, issue_desc = ctl_captured_cxx_ref_in_objc_block_warning lctx stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lcxt then if CTL.eval_formula condition (CTL.Stmt stmt) lctx then
Some issue_desc Some issue_desc
else None else None
let checker_NSNotificationCenter lcxt dec = let checker_NSNotificationCenter lctx dec =
let condition, issue_desc = ctl_ns_notification dec in let condition, issue_desc = ctl_ns_notification lctx dec in
if CTL.eval_formula condition (CTL.Decl dec) lcxt then if CTL.eval_formula condition (CTL.Decl dec) lctx then
Some issue_desc Some issue_desc
else None else None
let bad_pointer_comparison_warning lcxt stmt = let bad_pointer_comparison_warning lctx stmt =
let condition, issue_desc = ctl_bad_pointer_comparison_warning stmt in let condition, issue_desc = ctl_bad_pointer_comparison_warning lctx stmt in
if CTL.eval_formula condition (CTL.Stmt stmt) lcxt then if CTL.eval_formula condition (CTL.Stmt stmt) lctx then
Some issue_desc Some issue_desc
else None else None

@ -44,4 +44,4 @@ val global_var_init_with_calls_warning :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc option
val location_from_dinfo : 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 = and do_frontend_checks_decl context decl =
let open Clang_ast_t in let open Clang_ast_t in
let info = Clang_ast_proj.get_decl_tuple decl 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' = let context' =
(match decl with (match decl with
| FunctionDecl(_, _, _, fdi) | FunctionDecl(_, _, _, fdi)
@ -74,20 +74,22 @@ let context_with_ck_set context decl_list =
let store_issues source_file = let store_issues source_file =
let abbrev_source_file = DB.source_file_encoding source_file in let abbrev_source_file = DB.source_file_encoding source_file in
let lint_issues_dir = Config.results_dir // Config.lint_issues_dir_name 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 = let lint_issues_file =
DB.filename_from_string (Filename.concat lint_issues_dir (abbrev_source_file ^ ".issue")) in DB.filename_from_string (Filename.concat lint_issues_dir (abbrev_source_file ^ ".issue")) in
LintIssues.store_issues lint_issues_file !LintIssues.errLogMap LintIssues.store_issues lint_issues_file !LintIssues.errLogMap
let do_frontend_checks source_file ast = let do_frontend_checks trans_unit_ctx ast =
try 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); Logging.out "Start linting file %s@\n" (DB.source_file_to_string source_file);
match ast with match ast with
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> | 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 is_decl_allowed decl =
let decl_info = Clang_ast_proj.get_decl_tuple decl in 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 let allowed_decls = IList.filter is_decl_allowed decl_list in
IList.iter (do_frontend_checks_decl context) allowed_decls; IList.iter (do_frontend_checks_decl context) allowed_decls;
if (LintIssues.exists_issues ()) then if (LintIssues.exists_issues ()) then

@ -7,4 +7,4 @@
* of patent rights can be found in the PATENTS file in the same directory. * 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 *) (** 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 *) (** Constants *)
let alloc = "alloc" let alloc = "alloc"
@ -78,7 +83,6 @@ let modeled_function_attributes = [replace_with_deref_first_arg_attr]
(** Global state *) (** Global state *)
let current_source = ref DB.source_file_empty
let enum_map = ref Clang_ast_main.PointerMap.empty let enum_map = ref Clang_ast_main.PointerMap.empty
let global_translation_unit_decls : Clang_ast_t.decl list ref = ref [] let global_translation_unit_decls : Clang_ast_t.decl list ref = ref []
let ivar_to_property_index = ref Clang_ast_main.PointerMap.empty 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 *) (** 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 *) (** Constants *)
val alloc : string val alloc : string
@ -79,8 +84,6 @@ val modeled_function_attributes : string list
(** Global state *) (** Global state *)
val current_source : DB.source_file ref
(** Map from enum constants pointers to their predecesor and their sil value *) (** 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 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 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 Specs.summary_exists_in_models procname && not Config.models_mode
(* Translates the method/function's body into nodes of the cfg. *) (* 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 let add_method trans_unit_ctx tenv cg cfg class_decl_opt procname body has_return_param
outer_context_opt extra_instrs = is_objc_method outer_context_opt extra_instrs =
Logging.out_debug Logging.out_debug
"@\n@\n>>---------- ADDING METHOD: '%s' ---------<<@\n@." (Procname.to_string procname); "@\n@\n>>---------- ADDING METHOD: '%s' ---------<<@\n@." (Procname.to_string procname);
try try
@ -30,7 +30,7 @@ struct
| Some procdesc -> | Some procdesc ->
if (Cfg.Procdesc.is_defined procdesc && not (model_exists procname)) then if (Cfg.Procdesc.is_defined procdesc && not (model_exists procname)) then
(let context = (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 has_return_param is_objc_method outer_context_opt in
let start_node = Cfg.Procdesc.get_start_node procdesc in let start_node = Cfg.Procdesc.get_start_node procdesc in
let exit_node = Cfg.Procdesc.get_exit_node procdesc in let exit_node = Cfg.Procdesc.get_exit_node procdesc in
@ -45,44 +45,49 @@ struct
with with
| Not_found -> () | Not_found -> ()
| CTrans_utils.Self.SelfClassException _ -> | 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) -> | Assert_failure (file, line, column) ->
Logging.out "Fatal error: exception Assert_failure(%s, %d, %d)\n%!" file line column; Logging.out "Fatal error: exception Assert_failure(%s, %d, %d)\n%!" file line column;
Cfg.Procdesc.remove cfg procname true; Cfg.Procdesc.remove cfg procname true;
CMethod_trans.create_external_procdesc cfg procname is_objc_method None; 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 = let captured_vars, outer_context_opt =
match block_data_opt with match block_data_opt with
| Some (outer_context, _, _, captured_vars) -> captured_vars, Some outer_context | Some (outer_context, _, _, captured_vars) -> captured_vars, Some outer_context
| None -> [], None in | None -> [], None in
let ms, body_opt, extra_instrs = 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 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 procname = CMethod_signature.ms_get_name ms in
let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ 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 if CMethod_trans.create_local_procdesc
add_method tenv cg cfg CContext.ContextNoCls procname body return_param_typ_opt false trans_unit_ctx cfg tenv ms [body] captured_vars false then
outer_context_opt extra_instrs add_method trans_unit_ctx tenv cg cfg CContext.ContextNoCls procname body
return_param_typ_opt false outer_context_opt extra_instrs
| None -> () | 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 = 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 match body_opt with
| Some body -> | Some body ->
let is_instance = CMethod_signature.ms_is_instance ms in let is_instance = CMethod_signature.ms_is_instance ms in
let procname = CMethod_signature.ms_get_name ms in let procname = CMethod_signature.ms_get_name ms in
let is_objc_inst_method = is_instance && is_objc 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 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 if CMethod_trans.create_local_procdesc
add_method tenv cg cfg curr_class procname body return_param_typ_opt is_objc trans_unit_ctx cfg tenv ms [body] [] is_objc_inst_method then
None extra_instrs add_method trans_unit_ctx tenv cg cfg curr_class procname body return_param_typ_opt
is_objc None extra_instrs
| None -> () | 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 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 match Ast_utils.get_decl_opt_with_decl_ref property_decl_opt with
| Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) -> | Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) ->
@ -94,13 +99,14 @@ struct
(match Ast_utils.get_decl_opt_with_decl_ref pointer with (match Ast_utils.get_decl_opt_with_decl_ref pointer with
| Some (ObjCMethodDecl (decl_info, _, _) as d) -> | Some (ObjCMethodDecl (decl_info, _, _) as d) ->
let source_range = decl_info.Clang_ast_t.di_source_range in 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 = let property_accessor =
if getter then if getter then
Some (ProcAttributes.Objc_getter field_name) Some (ProcAttributes.Objc_getter field_name)
else else
Some (ProcAttributes.Objc_setter field_name) in 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 let attrs = { (ProcAttributes.default procname Config.Clang) with
loc = loc; loc = loc;
objc_accessor = property_accessor; } in 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 let open Clang_ast_t in
match dec with match dec with
| CXXMethodDecl _ | CXXConstructorDecl _ | CXXConversionDecl _ | CXXDestructorDecl _ -> | 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 _ -> | 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) -> | 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 _ | EmptyDecl _
| ObjCIvarDecl _ | ObjCPropertyDecl _ -> () | 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); "\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 = let process_methods trans_unit_ctx tenv cg cfg curr_class decl_list =
IList.iter (process_one_method_decl 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 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 source_range = info.Clang_ast_t.di_source_range in
let translate_when_used = match dec with let translate_when_used = match dec with
| Clang_ast_t.FunctionDecl (_, name_info, _, _) | Clang_ast_t.FunctionDecl (_, name_info, _, _)
@ -144,7 +150,8 @@ struct
AttributesTable.is_whitelisted_cpp_method name AttributesTable.is_whitelisted_cpp_method name
| _ -> false in | _ -> false in
let translate_location = 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 let never_translate_decl = match dec with
| Clang_ast_t.FunctionDecl (_, name_info, _, _) | Clang_ast_t.FunctionDecl (_, name_info, _, _)
| Clang_ast_t.CXXMethodDecl (_, name_info, _, _, _) -> | Clang_ast_t.CXXMethodDecl (_, name_info, _, _, _) ->
@ -154,49 +161,49 @@ struct
(not never_translate_decl) && translate_location (not never_translate_decl) && translate_location
(* Translate one global declaration *) (* 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 let open Clang_ast_t in
(* each procedure has different scope: start names from id 0 *) (* each procedure has different scope: start names from id 0 *)
Ident.NameGenerator.reset (); 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 match dec with
| FunctionDecl(_, _, _, _) -> | 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) -> | ObjCInterfaceDecl(_, name_info, decl_list, _, oi_decl_info) ->
let name = Ast_utils.get_qualified_name name_info in let name = Ast_utils.get_qualified_name name_info in
let curr_class = ObjcInterface_decl.get_curr_class name oi_decl_info in let curr_class = ObjcInterface_decl.get_curr_class name oi_decl_info in
ignore ignore
(ObjcInterface_decl.interface_declaration CTypes_decl.type_ptr_to_sil_type tenv dec); (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, _, _) -> | ObjCProtocolDecl(_, name_info, decl_list, _, _) ->
let name = Ast_utils.get_qualified_name name_info in let name = Ast_utils.get_qualified_name name_info in
let curr_class = CContext.ContextProtocol name in let curr_class = CContext.ContextProtocol name in
ignore (ObjcProtocol_decl.protocol_decl CTypes_decl.type_ptr_to_sil_type tenv dec); 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) -> | ObjCCategoryDecl(_, name_info, decl_list, _, ocdi) ->
let name = Ast_utils.get_qualified_name name_info in let name = Ast_utils.get_qualified_name name_info in
let curr_class = ObjcCategory_decl.get_curr_class_from_category_decl name ocdi 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); 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) -> | ObjCCategoryImplDecl(_, name_info, decl_list, _, ocidi) ->
let name = Ast_utils.get_qualified_name name_info in let name = Ast_utils.get_qualified_name name_info in
let curr_class = ObjcCategory_decl.get_curr_class_from_category_impl name ocidi 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); 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) -> | ObjCImplementationDecl(decl_info, _, decl_list, _, idi) ->
let curr_class = ObjcInterface_decl.get_curr_class_impl idi in let curr_class = ObjcInterface_decl.get_curr_class_impl idi in
let class_name = CContext.get_curr_class_name curr_class 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 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); ignore (ObjcInterface_decl.interface_impl_declaration type_ptr_to_sil_type tenv dec);
CMethod_trans.add_default_method_for_class class_name decl_info; CMethod_trans.add_default_method_for_class trans_unit_ctx class_name decl_info;
process_methods tenv cg cfg curr_class decl_list; process_methods trans_unit_ctx tenv cg cfg curr_class decl_list;
| CXXMethodDecl (decl_info, _, _, _, _) | CXXMethodDecl (decl_info, _, _, _, _)
| CXXConstructorDecl (decl_info, _, _, _, _) | CXXConstructorDecl (decl_info, _, _, _, _)
@ -210,11 +217,12 @@ struct
| Some (ClassTemplateSpecializationDecl _) -> | Some (ClassTemplateSpecializationDecl _) ->
let curr_class = CContext.ContextClsDeclPtr parent_ptr in let curr_class = CContext.ContextClsDeclPtr parent_ptr in
if Config.cxx_experimental then 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 -> | Some dec ->
Logging.out "Methods of %s skipped\n" (Ast_utils.string_of_decl dec) Logging.out "Methods of %s skipped\n" (Ast_utils.string_of_decl dec)
| None -> ()) | None -> ())
| _ -> ()); | _ -> ());
let translate = translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context in
match dec with match dec with
(* Note that C and C++ records are treated the same way (* Note that C and C++ records are treated the same way
Skip translating implicit struct declarations, unless they have Skip translating implicit struct declarations, unless they have
@ -229,19 +237,19 @@ struct
true true
| _ -> false in | _ -> false in
let method_decls, no_method_decls = IList.partition is_method_decl decl_list 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); 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) | EnumDecl _ -> ignore (CEnum_decl.enum_decl dec)
| LinkageSpecDecl (_, decl_list, _) -> | LinkageSpecDecl (_, decl_list, _) ->
Logging.out_debug "ADDING: LinkageSpecDecl decl list\n"; Logging.out_debug "ADDING: LinkageSpecDecl decl list@\n";
IList.iter (translate_one_declaration tenv cg cfg decl_trans_context) decl_list IList.iter translate decl_list
| NamespaceDecl (_, _, 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) | ClassTemplateDecl (_, _, template_decl_info)
| FunctionTemplateDecl (_, _, template_decl_info) -> | FunctionTemplateDecl (_, _, template_decl_info) ->
let decl_list = template_decl_info.Clang_ast_t.tdi_specializations in 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 end

@ -81,17 +81,17 @@ let function_decl_checker_list = [ComponentKit.component_factory_function_advice
let checker_for_function_decl decl checker context = let checker_for_function_decl decl checker context =
checker context decl 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 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 | None -> Procname.Linters_dummy_method in
LintIssues.get_err_log procname LintIssues.get_err_log procname
(* Add a frontend warning with a description desc at location loc to the errlog of a proc desc *) (* 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 issue = issue_desc.CIssue.issue in
let loc = issue_desc.CIssue.loc 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 let err_desc = Errdesc.explain_frontend_warning issue_desc.CIssue.description
issue_desc.CIssue.suggestion loc in issue_desc.CIssue.suggestion loc in
let name = CIssue.to_string issue 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 -> IList.iter (fun checker ->
match f checker context with match f checker context with
| Some issue_desc -> | 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 | None -> ()) checkers
let run_frontend_checkers_on_stmt context instr = let run_frontend_checkers_on_stmt context instr =

@ -437,10 +437,15 @@ struct
| Clang_ast_t.ObjCImplementationDecl (_, _, _, _, idi) -> Some idi | Clang_ast_t.ObjCImplementationDecl (_, _, _, _, idi) -> Some idi
| _ -> None | _ -> 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 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 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 default_blacklist =
let open CFrontend_config in let open CFrontend_config in
@ -632,11 +637,13 @@ struct
| None -> file) | None -> file)
| None -> "" | None -> ""
let is_cpp_translation = let is_cpp_translation translation_unit_context =
Config.clang_lang = Config.CPP || Config.clang_lang = Config.OBJCPP let lang = translation_unit_context.CFrontend_config.lang in
lang = Config.CPP || lang = Config.OBJCPP
let is_objc_extension = let is_objc_extension translation_unit_context =
Config.clang_lang = Config.OBJC || Config.clang_lang = Config.OBJCPP 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 = 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 (* For virtual methods return mangled name of the method from most base class
@ -658,7 +665,7 @@ struct
get_mangled_method_name fdi mdi get_mangled_method_name fdi mdi
| _ -> assert false) | _ -> 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 = let file =
match function_decl_info_opt with match function_decl_info_opt with
| Some (decl_info, function_decl_info) -> | Some (decl_info, function_decl_info) ->
@ -673,7 +680,7 @@ struct
| _ -> None in | _ -> None in
let mangled_name = let mangled_name =
match mangled_opt with match mangled_opt with
| Some m when is_cpp_translation -> m | Some m when is_cpp_translation translation_unit_context -> m
| _ -> "" in | _ -> "" in
let mangled = (string_crc_hex32 file) ^ mangled_name in let mangled = (string_crc_hex32 file) ^ mangled_name in
if String.length file == 0 && String.length mangled_name == 0 then 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 let method_kind = Procname.objc_method_kind_of_bool is_instance in
mk_procname_from_objc_method class_name method_name method_kind 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 let open Clang_ast_t in
match meth_decl with match meth_decl with
| FunctionDecl (decl_info, name_info, _, fdi) -> | FunctionDecl (decl_info, name_info, _, fdi) ->
let name = Ast_utils.get_qualified_name name_info in let name = Ast_utils.get_qualified_name name_info in
let function_info = Some (decl_info, fdi) 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) | CXXMethodDecl (_, name_info, _, fdi, mdi)
| CXXConstructorDecl (_, name_info, _, fdi, mdi) | CXXConstructorDecl (_, name_info, _, fdi, mdi)
| CXXConversionDecl (_, 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 (** Returns true if the declaration or statement is inside the main source
file, as opposed to an imported header file. For statements, this refers file, as opposed to an imported header file. For statements, this refers
to the parent decl. *) 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. (** 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 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_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) val mk_procname_from_function : CFrontend_config.translation_unit_context -> string
option -> Procname.t -> (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 -> val get_mangled_method_name : Clang_ast_t.function_decl_info ->
Clang_ast_t.cxx_method_decl_info -> string option Clang_ast_t.cxx_method_decl_info -> string option
@ -233,7 +233,7 @@ sig
val mk_procname_from_cpp_method : val mk_procname_from_cpp_method :
string -> string -> ?meth_decl:Clang_ast_t.decl -> string option -> Procname.t 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 val mk_class_field_name : Clang_ast_t.named_decl_info -> Ident.fieldname
@ -244,9 +244,9 @@ sig
Pvar.t Pvar.t
(** true if Config.clang_lang is C++ or ObjC++ *) (** 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++ *) (** 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 end

@ -11,9 +11,8 @@ open! Utils
(** Module for function to retrieve the location (file, line, etc) of instructions *) (** 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 *) (** Inside the AST there may be code or type definitions from other files than the one passed as an
(* than the one passed as an argument. That current file in the translation is saved*) argument. That current file in the translation is saved in this variable. *)
(* in this variable. *)
let curr_file = ref DB.source_file_empty let curr_file = ref DB.source_file_empty
let source_file_from_path path = 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 | Some f when not (DB.source_file_equal (source_file_from_path f) !curr_file) -> sloc2
| _ -> sloc1 | _ -> 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 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 sloc2
| _ -> sloc1 | _ -> 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_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 match loc.Clang_ast_t.sl_file with
| Some f -> curr_file := source_file_from_path f | Some f -> curr_file := source_file_from_path f
| None -> () | 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 let line = match clang_loc.Clang_ast_t.sl_line with
| Some l -> l | Some l -> l
| None -> -1 in | None -> -1 in
@ -68,7 +68,7 @@ let clang_to_sil_location clang_loc procdesc_opt =
| Some f -> | Some f ->
let file_db = source_file_from_path f in let file_db = source_file_from_path f in
let nloc = 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 !Config.nLOC
else -1 in else -1 in
file_db, nloc file_db, nloc
@ -87,22 +87,20 @@ let file_in_project file =
file_in_project && not (file_should_be_skipped) file_in_project && not (file_should_be_skipped)
| None -> false | 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 match loc_start.Clang_ast_t.sl_file with
| Some file -> | Some file ->
let equal_current_source file = let equal_current_source file = DB.source_file_equal (source_file_from_path file)
DB.source_file_equal (source_file_from_path file) !CFrontend_config.current_source in trans_unit_ctx.CFrontend_config.source_file in
equal_current_source file || equal_current_source file ||
(file_in_project file && not Config.testing_mode) (file_in_project file && not Config.testing_mode)
| None -> false | None -> false
(* We translate by default the instructions in the current file.*) (** We translate by default the instructions in the current file. In C++ development, we also
(* In C++ development, we also translate the headers that are part *) translate the headers that are part of the project. However, in testing mode, we don't want to
(* of the project. However, in testing mode, we don't want to translate *) translate the headers because the dot files in the frontend tests should contain nothing else
(* the headers because the dot files in the frontend tests should contain nothing *) than the source file to avoid conflicts between different versions of the libraries. *)
(* else than the source file to avoid conflicts between different versions of the *) let should_translate trans_unit_ctx (loc_start, loc_end) decl_trans_context ~translate_when_used =
(* libraries in the CI *)
let should_translate (loc_start, loc_end) decl_trans_context ~translate_when_used =
let map_path_of pred loc = let map_path_of pred loc =
match loc.Clang_ast_t.sl_file with match loc.Clang_ast_t.sl_file with
| Some f -> pred f | 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 let path_pred path = pred (source_file_from_path path) in
map_path_of path_pred loc map_path_of path_pred loc
in in
let equal_current_source file = let equal_current_source = DB.source_file_equal trans_unit_ctx.CFrontend_config.source_file
DB.source_file_equal file !CFrontend_config.current_source
in in
let file_in_project = map_path_of file_in_project loc_end let file_in_project = map_path_of file_in_project loc_end
|| map_path_of file_in_project loc_start in || 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 || (Config.cxx_experimental && decl_trans_context = `Translation && translate_on_demand
&& not Config.testing_mode) && 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 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 is_file_blacklisted file =
let paths = Config.skip_clang_analysis_in_path in let paths = Config.skip_clang_analysis_in_path in
@ -139,15 +136,16 @@ let is_file_blacklisted file =
paths in paths in
is_file_blacklisted 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 sloc1, sloc2 = source_range in
let sloc = if not prefer_first then sloc2 else choose_sloc sloc1 sloc2 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 get_sil_location stmt_info context =
let sloc1, sloc2 = stmt_info.Clang_ast_t.si_source_range in let sloc1, sloc2 = stmt_info.Clang_ast_t.si_source_range in
let sloc = choose_sloc sloc1 sloc2 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 = let check_source_file source_file =
if is_file_blacklisted source_file then 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 *) (** 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 *) (** Inside the AST there may be code or type definitions from other files than the one passed as an
(* than the one passed as an argument. That current file in the translation is saved*) argument. That current file in the translation is saved in this variable. *)
(* in this variable. *)
val curr_file : DB.source_file ref 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 Location.t
val get_sil_location : Clang_ast_t.stmt_info -> CContext.t -> 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 -> val should_translate_lib : CFrontend_config.translation_unit_context -> Clang_ast_t.source_range ->
translate_when_used:bool -> bool 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 check_source_file : string -> unit
val source_file_from_path : string -> DB.source_file 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 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 abbrev_source_file = DB.source_file_encoding source_file in
let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in
DB.create_dir Config.results_dir ; create_dir Config.results_dir ;
DB.create_dir stats_dir ; create_dir stats_dir ;
PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file) PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file)
let init_global_state_for_capture_and_linters source_file = let init_global_state_for_capture_and_linters source_file =
register_perf_stats_report 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 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 init_time = Unix.gettimeofday () in
let print_elapsed () = let print_elapsed () =
let elapsed = Unix.gettimeofday () -. init_time in let elapsed = Unix.gettimeofday () -. init_time in
@ -58,8 +56,7 @@ let do_run source_path ast_path =
| Some path -> | Some path ->
path, validate_decl_from_file path path, validate_decl_from_file path
| None -> | 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 = let decl_index, stmt_index, type_index, ivar_to_property_index =
Clang_ast_main.index_node_pointers ast_decl in Clang_ast_main.index_node_pointers ast_decl in
CFrontend_config.pointer_decl_index := decl_index; 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.pointer_type_index := type_index;
CFrontend_config.ivar_to_property_index := ivar_to_property_index; CFrontend_config.ivar_to_property_index := ivar_to_property_index;
CFrontend_config.json := ast_filename; 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 "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 Logging.out "Start %s of AST from %s\n" Config.clang_frontend_action_string
!CFrontend_config.json; !CFrontend_config.json;
init_global_state_for_capture_and_linters source_file; 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 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 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; Logging.out "End translation AST file %s... OK!@\n" !CFrontend_config.json;
print_elapsed (); print_elapsed ();
with with
@ -86,9 +82,13 @@ let do_run source_path ast_path =
raise exc raise exc
let () = let () =
match Config.source_file with let source_file =
| Some path -> (match Config.source_file with
do_run path Config.ast_file | Some path ->
| None -> Logging.set_log_file_identifier (Some (Filename.basename path));
Logging.err_debug "Incorrect command line arguments\n"; CLocation.check_source_file path;
Config.print_usage_exit () 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 open! Utils
(** Main module of InferClang. Take as input AST files produced by clang during compilation *) (** Main module of InferClang. Take as input AST files produced by clang during compilation and
(** and their corresponding C/C++/ObjectiveC source files. *) 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. *)
Parse the arguments, parse and validate the input AST into a data structure and translates it
val do_run : string -> string option -> unit 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 | 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 | 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 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 | Cpp_Meth_decl_info _ -> Config.CPP
| ObjC_Meth_decl_info _ -> Config.OBJC | ObjC_Meth_decl_info _ -> Config.OBJC
| Block_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) 1. self/this parameter (optional, only for methods)
2. normal parameters 2. normal parameters
3. return parameter (optional) *) 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 = let par_to_ms_par par =
match par with match par with
| Clang_ast_t.ParmVarDecl (_, name_info, qt, var_decl_info) -> | 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 param_typ = CTypes_decl.type_ptr_to_sil_type tenv qt.Clang_ast_t.qt_type_ptr in
let qt_type_ptr = let qt_type_ptr =
match param_typ with 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 Ast_expressions.create_reference_type qt.Clang_ast_t.qt_type_ptr
| _ -> qt.Clang_ast_t.qt_type_ptr in | _ -> qt.Clang_ast_t.qt_type_ptr in
(mangled, {qt with qt_type_ptr}) (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)) Ast_expressions.create_void_type, Some (Typ.Tptr (return_typ, Typ.Pk_pointer))
else return_type_ptr, None 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 = parent_pointer pointer_to_property_opt =
let source_range = decl_info.Clang_ast_t.di_source_range in 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 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 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 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 let is_cpp_virtual = is_cpp_virtual function_method_decl_info in
CMethod_signature.make_ms CMethod_signature.make_ms
procname parameters tp attributes source_range is_instance_method ~is_cpp_virtual:is_cpp_virtual 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 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 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 let open Clang_ast_t in
match meth_decl, block_data_opt with match meth_decl, block_data_opt with
| FunctionDecl (decl_info, _, qt, fdi), _ -> | FunctionDecl (decl_info, _, qt, fdi), _ ->
let func_decl = Func_decl_info (fdi, qt.Clang_ast_t.qt_type_ptr) in 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 procname = General_utils.procname_of_decl trans_unit_ctx meth_decl 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 fdi.Clang_ast_t.fdi_parameters 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 ms, fdi.Clang_ast_t.fdi_body, extra_instrs
| CXXMethodDecl (decl_info, _, qt, fdi, mdi), _ | CXXMethodDecl (decl_info, _, qt, fdi, mdi), _
| CXXConstructorDecl (decl_info, _, qt, fdi, mdi), _ | CXXConstructorDecl (decl_info, _, qt, fdi, mdi), _
| CXXConversionDecl (decl_info, _, qt, fdi, mdi), _ | CXXConversionDecl (decl_info, _, qt, fdi, mdi), _
| CXXDestructorDecl (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 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 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 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 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 *) 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) ms, fdi.Clang_ast_t.fdi_body, (init_list_instrs @ non_null_instrs)
| ObjCMethodDecl (decl_info, _, mdi), _ -> | 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 parent_ptr = Option.get decl_info.di_parent_pointer in
let method_decl = ObjC_Meth_decl_info (mdi, parent_ptr) in let method_decl = ObjC_Meth_decl_info (mdi, parent_ptr) in
let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer 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 match mdi.Clang_ast_t.omdi_property_decl with
| Some decl_ref -> Some decl_ref.Clang_ast_t.dr_decl_pointer | Some decl_ref -> Some decl_ref.Clang_ast_t.dr_decl_pointer
| None -> None in | 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 parent_pointer pointer_to_property_opt in
let extra_instrs = get_assume_not_null_calls mdi.omdi_parameters in let extra_instrs = get_assume_not_null_calls mdi.omdi_parameters in
ms, mdi.omdi_body, extra_instrs ms, mdi.omdi_body, extra_instrs
| BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) -> | BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) ->
let func_decl = Block_decl_info (bdi, tp, outer_context) in 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 let extra_instrs = get_assume_not_null_calls bdi.bdi_parameters in
ms, bdi.bdi_body, extra_instrs ms, bdi.bdi_body, extra_instrs
| _ -> raise Invalid_declaration | _ -> raise Invalid_declaration
let method_signature_of_pointer tenv pointer = let method_signature_of_pointer trans_unit_ctx tenv pointer =
try try
match Ast_utils.get_decl pointer with match Ast_utils.get_decl pointer with
| Some meth_decl -> | 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 Some ms
| None -> None | None -> None
with Invalid_declaration -> None with Invalid_declaration -> None
@ -247,10 +248,10 @@ let get_superclass_curr_class_objc context =
| CContext.ContextProtocol _ -> assert false | CContext.ContextProtocol _ -> assert false
(* Gets the class name from a method signature found by clang, if search is successful *) (* 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 match obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer with
| Some pointer -> | Some pointer ->
(match method_signature_of_pointer tenv pointer with (match method_signature_of_pointer trans_unit_ctx tenv pointer with
| Some ms -> | Some ms ->
begin begin
match CMethod_signature.ms_get_name ms with match CMethod_signature.ms_get_name ms with
@ -377,7 +378,7 @@ let get_const_args_indices ~shift args =
aux [] args aux [] args
(** Creates a procedure description. *) (** 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 defined = not ((IList.length fbody) == 0) in
let proc_name = CMethod_signature.ms_get_name ms in let proc_name = CMethod_signature.ms_get_name ms in
let pname = Procname.to_string proc_name 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 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 "\nCreating a new procdesc for function: '%s'\n@." pname;
Logging.out_debug "\nms = %s\n@." (CMethod_signature.ms_to_string ms); 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_start = CLocation.get_sil_location_from_range trans_unit_ctx source_range true in
let loc_exit = CLocation.get_sil_location_from_range source_range false 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 let ret_type = get_return_type tenv ms in
if skip_property_accessor ms then () if skip_property_accessor ms then ()
else 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 create_procdesc_with_pointer context pointer class_name_opt name =
let open CContext in 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 -> | 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 CMethod_signature.ms_get_name callee_ms
| None -> | None ->
let callee_name = let callee_name =
@ -462,12 +464,13 @@ let create_procdesc_with_pointer context pointer class_name_opt name =
| Some class_name -> | Some class_name ->
General_utils.mk_procname_from_cpp_method class_name name None General_utils.mk_procname_from_cpp_method class_name name None
| 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; create_external_procdesc context.cfg callee_name false None;
callee_name callee_name
let add_default_method_for_class class_name decl_info = let add_default_method_for_class trans_unit_ctx class_name decl_info =
let loc = CLocation.get_sil_location_from_range decl_info.Clang_ast_t.di_source_range true in 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 proc_name = Procname.get_default_objc_class_method class_name in
let attrs = { (ProcAttributes.default proc_name Config.Clang) with loc = loc; } in let attrs = { (ProcAttributes.default proc_name Config.Clang) with loc = loc; } in
AttributesTable.store_attributes attrs 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 should_add_return_param : Typ.t -> is_objc_method:bool -> bool
val create_local_procdesc : Cfg.cfg -> Tenv.t -> CMethod_signature.method_signature -> val create_local_procdesc : CFrontend_config.translation_unit_context -> Cfg.cfg -> Tenv.t ->
Clang_ast_t.stmt list -> (Pvar.t * Typ.t) list -> bool -> bool 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 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 -> 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 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 -> val get_class_name_method_call_from_clang : CFrontend_config.translation_unit_context -> Tenv.t ->
string option 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 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 -> val method_signature_of_pointer : CFrontend_config.translation_unit_context -> Tenv.t ->
CMethod_signature.method_signature option Clang_ast_t.pointer -> CMethod_signature.method_signature option
val get_method_name_from_clang : Tenv.t -> CMethod_signature.method_signature option -> val get_method_name_from_clang : Tenv.t -> CMethod_signature.method_signature option ->
CMethod_signature.method_signature option CMethod_signature.method_signature option
val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string option -> val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string option -> string ->
string -> Procname.t 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 val get_procname_from_cpp_lambda : CContext.t -> Clang_ast_t.decl -> Procname.t

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

@ -100,7 +100,7 @@ let eval_Atomic pred_name params an lcxt =
match pred_name, params, an with match pred_name, params, an with
| "call_method", [p1], Stmt st -> Predicates.call_method p1 st | "call_method", [p1], Stmt st -> Predicates.call_method p1 st
| "property_name_contains_word", [p1] , Decl d -> Predicates.property_name_contains_word d p1 | "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_global_var", [], Decl d -> Predicates.is_syntactically_global_var d
| "is_const_var", [], Decl d -> Predicates.is_const_expr_var d | "is_const_var", [], Decl d -> Predicates.is_const_expr_var d
| "call_function_named", _, Stmt st -> Predicates.call_function_named st params | "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 method_kind = Procname.objc_method_kind_of_bool is_instance in
let ms_opt = let ms_opt =
match method_pointer_opt with 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 | None -> None in
let proc_name = let proc_name =
match CMethod_trans.get_method_name_from_clang context.tenv ms_opt with match CMethod_trans.get_method_name_from_clang context.tenv ms_opt with
@ -51,10 +53,12 @@ struct
None in None in
match predefined_ms_opt, ms_opt with match predefined_ms_opt, ms_opt with
| Some ms, _ -> | 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 CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual
| None, Some ms -> | 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 if CMethod_signature.ms_is_getter ms || CMethod_signature.ms_is_setter ms then
proc_name, CMethod_trans.MCNoVirtual proc_name, CMethod_trans.MCNoVirtual
else else
@ -235,7 +239,8 @@ struct
let open CContext in let open CContext in
(* translation will reset Ident counter, save it's state and restore it afterwards *) (* translation will reset Ident counter, save it's state and restore it afterwards *)
let ident_state = Ident.NameGenerator.get_current () in 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 Ident.NameGenerator.set_current ident_state
let mk_temp_sil_var procdesc var_name_suffix = 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 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 } { 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 get_deprecated_attr_arg decl =
let open Clang_ast_t in let open Clang_ast_t in
let decl_info = Clang_ast_proj.get_decl_tuple decl 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 -> | _ when CTrans_models.is_retain_builtin name type_ptr ->
Some ModelBuiltins.__objc_retain_cf Some ModelBuiltins.__objc_retain_cf
| _ when name = CFrontend_config.malloc && | _ when name = CFrontend_config.malloc &&
General_utils.is_objc_extension -> General_utils.is_objc_extension trans_unit_ctx ->
Some ModelBuiltins.malloc_no_fail Some ModelBuiltins.malloc_no_fail
| _ -> None | _ -> None
@ -457,7 +462,8 @@ struct
Option.may (call_translation context) decl_opt; Option.may (call_translation context) decl_opt;
let name = Ast_utils.get_qualified_name name_info in 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 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 | Some builtin_pname -> builtin_pname
| None -> CMethod_trans.create_procdesc_with_pointer context decl_ptr None name in | None -> CMethod_trans.create_procdesc_with_pointer context decl_ptr None name in
{ empty_res_trans with exps = [(Exp.Const (Const.Cfun pname), typ)] } { 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 let class_name = Ast_utils.get_class_name_from_member name_info in
Logging.out_debug "!!!!! Dealing with method '%s' @." method_name; 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 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 let is_instance_method = match ms_opt with
| Some ms -> CMethod_signature.ms_is_instance ms | Some ms -> CMethod_signature.ms_is_instance ms
| _ -> true (* might happen for methods that are not exported yet (some templates). *) in | _ -> 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 *) (* 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 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 | Some builtin_pname -> builtin_pname
| None -> | None ->
CMethod_trans.create_procdesc_with_pointer context decl_ptr (Some class_name) CMethod_trans.create_procdesc_with_pointer context decl_ptr (Some class_name)
@ -562,7 +571,8 @@ struct
cxx_record_info.xrdi_destructor cxx_record_info.xrdi_destructor
| _ -> None in | _ -> None in
match destruct_decl_ref_opt with 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 | None -> empty_res_trans
let this_expr_trans trans_state sil_loc class_type_ptr = let this_expr_trans trans_state sil_loc class_type_ptr =
@ -599,7 +609,7 @@ struct
let typ = let typ =
match ast_typ with match ast_typ with
| Tstruct _ when decl_ref.dr_kind = `ParmVar -> | 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) Typ.Tptr (ast_typ, Pk_reference)
else ast_typ else ast_typ
| _ -> ast_typ in | _ -> ast_typ in
@ -617,7 +627,8 @@ struct
match Ast_utils.get_decl decl_ref.dr_decl_pointer with match Ast_utils.get_decl decl_ref.dr_decl_pointer with
| Some VarDecl (_, _, qual_type, vdi) -> ( | Some VarDecl (_, _, qual_type, vdi) -> (
match ast_typ with 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 (* Do not convert a global struct to a local because SIL
values do not include structs, they must all be heap-allocated *) values do not include structs, they must all be heap-allocated *)
false, None false, None
@ -649,7 +660,8 @@ struct
match decl_kind with match decl_kind with
| `EnumConstant -> enum_constant_trans trans_state decl_ref | `EnumConstant -> enum_constant_trans trans_state decl_ref
| `Function -> function_deref_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 | `ObjCIvar ->
field_deref_trans trans_state stmt_info pre_trans_result decl_ref ~is_constructor_init field_deref_trans trans_state stmt_info pre_trans_result decl_ref ~is_constructor_init
| `CXXMethod | `CXXConversion | `CXXConstructor | `CXXDestructor -> | `CXXMethod | `CXXConversion | `CXXConstructor | `CXXDestructor ->
@ -790,7 +802,7 @@ struct
if (is_binary_assign_op binary_operator_info) if (is_binary_assign_op binary_operator_info)
(* assignment operator result is lvalue in CPP, rvalue in C, *) (* assignment operator result is lvalue in CPP, rvalue in C, *)
(* hence the difference *) (* 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 ( && ((not creating_node) || (is_return_temp trans_state.continuation)) then (
(* We are in this case when an assignment is inside *) (* We are in this case when an assignment is inside *)
(* another operator that creates a node. Eg. another *) (* another operator that creates a node. Eg. another *)
@ -1005,7 +1017,7 @@ struct
| `Class type_ptr -> | `Class type_ptr ->
let class_opt = let class_opt =
CMethod_trans.get_class_name_method_call_from_clang 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) Some (new_or_alloc_trans trans_state_pri sil_loc si type_ptr class_opt selector)
| _ -> None | _ -> None
(* assertions *) (* assertions *)
@ -1850,7 +1862,8 @@ struct
CTypes_decl.type_ptr_to_sil_type CTypes_decl.type_ptr_to_sil_type
context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let exp_op, instr_op = 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 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 all_res_trans = [ res_trans_stmt; unary_op_res_trans ] in
let nname = "UnaryOperator" in let nname = "UnaryOperator" in
@ -2004,7 +2017,8 @@ struct
let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc in let procname = Cfg.Procdesc.get_proc_name context.CContext.procdesc in
let loc = let loc =
(match stmt_info.Clang_ast_t.si_source_range with (l1, _) -> (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 *) (* Given a captured var, return the instruction to assign it to a temp *)
let assign_captured_var (cvar, typ) = let assign_captured_var (cvar, typ) =
let id = Ident.create_fresh Ident.knormal in 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.map assign_captured_var captureds in
let ids, instrs = IList.split ids_instrs in let ids, instrs = IList.split ids_instrs in
let block_data = (context, type_ptr, block_pname, captureds) 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 = let captured_vars =
IList.map2 (fun id (pvar, typ) -> (Exp.Var id, pvar, typ)) ids captureds in IList.map2 (fun id (pvar, typ) -> (Exp.Var id, pvar, typ)) ids captureds in
let closure = Exp.Closure { name=block_pname; captured_vars } in let closure = Exp.Closure { name=block_pname; captured_vars } in
@ -2622,13 +2637,14 @@ struct
(Ast_utils.string_of_stmt s); (Ast_utils.string_of_stmt s);
assert false) assert false)
(* Function similar to instruction function, but it takes C++ constructor initializer as *) (* Function similar to instruction function, but it takes C++ constructor initializer as
(* an input parameter. *) an input parameter. *)
and cxx_constructor_init_trans ctor_init trans_state = and cxx_constructor_init_trans ctor_init trans_state =
(*let tenv = trans_state.context.CContext.tenv in*) let context = trans_state.context in
let class_ptr = CContext.get_curr_class_decl_ptr trans_state.context.CContext.curr_class 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 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 *) (* its pointer will be used in PriorityNode *)
let this_stmt_info = Ast_expressions.dummy_stmt_info () in let this_stmt_info = Ast_expressions.dummy_stmt_info () in
(* this will be used to avoid creating node in init_expr_trans *) (* 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) with Not_found -> false)
| _ -> 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 = let is_syntactically_global_var decl =
Ast_utils.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 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 val is_syntactically_global_var : Clang_ast_t.decl -> bool

@ -192,5 +192,5 @@ let get_compilation_database changed_files =
let () = let () =
let changed_files = read_files_to_compile () in let changed_files = read_files_to_compile () in
let compilation_database = get_compilation_database changed_files 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 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 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 abbrev_source_file = DB.source_file_encoding source_file in
let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in
DB.create_dir Config.results_dir ; create_dir Config.results_dir ;
DB.create_dir stats_dir ; create_dir stats_dir ;
PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file) 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 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 abbrev_source_file = DB.source_file_encoding source_file in
let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in let stats_file = Config.perf_stats_prefix ^ "_" ^ abbrev_source_file ^ ".json" in
DB.create_dir Config.results_dir ; create_dir Config.results_dir ;
DB.create_dir stats_dir ; create_dir stats_dir ;
PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file) PerfStats.register_report_at_exit (Filename.concat stats_dir stats_file)
let init_global_state source_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_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_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; let aggregated_reporting_stats_dir = Filename.concat infer_out Config.reporting_stats_dir_name;
DB.create_dir aggregated_frontend_stats_dir; create_dir aggregated_frontend_stats_dir;
DB.create_dir aggregated_backend_stats_dir; create_dir aggregated_backend_stats_dir;
DB.create_dir aggregated_reporting_stats_dir; create_dir aggregated_reporting_stats_dir;
let write_to_json_file_opt destfile json => let write_to_json_file_opt destfile json =>
switch json { switch json {
| Some j => Utils.write_json_to_file destfile j | Some j => Utils.write_json_to_file destfile j

Loading…
Cancel
Save